diff -r 000000000000 -r 2f259fa3e83a uifw/AknGlobalUI/AknNfySrv/src/AknNfySrv.cpp --- /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 +#include +#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* const array = + reinterpret_cast*>(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* (*CreateEikSrvNotifierBase)(); + +void CAknNfySrv::AddNotifiersFromLibL(CAknNotifLibraryEntry* aNewLib) + { + CreateEikSrvNotifierBase libEntry = + (CreateEikSrvNotifierBase)(aNewLib->iLibrary.Lookup(1)); // fetch fptr + + CArrayPtr* array = + reinterpret_cast*>((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