uifw/AknGlobalUI/AknNfySrv/src/AknNfySrv.cpp
changeset 0 2f259fa3e83a
child 38 c52421ed5f07
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AknGlobalUI/AknNfySrv/src/AknNfySrv.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,402 @@
+/*
+* Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  AknNfySrv server and session implementation.
+*
+*/
+
+#include <AknNotifierWrapperDefs.h>
+#include <AknNotifierControllerPlugin.h>
+#include "AknNfySrv.h"
+
+const TUid KDllUid = {0x10000079};
+
+    
+class CAknNotifierEntry: public CBase
+    {
+public:   
+    CAknNotifierEntry():iNotifier(0),iLibraryName(0){}
+    ~CAknNotifierEntry(){if (iNotifier) iNotifier->Release();}
+    MEikSrvNotifierBase2* iNotifier;
+    HBufC* iLibraryName; // Not owned
+    };
+    
+class CAknNotifLibraryEntry: public CBase
+    {
+public:   
+    CAknNotifLibraryEntry(HBufC* aName):iReferenceCount(1), iLibraryName(aName){}
+    ~CAknNotifLibraryEntry()
+        {
+        delete iLibraryName;
+        iLibrary.Close();
+        }
+    TInt Load()
+        {
+        return iLibrary.Load( 
+            *iLibraryName,
+            _L("z:\\sys\\bin\\"),
+            TUidType(KDllUid, KUidNotifierPlugInV2, KNullUid));
+        }
+    TInt iReferenceCount;
+    HBufC* iLibraryName;
+    RLibrary iLibrary;
+    TInt iNestingLevel;
+    };   
+    
+// local functions
+TBool CheckUnusedLibraries(TAny* aThis)
+    {
+    CAknNfySrv* me = (CAknNfySrv*)aThis;
+    TBool foundPending(EFalse); 
+    for (TInt ii = me->iLibraryArray.Count()-1; ii >= 0; ii-- )
+        {
+        if (me->iLibraryArray[ii]->iReferenceCount == 0)
+            {
+            if (me->iLibraryArray[ii]->iNestingLevel >= CActiveScheduler::Current()->StackDepth())
+                {
+                me->DoUnload(me->iLibraryArray[ii]->iLibraryName->Des());
+                }
+            else
+                {
+                foundPending = ETrue;
+                }   
+            }
+        }
+    return foundPending; 
+    }
+
+void  CAknNfySrvSession::HandleMessageL(const RMessage2& aMessage)
+    {
+    TInt command = aMessage.Function();
+    
+    if ( command == EStartNotifier || command == EStartNotifierAndGetResponse 
+        || command == EAknNfySrvLoadLibrary)
+        {
+        TInt libNameLength = aMessage.GetDesLength(3);
+        if (libNameLength > 0)
+            {
+            HBufC* libName = HBufC::NewLC(libNameLength);
+            TPtr ptr = libName->Des();
+            aMessage.ReadL(3, ptr); 
+            CleanupStack::Pop(); // ownership to server
+            iServer->LoadLibraryL(libName);
+            }
+        }
+        
+    // Check pending removals before passing execution to plugin (as it may create new nesting 
+    // levels).
+    iServer->CheckPendingRemovalsL();
+    
+    if (command == EAknNfySrvLoadLibrary)
+        {
+        aMessage.Complete(KErrNone);
+        }
+    else
+        {
+        CAknNotifierServerAppService::HandleMessageL(aMessage);    
+        }
+    }
+
+void CAknNfySrv::CheckPendingRemovalsL()
+    {
+    if (!iLibraryRemover)
+        {
+        iLibraryRemover = CIdle::NewL(CActive::EPriorityIdle); // there is no hurry
+        }
+    else if (iLibraryRemover->IsActive())
+        {
+        if (CheckUnusedLibraries((TAny*) this))
+            {
+            iLibraryRemover->Cancel();
+            }
+        }
+    }
+
+void CAknNfySrv::CancelNotifier(TUid aNotifierUid)
+    {
+    MEikSrvNotifierBase2* impl = FindImplementation(aNotifierUid);  
+    if (impl)
+        {
+        // Just in case notifier likes to null the information on cancel.
+        TUid uid = impl->Info().iUid; 
+        
+        impl->Cancel();    
+        UnloadLibrary(uid);
+        }
+    }
+    
+void CAknNfySrv::StartNotifierAndGetResponseL(TUid aNotifierUid, TDesC8& aBuffer, 
+    const RMessagePtr2& aMsg, TInt aReplySlot)
+    {
+    MEikSrvNotifierBase2* impl = FindImplementation(aNotifierUid);  
+    if (!impl)
+        {
+        UnloadLibrary(aNotifierUid);
+        }
+    User::LeaveIfNull(impl);    
+    impl->StartL(aBuffer, aReplySlot, aMsg);
+    }
+    
+void CAknNfySrv::StartNotifierL(TUid aNotifierUid, const TDesC8& aBuffer, TDes8& aResponse)
+    {
+    MEikSrvNotifierBase2* impl = FindImplementation(aNotifierUid);  
+    if (!impl)
+        {
+        UnloadLibrary(aNotifierUid);
+        }
+        
+    User::LeaveIfNull(impl);    
+    aResponse.Copy(impl->StartL(aBuffer));
+    }
+        
+CApaAppServiceBase* CAknNfySrv::CreateServiceL(TUid aServiceType) const
+    {
+    if ( aServiceType == KAknNotifierServiceUid )
+        {
+        return new (ELeave) CAknNfySrvSession(this);
+        }
+    else 
+        {
+        return CAknNotifierAppServer::CreateServiceL(aServiceType); 
+        }   
+    }
+
+void CAknNfySrv::LoadLibraryL(HBufC* aLibName) 
+    {
+    CleanupStack::PushL(aLibName);
+    if (!CheckReferenceCount(aLibName->Des(), ETrue))
+        {
+        CAknNotifLibraryEntry* newLib = new (ELeave) CAknNotifLibraryEntry(aLibName);
+        newLib->iNestingLevel = CActiveScheduler::Current()->StackDepth();
+        CleanupStack::Pop(); // aLibName
+        CleanupStack::PushL(newLib);
+        User::LeaveIfError(newLib->Load());
+        AddNotifiersFromLibL(newLib);
+        iLibraryArray.AppendL(newLib);
+        CleanupStack::Pop(); // newLib
+        }
+    else
+        {
+        CleanupStack::PopAndDestroy(); // aLibName
+        }
+    }
+
+LOCAL_C void DeleteTempMArray(TAny* aPtr)
+    {
+    CArrayPtr<MEikSrvNotifierBase2>* const array = 
+        reinterpret_cast<CArrayPtr<MEikSrvNotifierBase2>*>(aPtr);
+        
+    for (TInt i = array->Count()-1; i >= 0; i--)
+        {
+        array->At(i)->Release(); // effectively delete 
+        }
+
+    delete array;
+    }   
+    
+// To make polymorphic binding bit more readable.
+typedef CArrayPtr<MEikSrvNotifierBase2>* (*CreateEikSrvNotifierBase)();     
+
+void CAknNfySrv::AddNotifiersFromLibL(CAknNotifLibraryEntry* aNewLib)
+    {
+    CreateEikSrvNotifierBase libEntry =
+        (CreateEikSrvNotifierBase)(aNewLib->iLibrary.Lookup(1)); // fetch fptr   
+        
+    CArrayPtr<MEikSrvNotifierBase2>* array = 
+        reinterpret_cast<CArrayPtr<MEikSrvNotifierBase2>*>((libEntry)()); // and execute it
+        
+    User::LeaveIfNull(array);       
+    CleanupStack::PushL(TCleanupItem(DeleteTempMArray,array));
+    const TInt count = array->Count();
+    for (TInt j = count-1; j >= 0 ; j--)
+        {
+        CAknNotifierEntry* newEntry = new (ELeave) CAknNotifierEntry();
+        newEntry->iNotifier = array->At(j);
+        newEntry->iLibraryName = aNewLib->iLibraryName;
+        CleanupStack::PushL(newEntry);
+        newEntry->iNotifier->RegisterL();
+        
+        User::LeaveIfError(iNotifierArray.Append(newEntry));
+        
+        CleanupStack::Pop(newEntry);
+        
+        array->At(j)=0;
+        array->Delete(j);
+        }
+            
+    CleanupStack::PopAndDestroy(array);     
+    }
+
+CAknNotifierEntry* CAknNfySrv::FindEntry(TUid aUid) const
+    {
+    for (TInt i = 0; i < iNotifierArray.Count(); i++)
+        {
+        if (iNotifierArray[i]->iNotifier->Info().iUid == aUid)
+            {
+            return iNotifierArray[i];   
+            }
+        }
+    return 0;
+    }
+
+MEikSrvNotifierBase2* CAknNfySrv::FindImplementation(TUid aUid) const
+    {
+    CAknNotifierEntry* entry = FindEntry(aUid);
+    if (entry)
+        {
+        return entry->iNotifier;
+        }
+        
+    return 0;
+    }
+
+TBool CAknNfySrv::CheckReferenceCount(const TDesC& aLibName, TBool aIncrease)
+    {
+    TBool ret = EFalse;
+    for (TInt i = iLibraryArray.Count()-1; i >= 0; i--)
+        {
+        if (iLibraryArray[i]->iLibraryName->CompareF(aLibName) == 0)
+            {
+            if (aIncrease)
+                {
+                iLibraryArray[i]->iReferenceCount++;
+                // modify nesting level only if it decreases
+                if (iLibraryArray[i]->iNestingLevel > CActiveScheduler::Current()->StackDepth())
+                    {
+                    iLibraryArray[i]->iNestingLevel = CActiveScheduler::Current()->StackDepth();
+                    }
+                ret = ETrue; 
+                }
+            else
+                {
+                if (--iLibraryArray[i]->iReferenceCount == 0)
+                    {
+                    if (iLibraryArray[i]->iNestingLevel == CActiveScheduler::Current()->StackDepth())
+                        {
+                        // Return true if this was last reference and nesting level is same as 
+                        // when created.
+                        ret = ETrue; 
+                        }
+                    else
+                        {                            
+                        if (!iLibraryRemover->IsActive())
+                            {
+                            iLibraryRemover->Start(TCallBack(CheckUnusedLibraries, this));
+                            }
+                        }
+                    }
+                }    
+            break;               
+            }
+        }
+#ifdef _DEBUG
+    RDebug::Print(_L("CAknNfySrv::CheckReferenceCount(%S, %d), ret %d"), &aLibName, aIncrease, ret);    
+#endif
+    return ret;
+    }
+
+void CAknNfySrv::UnloadLibrary(TUid aNotifierUid)
+    {
+    __ASSERT_ALWAYS(iLibraryArray.Count(), User::Invariant());
+    
+    // default to last added name
+    TPtrC libName = iLibraryArray[iLibraryArray.Count()-1]->iLibraryName->Des(); 
+
+    CAknNotifierEntry* entry = FindEntry(aNotifierUid);
+    if (entry)
+        {
+        libName.Set(entry->iLibraryName->Des());
+        }
+    
+    // RPointerArray could probably provide something better than linear search,
+    // anyway the amount of notifiers should be considerably small so applying KISS paradigm here.
+    if (CheckReferenceCount(libName, EFalse))
+        {
+        DoUnload(libName);
+        } 
+    }
+
+void CAknNfySrv::DoUnload(const TDesC& aLibName)
+    {
+    for (TInt i = iNotifierArray.Count()-1; i >= 0; i--)
+        {
+        // Release notifiers from lib (reverse order to handle possible dependencies).
+        if (iNotifierArray[i]->iLibraryName->CompareF(aLibName) == 0)
+            {
+            delete iNotifierArray[i];
+            iNotifierArray.Remove(i);
+#ifdef _DEBUG
+            RDebug::Print(_L("Deleted notifier from library %S"), &aLibName);    
+#endif
+            }
+        }
+            
+    for (TInt i = iLibraryArray.Count()-1; i >= 0; i--)
+        {
+        if (iLibraryArray[i]->iLibraryName->CompareF(aLibName) == 0)
+            {
+            delete iLibraryArray[i];
+            iLibraryArray.Remove(i);
+#ifdef _DEBUG
+            RDebug::Print(_L("Deleted library"));    
+#endif
+            break;
+            }
+        }        
+        
+    User::Heap().Compress();
+#ifdef _DEBUG
+    RDebug::Print(_L("Heap compressed"));    
+#endif
+    }
+
+
+CAknNfySrv::~CAknNfySrv()
+    {
+    delete iLibraryRemover;
+    for (TInt i = iNotifierArray.Count()-1; i >= 0; i--)
+        {
+        delete iNotifierArray[i];
+        }
+    iNotifierArray.Close();             
+    for (TInt i = iLibraryArray.Count()-1; i >= 0; i--)
+        {
+        delete iLibraryArray[i];
+        }
+    iLibraryArray.Close();
+    }
+
+void CAknNfySrv::HandleClientExit(CAknNfySrvSession* /*aSession*/)
+    {
+    }
+
+void CAknNfySrv::UnbalanceReferenceCount(TUid aUid, TBool aAddCount)
+    {
+    CAknNotifierEntry* entry = CAknNfySrv::FindEntry(aUid);
+    if (entry)
+        {
+        CheckReferenceCount(*entry->iLibraryName, aAddCount);
+        if (!aAddCount)
+            {
+            // In order to free memory, we may need to allocate memory.
+            TRAP_IGNORE(CheckPendingRemovalsL()); 
+            }
+        }
+    }
+    
+// future proofing    
+void CAknNfySrv::NotifierExtension(TUid /*aExtensionUid*/, TAny*& /*aGenParam*/)
+    {    
+    }
+    
+// End of file