--- /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