uifw/AknGlobalUI/AknCapServer/src/AknCapServerShutdown.cpp
changeset 0 2f259fa3e83a
child 9 aabf2c525e0f
child 14 3320e4e6e8bb
equal deleted inserted replaced
-1:000000000000 0:2f259fa3e83a
       
     1 /*
       
     2 * Copyright (c) 2005-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:  Handles shutdown situation.
       
    15 *
       
    16 */
       
    17 
       
    18 #include "AknCapServerShutdown.h"
       
    19 #include <apgwgnam.h>
       
    20 #include <coemain.h>
       
    21 #include <apgtask.h>
       
    22 #include <coedef.h>
       
    23 #include <eiksvdef.h>
       
    24 
       
    25 #include <gfxtranseffect/gfxtranseffect.h>
       
    26 #include "akntranseffect.h" // for Transition effect enumerations
       
    27 
       
    28 // Delay after sending rogue apps a kill signal before completing the shutdown.
       
    29 const TInt KEikServShutdownAppKillDelay = 1000000;  // 1 second 
       
    30 const TUid KCapServerUid = { 0x10207218 };
       
    31 const TUid KFepSwitchWGId = {0xfabbabba}; // hoping that value is to stay...
       
    32 
       
    33 _LIT( KViewServerThreadName, "ViewServerThread" );
       
    34 _LIT( KUikonWatchersThreadName, "UikonWatchers" );
       
    35 _LIT( KAknCapServerThreadName, "akncapserver" ); 
       
    36 _LIT( KEikAppUiServerThreadName, "EikAppUiServerThread" );	
       
    37 _LIT( KEikAppClock2ThreadName, "adtupdater" );	
       
    38 _LIT( KEikAppBsengineThreadName, "bsengine" );	
       
    39 
       
    40 // shut critical thread may cause system to reset during shut up process.
       
    41 TBool IsSystemCriticalThread( const RThread& aThread )
       
    42     {
       
    43     if ( ( User::Critical( aThread ) == User::ESystemCritical ) ||
       
    44          ( aThread.Name() == KViewServerThreadName ) ||
       
    45          ( aThread.Name() == KAknCapServerThreadName ) ||
       
    46          ( aThread.Name() == KUikonWatchersThreadName ) ||
       
    47          ( aThread.Name() == KEikAppClock2ThreadName ) ||
       
    48          ( aThread.Name() == KEikAppBsengineThreadName ) ||
       
    49 		 ( aThread.Name() == KEikAppUiServerThreadName ) )
       
    50         {
       
    51         return ETrue;
       
    52         }
       
    53 
       
    54     return EFalse;
       
    55     }
       
    56 
       
    57 CAknCapServerShutdown::CAknCapServerShutdown()
       
    58 : iWs(CCoeEnv::Static()->WsSession())
       
    59     {
       
    60     }
       
    61     
       
    62 CAknCapServerShutdown::~CAknCapServerShutdown()
       
    63     {
       
    64     if (iAppExitNotifiers)
       
    65         {
       
    66         iAppExitNotifiers->ResetAndDestroy();
       
    67         }
       
    68     delete iAppExitNotifiers;
       
    69     delete iShutdownTimeout;
       
    70     }
       
    71     
       
    72 void CAknCapServerShutdown::ConstructL()
       
    73     {
       
    74 #ifdef _DEBUG
       
    75     RDebug::Print(_L("Creating app exit notifiers"));
       
    76 #endif
       
    77     iAppExitNotifiers = new (ELeave) CArrayPtrFlat<CAppExitNotifier>(4);
       
    78     }
       
    79 
       
    80 void CAknCapServerShutdown::ShutdownAppsL(
       
    81     const TUid aRequesterUID, 
       
    82     const RMessage2& aShutdownMessage, 
       
    83     const TInt aTimeoutInMicroseconds)
       
    84     {
       
    85     GfxTransEffect::BeginFullScreen(
       
    86         AknTransEffect::EApplicationExit,
       
    87         TRect(0,0,0,0),
       
    88         AknTransEffect::EParameterType,
       
    89         AknTransEffect::GfxTransParam(KCapServerUid, AknTransEffect::TParameter::EAvkonCheck));
       
    90       
       
    91     // Exit all apps currently running, with the exception of the one whose UID is passed in.
       
    92     iShutdownMessage = aShutdownMessage;
       
    93 
       
    94     CArrayFixFlat<TInt>* wgIds = new(ELeave) CArrayFixFlat<TInt>(4);
       
    95     CleanupStack::PushL(wgIds);
       
    96     User::LeaveIfError(iWs.WindowGroupList(0, wgIds));
       
    97     TInt lastEntry = wgIds->Count() - 1;
       
    98 
       
    99     iTotalAppExitNotifiers = 0;
       
   100     iAppExitNotifiers->ResetAndDestroy();
       
   101 
       
   102     for ( TInt ii = lastEntry; ii >= 0; ii-- )
       
   103       {
       
   104       CApaWindowGroupName* doomed = CApaWindowGroupName::NewLC(iWs, wgIds->At(ii));
       
   105       RThread thd;
       
   106       TThreadId threadId;
       
   107 
       
   108 #ifdef _DEBUG
       
   109       TBool isSystem = doomed->IsSystem();
       
   110       TBool isHidden = doomed->Hidden();
       
   111 #endif // _DEBUG
       
   112       // This UID comes from the app, not the mmp!
       
   113       TUid uid = doomed->AppUid(); 
       
   114       iWs.GetWindowGroupClientThreadId(wgIds->At(ii), threadId);
       
   115       thd.Open(threadId);  
       
   116 	  CleanupClosePushL( thd );
       
   117 
       
   118       // Is this app OK to kill? We don't kill the this app, EikSrv backdrop or the app that 
       
   119       // instigated the shutdown.
       
   120       if ((uid != aRequesterUID) && ( uid != KCapServerUid ) && ( uid != KFepSwitchWGId ) && 
       
   121              ( doomed->Caption() != EIKON_SERVER_BACKDROP_WINDOW_GROUP_NAME ) &&
       
   122 			  !IsSystemCriticalThread( thd ) )  
       
   123          {
       
   124          TApaTask* harbingerOfDoom = new (ELeave) TApaTask(iWs);
       
   125          CleanupDeletePushL(harbingerOfDoom);
       
   126          harbingerOfDoom->SetWgId(wgIds->At(ii));
       
   127                 
       
   128 #ifdef _DEBUG   // Silliness to prevent "using lvalue as rvalue" warnings.
       
   129          TPtrC caption(doomed->Caption()); // doomed->Caption());
       
   130          TPtrC docname(doomed->DocName()); // doomed->DocName());
       
   131          TPtrC wgname(doomed->WindowGroupName());  // doomed->WindowGroupName());
       
   132              
       
   133          _LIT(KDebugShutdownMsg1, "SHUTDOWN: Exiting App (ThreadId %d, WgId %d, ");
       
   134          RDebug::Print(KDebugShutdownMsg1, TUint(harbingerOfDoom->ThreadId()), wgIds->At(ii));
       
   135          _LIT(KDebugShutdownMsg2, "UID 0x%X); Caption: %S, ");
       
   136          RDebug::Print(KDebugShutdownMsg2, uid.iUid, &caption);
       
   137              
       
   138          _LIT(KDebugShutdownMsg3, "Docname: %S, system %d, ");
       
   139          RDebug::Print(KDebugShutdownMsg3, &docname, isSystem);
       
   140              
       
   141          _LIT(KDebugShutdownMsg4, "hidden %d, WGName : %S");
       
   142          RDebug::Print(KDebugShutdownMsg4, isHidden, &wgname);
       
   143          TPtrC threadName(thd.Name());
       
   144          RDebug::Print(_L("thread:%S)"), &threadName );
       
   145 #endif // _DEBUG
       
   146          CAppExitNotifier* exiter = CAppExitNotifier::NewL(harbingerOfDoom, this);
       
   147          CleanupStack::Pop(); // harbingerOfDoom
       
   148          CleanupStack::PushL(exiter);
       
   149          iAppExitNotifiers->AppendL(exiter);
       
   150          iTotalAppExitNotifiers++;
       
   151          CleanupStack::Pop(); //exiter
       
   152          exiter->ExitTask();
       
   153          } 
       
   154 #ifdef _DEBUG           
       
   155       else 
       
   156          {
       
   157          TPtrC caption = doomed->Caption();
       
   158          TPtrC threadName(thd.Name());
       
   159          RDebug::Print(_L("SHUTDOWN: privileged App %S(thread:%S) is not being closed"), &caption, &threadName );
       
   160          }
       
   161 #endif
       
   162 
       
   163       CleanupStack::PopAndDestroy( &thd ); //thd
       
   164       CleanupStack::PopAndDestroy();  //doomed
       
   165       }
       
   166 
       
   167     // If no apps were running, complete straight away.
       
   168     if (iTotalAppExitNotifiers == 0)
       
   169         {
       
   170         iShutdownMessage.Complete(KErrNone);
       
   171         }
       
   172     else
       
   173         {
       
   174         // Start the timeout timer.
       
   175         iShutdownTimeout = CPeriodic::NewL(CActive::EPriorityHigh); 
       
   176         
       
   177         iShutdownTimeout->Start(
       
   178             aTimeoutInMicroseconds, 
       
   179             aTimeoutInMicroseconds, 
       
   180             TCallBack(ShutdownTimeoutL, this));
       
   181             
       
   182         iShutdownState=EShutdownWaitingForApps;
       
   183         }
       
   184 
       
   185     CleanupStack::PopAndDestroy(); // wgIds
       
   186     }
       
   187     
       
   188 void CAknCapServerShutdown::CancelShutdownAppsL()
       
   189     {
       
   190     if ( !iShutdownMessage.IsNull() )
       
   191         {
       
   192         iShutdownMessage.Complete(KErrCancel);
       
   193         }
       
   194     }
       
   195 
       
   196 // Static callback from Shutdown timeout.
       
   197 TInt CAknCapServerShutdown::ShutdownTimeoutL(TAny* aPtr)
       
   198     {
       
   199     return (STATIC_CAST(CAknCapServerShutdown*,aPtr))->DoShutdownTimeoutL();
       
   200     }
       
   201 
       
   202 TInt CAknCapServerShutdown::DoShutdownTimeoutL()
       
   203     {
       
   204     if (iShutdownState == EShutdownWaitingForApps)
       
   205         { //The timer has completed because not all apps have closed cleanly in the allotted time.
       
   206 #ifdef _DEBUG
       
   207         RDebug::Print(_L("SHUTDOWN: Timeout! Killing remaining apps"));
       
   208 #endif
       
   209         delete iShutdownTimeout;
       
   210         iShutdownTimeout = NULL;
       
   211         
       
   212         // Kill any remaining apps forcibly.
       
   213         for (TInt ii = 0; ii < iAppExitNotifiers->Count(); ii++)
       
   214             {
       
   215             if (!iAppExitNotifiers->At(ii)->IsDead())
       
   216                 {
       
   217                 iAppExitNotifiers->At(ii)->KillTask();
       
   218                 }
       
   219             }
       
   220         
       
   221         // Now the remaining apps have been killed, there is no need to wait any longer.
       
   222         // We can allow the machine to turn off after a short delay.
       
   223         iShutdownTimeout = CPeriodic::NewL(CActive::EPriorityHigh); 
       
   224         
       
   225         iShutdownTimeout->Start(
       
   226             KEikServShutdownAppKillDelay, 
       
   227             KEikServShutdownAppKillDelay,
       
   228             TCallBack(ShutdownTimeoutL, this));
       
   229             
       
   230         iShutdownState = EShutdownKillingRogueApps;
       
   231         }
       
   232     else
       
   233         { 
       
   234         // The timer has completed because not all apps have responded to a kill request in the 
       
   235         // allotted time (this is bad).
       
   236 #ifdef _DEBUG
       
   237         RDebug::Print(_L("SHUTDOWN: Error! At least one app failed to respond to kill request. Shutting down..."));
       
   238 #endif
       
   239         ProceedWithShutdown();
       
   240         }
       
   241 
       
   242     return EFalse;
       
   243     }
       
   244 
       
   245 // Callback from CAppExitNotifier.
       
   246 void CAknCapServerShutdown::AppExitNotifierL(
       
   247     const CAppExitNotifier* aNotifier, 
       
   248     CAppExitNotifier::TAppExitMethod aHowClosed)
       
   249     {
       
   250     if (aHowClosed == CAppExitNotifier::EAppExitNormal)
       
   251         {
       
   252 #ifdef _DEBUG
       
   253         RDebug::Print(_L("SHUTDOWN: App with ThreadId %d has exited"), TUint(aNotifier->ThreadId()));
       
   254 #else
       
   255         aNotifier->ThreadId(); // just for fixing warning
       
   256 #endif
       
   257         }
       
   258     else if (aHowClosed == CAppExitNotifier::EAppExitForced)
       
   259         {
       
   260 #ifdef _DEBUG
       
   261         RDebug::Print(_L("SHUTDOWN: App with ThreadId %d was killed"), TUint(aNotifier->ThreadId()));
       
   262 #else
       
   263         aNotifier->ThreadId(); // just for fixing warning
       
   264 #endif
       
   265         }
       
   266     iTotalAppExitNotifiers--;
       
   267     
       
   268     // If all the apps have exited then complete the request.
       
   269     if (iTotalAppExitNotifiers == 0)
       
   270         {
       
   271         ProceedWithShutdown();
       
   272         }
       
   273     }
       
   274     
       
   275 // Cleanup of objects used in shutdown, and signal to client that apps are all closed.
       
   276 void CAknCapServerShutdown::ProceedWithShutdown()
       
   277     {
       
   278     // Complete the client message.
       
   279     iShutdownMessage.Complete(KErrNone);
       
   280     // Delete all the notifiers
       
   281     iAppExitNotifiers->ResetAndDestroy();
       
   282     // and stop the timeout timer.
       
   283     delete iShutdownTimeout;
       
   284     iShutdownTimeout=NULL;
       
   285     }
       
   286 
       
   287 //
       
   288 // class CAppExitNotifier
       
   289 // 
       
   290 CAknCapServerShutdown::CAppExitNotifier* CAknCapServerShutdown::CAppExitNotifier::NewL(
       
   291     TApaTask* aTask, 
       
   292     CAknCapServerShutdown* aObserver)
       
   293     {
       
   294     CAppExitNotifier* self = new (ELeave) CAppExitNotifier(aTask,aObserver);
       
   295     CleanupStack::PushL(self);
       
   296     self->ConstructL();
       
   297     CleanupStack::Pop(); //self
       
   298     return self;
       
   299     }
       
   300 
       
   301 CAknCapServerShutdown::CAppExitNotifier::~CAppExitNotifier()
       
   302     {
       
   303     Cancel();
       
   304     delete iTask;
       
   305     }
       
   306 
       
   307 void CAknCapServerShutdown::CAppExitNotifier::ExitTask()
       
   308     {
       
   309     iExitMethod = EAppExitNormal;
       
   310     iTask->EndTask();
       
   311     }
       
   312 
       
   313 void CAknCapServerShutdown::CAppExitNotifier::KillTask()
       
   314     {
       
   315     iExitMethod = EAppExitForced;
       
   316     iTask->KillTask();
       
   317     }
       
   318 
       
   319 TBool CAknCapServerShutdown::CAppExitNotifier::IsDead()
       
   320     {
       
   321     return iIsDead;
       
   322     }
       
   323 
       
   324 const TApaTask& CAknCapServerShutdown::CAppExitNotifier::Task() const
       
   325     {
       
   326     return *iTask;
       
   327     }
       
   328 
       
   329 const TThreadId CAknCapServerShutdown::CAppExitNotifier::ThreadId() const
       
   330     {
       
   331     return iThreadId;
       
   332     }
       
   333 
       
   334 void CAknCapServerShutdown::CAppExitNotifier::ConstructL()
       
   335     {
       
   336     iThreadId = iTask->ThreadId();
       
   337     User::LeaveIfError(iThread.Open(iThreadId));
       
   338     iThread.Logon(iStatus);
       
   339     SetActive();
       
   340     }
       
   341 
       
   342 void CAknCapServerShutdown::CAppExitNotifier::RunL()
       
   343     {
       
   344     iIsDead = ETrue;
       
   345     iObserver->AppExitNotifierL(this,iExitMethod);
       
   346     }
       
   347 
       
   348 void CAknCapServerShutdown::CAppExitNotifier::DoCancel()
       
   349     {
       
   350     iThread.LogonCancel(iStatus);
       
   351     }
       
   352 
       
   353 CAknCapServerShutdown::CAppExitNotifier::CAppExitNotifier(TApaTask* aTask, 
       
   354     CAknCapServerShutdown* aObserver) 
       
   355 : CActive(EPriorityStandard),
       
   356     iObserver(aObserver),
       
   357     iTask(aTask)
       
   358     {
       
   359     CActiveScheduler::Add(this);
       
   360     }
       
   361 
       
   362 // End of file