uifw/AknGlobalUI/AknNfySrv/src/AknNfySrv.cpp
changeset 0 2f259fa3e83a
child 15 c52421ed5f07
equal deleted inserted replaced
-1:000000000000 0:2f259fa3e83a
       
     1 /*
       
     2 * Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  AknNfySrv server and session implementation.
       
    15 *
       
    16 */
       
    17 
       
    18 #include <AknNotifierWrapperDefs.h>
       
    19 #include <AknNotifierControllerPlugin.h>
       
    20 #include "AknNfySrv.h"
       
    21 
       
    22 const TUid KDllUid = {0x10000079};
       
    23 
       
    24     
       
    25 class CAknNotifierEntry: public CBase
       
    26     {
       
    27 public:   
       
    28     CAknNotifierEntry():iNotifier(0),iLibraryName(0){}
       
    29     ~CAknNotifierEntry(){if (iNotifier) iNotifier->Release();}
       
    30     MEikSrvNotifierBase2* iNotifier;
       
    31     HBufC* iLibraryName; // Not owned
       
    32     };
       
    33     
       
    34 class CAknNotifLibraryEntry: public CBase
       
    35     {
       
    36 public:   
       
    37     CAknNotifLibraryEntry(HBufC* aName):iReferenceCount(1), iLibraryName(aName){}
       
    38     ~CAknNotifLibraryEntry()
       
    39         {
       
    40         delete iLibraryName;
       
    41         iLibrary.Close();
       
    42         }
       
    43     TInt Load()
       
    44         {
       
    45         return iLibrary.Load( 
       
    46             *iLibraryName,
       
    47             _L("z:\\sys\\bin\\"),
       
    48             TUidType(KDllUid, KUidNotifierPlugInV2, KNullUid));
       
    49         }
       
    50     TInt iReferenceCount;
       
    51     HBufC* iLibraryName;
       
    52     RLibrary iLibrary;
       
    53     TInt iNestingLevel;
       
    54     };   
       
    55     
       
    56 // local functions
       
    57 TBool CheckUnusedLibraries(TAny* aThis)
       
    58     {
       
    59     CAknNfySrv* me = (CAknNfySrv*)aThis;
       
    60     TBool foundPending(EFalse); 
       
    61     for (TInt ii = me->iLibraryArray.Count()-1; ii >= 0; ii-- )
       
    62         {
       
    63         if (me->iLibraryArray[ii]->iReferenceCount == 0)
       
    64             {
       
    65             if (me->iLibraryArray[ii]->iNestingLevel >= CActiveScheduler::Current()->StackDepth())
       
    66                 {
       
    67                 me->DoUnload(me->iLibraryArray[ii]->iLibraryName->Des());
       
    68                 }
       
    69             else
       
    70                 {
       
    71                 foundPending = ETrue;
       
    72                 }   
       
    73             }
       
    74         }
       
    75     return foundPending; 
       
    76     }
       
    77 
       
    78 void  CAknNfySrvSession::HandleMessageL(const RMessage2& aMessage)
       
    79     {
       
    80     TInt command = aMessage.Function();
       
    81     
       
    82     if ( command == EStartNotifier || command == EStartNotifierAndGetResponse 
       
    83         || command == EAknNfySrvLoadLibrary)
       
    84         {
       
    85         TInt libNameLength = aMessage.GetDesLength(3);
       
    86         if (libNameLength > 0)
       
    87             {
       
    88             HBufC* libName = HBufC::NewLC(libNameLength);
       
    89             TPtr ptr = libName->Des();
       
    90             aMessage.ReadL(3, ptr); 
       
    91             CleanupStack::Pop(); // ownership to server
       
    92             iServer->LoadLibraryL(libName);
       
    93             }
       
    94         }
       
    95         
       
    96     // Check pending removals before passing execution to plugin (as it may create new nesting 
       
    97     // levels).
       
    98     iServer->CheckPendingRemovalsL();
       
    99     
       
   100     if (command == EAknNfySrvLoadLibrary)
       
   101         {
       
   102         aMessage.Complete(KErrNone);
       
   103         }
       
   104     else
       
   105         {
       
   106         CAknNotifierServerAppService::HandleMessageL(aMessage);    
       
   107         }
       
   108     }
       
   109 
       
   110 void CAknNfySrv::CheckPendingRemovalsL()
       
   111     {
       
   112     if (!iLibraryRemover)
       
   113         {
       
   114         iLibraryRemover = CIdle::NewL(CActive::EPriorityIdle); // there is no hurry
       
   115         }
       
   116     else if (iLibraryRemover->IsActive())
       
   117         {
       
   118         if (CheckUnusedLibraries((TAny*) this))
       
   119             {
       
   120             iLibraryRemover->Cancel();
       
   121             }
       
   122         }
       
   123     }
       
   124 
       
   125 void CAknNfySrv::CancelNotifier(TUid aNotifierUid)
       
   126     {
       
   127     MEikSrvNotifierBase2* impl = FindImplementation(aNotifierUid);  
       
   128     if (impl)
       
   129         {
       
   130         // Just in case notifier likes to null the information on cancel.
       
   131         TUid uid = impl->Info().iUid; 
       
   132         
       
   133         impl->Cancel();    
       
   134         UnloadLibrary(uid);
       
   135         }
       
   136     }
       
   137     
       
   138 void CAknNfySrv::StartNotifierAndGetResponseL(TUid aNotifierUid, TDesC8& aBuffer, 
       
   139     const RMessagePtr2& aMsg, TInt aReplySlot)
       
   140     {
       
   141     MEikSrvNotifierBase2* impl = FindImplementation(aNotifierUid);  
       
   142     if (!impl)
       
   143         {
       
   144         UnloadLibrary(aNotifierUid);
       
   145         }
       
   146     User::LeaveIfNull(impl);    
       
   147     impl->StartL(aBuffer, aReplySlot, aMsg);
       
   148     }
       
   149     
       
   150 void CAknNfySrv::StartNotifierL(TUid aNotifierUid, const TDesC8& aBuffer, TDes8& aResponse)
       
   151     {
       
   152     MEikSrvNotifierBase2* impl = FindImplementation(aNotifierUid);  
       
   153     if (!impl)
       
   154         {
       
   155         UnloadLibrary(aNotifierUid);
       
   156         }
       
   157         
       
   158     User::LeaveIfNull(impl);    
       
   159     aResponse.Copy(impl->StartL(aBuffer));
       
   160     }
       
   161         
       
   162 CApaAppServiceBase* CAknNfySrv::CreateServiceL(TUid aServiceType) const
       
   163     {
       
   164     if ( aServiceType == KAknNotifierServiceUid )
       
   165         {
       
   166         return new (ELeave) CAknNfySrvSession(this);
       
   167         }
       
   168     else 
       
   169         {
       
   170         return CAknNotifierAppServer::CreateServiceL(aServiceType); 
       
   171         }   
       
   172     }
       
   173 
       
   174 void CAknNfySrv::LoadLibraryL(HBufC* aLibName) 
       
   175     {
       
   176     CleanupStack::PushL(aLibName);
       
   177     if (!CheckReferenceCount(aLibName->Des(), ETrue))
       
   178         {
       
   179         CAknNotifLibraryEntry* newLib = new (ELeave) CAknNotifLibraryEntry(aLibName);
       
   180         newLib->iNestingLevel = CActiveScheduler::Current()->StackDepth();
       
   181         CleanupStack::Pop(); // aLibName
       
   182         CleanupStack::PushL(newLib);
       
   183         User::LeaveIfError(newLib->Load());
       
   184         AddNotifiersFromLibL(newLib);
       
   185         iLibraryArray.AppendL(newLib);
       
   186         CleanupStack::Pop(); // newLib
       
   187         }
       
   188     else
       
   189         {
       
   190         CleanupStack::PopAndDestroy(); // aLibName
       
   191         }
       
   192     }
       
   193 
       
   194 LOCAL_C void DeleteTempMArray(TAny* aPtr)
       
   195     {
       
   196     CArrayPtr<MEikSrvNotifierBase2>* const array = 
       
   197         reinterpret_cast<CArrayPtr<MEikSrvNotifierBase2>*>(aPtr);
       
   198         
       
   199     for (TInt i = array->Count()-1; i >= 0; i--)
       
   200         {
       
   201         array->At(i)->Release(); // effectively delete 
       
   202         }
       
   203 
       
   204     delete array;
       
   205     }   
       
   206     
       
   207 // To make polymorphic binding bit more readable.
       
   208 typedef CArrayPtr<MEikSrvNotifierBase2>* (*CreateEikSrvNotifierBase)();     
       
   209 
       
   210 void CAknNfySrv::AddNotifiersFromLibL(CAknNotifLibraryEntry* aNewLib)
       
   211     {
       
   212     CreateEikSrvNotifierBase libEntry =
       
   213         (CreateEikSrvNotifierBase)(aNewLib->iLibrary.Lookup(1)); // fetch fptr   
       
   214         
       
   215     CArrayPtr<MEikSrvNotifierBase2>* array = 
       
   216         reinterpret_cast<CArrayPtr<MEikSrvNotifierBase2>*>((libEntry)()); // and execute it
       
   217         
       
   218     User::LeaveIfNull(array);       
       
   219     CleanupStack::PushL(TCleanupItem(DeleteTempMArray,array));
       
   220     const TInt count = array->Count();
       
   221     for (TInt j = count-1; j >= 0 ; j--)
       
   222         {
       
   223         CAknNotifierEntry* newEntry = new (ELeave) CAknNotifierEntry();
       
   224         newEntry->iNotifier = array->At(j);
       
   225         newEntry->iLibraryName = aNewLib->iLibraryName;
       
   226         CleanupStack::PushL(newEntry);
       
   227         newEntry->iNotifier->RegisterL();
       
   228         
       
   229         User::LeaveIfError(iNotifierArray.Append(newEntry));
       
   230         
       
   231         CleanupStack::Pop(newEntry);
       
   232         
       
   233         array->At(j)=0;
       
   234         array->Delete(j);
       
   235         }
       
   236             
       
   237     CleanupStack::PopAndDestroy(array);     
       
   238     }
       
   239 
       
   240 CAknNotifierEntry* CAknNfySrv::FindEntry(TUid aUid) const
       
   241     {
       
   242     for (TInt i = 0; i < iNotifierArray.Count(); i++)
       
   243         {
       
   244         if (iNotifierArray[i]->iNotifier->Info().iUid == aUid)
       
   245             {
       
   246             return iNotifierArray[i];   
       
   247             }
       
   248         }
       
   249     return 0;
       
   250     }
       
   251 
       
   252 MEikSrvNotifierBase2* CAknNfySrv::FindImplementation(TUid aUid) const
       
   253     {
       
   254     CAknNotifierEntry* entry = FindEntry(aUid);
       
   255     if (entry)
       
   256         {
       
   257         return entry->iNotifier;
       
   258         }
       
   259         
       
   260     return 0;
       
   261     }
       
   262 
       
   263 TBool CAknNfySrv::CheckReferenceCount(const TDesC& aLibName, TBool aIncrease)
       
   264     {
       
   265     TBool ret = EFalse;
       
   266     for (TInt i = iLibraryArray.Count()-1; i >= 0; i--)
       
   267         {
       
   268         if (iLibraryArray[i]->iLibraryName->CompareF(aLibName) == 0)
       
   269             {
       
   270             if (aIncrease)
       
   271                 {
       
   272                 iLibraryArray[i]->iReferenceCount++;
       
   273                 // modify nesting level only if it decreases
       
   274                 if (iLibraryArray[i]->iNestingLevel > CActiveScheduler::Current()->StackDepth())
       
   275                     {
       
   276                     iLibraryArray[i]->iNestingLevel = CActiveScheduler::Current()->StackDepth();
       
   277                     }
       
   278                 ret = ETrue; 
       
   279                 }
       
   280             else
       
   281                 {
       
   282                 if (--iLibraryArray[i]->iReferenceCount == 0)
       
   283                     {
       
   284                     if (iLibraryArray[i]->iNestingLevel == CActiveScheduler::Current()->StackDepth())
       
   285                         {
       
   286                         // Return true if this was last reference and nesting level is same as 
       
   287                         // when created.
       
   288                         ret = ETrue; 
       
   289                         }
       
   290                     else
       
   291                         {                            
       
   292                         if (!iLibraryRemover->IsActive())
       
   293                             {
       
   294                             iLibraryRemover->Start(TCallBack(CheckUnusedLibraries, this));
       
   295                             }
       
   296                         }
       
   297                     }
       
   298                 }    
       
   299             break;               
       
   300             }
       
   301         }
       
   302 #ifdef _DEBUG
       
   303     RDebug::Print(_L("CAknNfySrv::CheckReferenceCount(%S, %d), ret %d"), &aLibName, aIncrease, ret);    
       
   304 #endif
       
   305     return ret;
       
   306     }
       
   307 
       
   308 void CAknNfySrv::UnloadLibrary(TUid aNotifierUid)
       
   309     {
       
   310     __ASSERT_ALWAYS(iLibraryArray.Count(), User::Invariant());
       
   311     
       
   312     // default to last added name
       
   313     TPtrC libName = iLibraryArray[iLibraryArray.Count()-1]->iLibraryName->Des(); 
       
   314 
       
   315     CAknNotifierEntry* entry = FindEntry(aNotifierUid);
       
   316     if (entry)
       
   317         {
       
   318         libName.Set(entry->iLibraryName->Des());
       
   319         }
       
   320     
       
   321     // RPointerArray could probably provide something better than linear search,
       
   322     // anyway the amount of notifiers should be considerably small so applying KISS paradigm here.
       
   323     if (CheckReferenceCount(libName, EFalse))
       
   324         {
       
   325         DoUnload(libName);
       
   326         } 
       
   327     }
       
   328 
       
   329 void CAknNfySrv::DoUnload(const TDesC& aLibName)
       
   330     {
       
   331     for (TInt i = iNotifierArray.Count()-1; i >= 0; i--)
       
   332         {
       
   333         // Release notifiers from lib (reverse order to handle possible dependencies).
       
   334         if (iNotifierArray[i]->iLibraryName->CompareF(aLibName) == 0)
       
   335             {
       
   336             delete iNotifierArray[i];
       
   337             iNotifierArray.Remove(i);
       
   338 #ifdef _DEBUG
       
   339             RDebug::Print(_L("Deleted notifier from library %S"), &aLibName);    
       
   340 #endif
       
   341             }
       
   342         }
       
   343             
       
   344     for (TInt i = iLibraryArray.Count()-1; i >= 0; i--)
       
   345         {
       
   346         if (iLibraryArray[i]->iLibraryName->CompareF(aLibName) == 0)
       
   347             {
       
   348             delete iLibraryArray[i];
       
   349             iLibraryArray.Remove(i);
       
   350 #ifdef _DEBUG
       
   351             RDebug::Print(_L("Deleted library"));    
       
   352 #endif
       
   353             break;
       
   354             }
       
   355         }        
       
   356         
       
   357     User::Heap().Compress();
       
   358 #ifdef _DEBUG
       
   359     RDebug::Print(_L("Heap compressed"));    
       
   360 #endif
       
   361     }
       
   362 
       
   363 
       
   364 CAknNfySrv::~CAknNfySrv()
       
   365     {
       
   366     delete iLibraryRemover;
       
   367     for (TInt i = iNotifierArray.Count()-1; i >= 0; i--)
       
   368         {
       
   369         delete iNotifierArray[i];
       
   370         }
       
   371     iNotifierArray.Close();             
       
   372     for (TInt i = iLibraryArray.Count()-1; i >= 0; i--)
       
   373         {
       
   374         delete iLibraryArray[i];
       
   375         }
       
   376     iLibraryArray.Close();
       
   377     }
       
   378 
       
   379 void CAknNfySrv::HandleClientExit(CAknNfySrvSession* /*aSession*/)
       
   380     {
       
   381     }
       
   382 
       
   383 void CAknNfySrv::UnbalanceReferenceCount(TUid aUid, TBool aAddCount)
       
   384     {
       
   385     CAknNotifierEntry* entry = CAknNfySrv::FindEntry(aUid);
       
   386     if (entry)
       
   387         {
       
   388         CheckReferenceCount(*entry->iLibraryName, aAddCount);
       
   389         if (!aAddCount)
       
   390             {
       
   391             // In order to free memory, we may need to allocate memory.
       
   392             TRAP_IGNORE(CheckPendingRemovalsL()); 
       
   393             }
       
   394         }
       
   395     }
       
   396     
       
   397 // future proofing    
       
   398 void CAknNfySrv::NotifierExtension(TUid /*aExtensionUid*/, TAny*& /*aGenParam*/)
       
   399     {    
       
   400     }
       
   401     
       
   402 // End of file