uifw/AknGlobalUI/AknCapServer/src/AknCapServerShutdown.cpp
changeset 0 2f259fa3e83a
child 9 aabf2c525e0f
child 14 3320e4e6e8bb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AknGlobalUI/AknCapServer/src/AknCapServerShutdown.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,362 @@
+/*
+* Copyright (c) 2005-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:  Handles shutdown situation.
+*
+*/
+
+#include "AknCapServerShutdown.h"
+#include <apgwgnam.h>
+#include <coemain.h>
+#include <apgtask.h>
+#include <coedef.h>
+#include <eiksvdef.h>
+
+#include <gfxtranseffect/gfxtranseffect.h>
+#include "akntranseffect.h" // for Transition effect enumerations
+
+// Delay after sending rogue apps a kill signal before completing the shutdown.
+const TInt KEikServShutdownAppKillDelay = 1000000;  // 1 second 
+const TUid KCapServerUid = { 0x10207218 };
+const TUid KFepSwitchWGId = {0xfabbabba}; // hoping that value is to stay...
+
+_LIT( KViewServerThreadName, "ViewServerThread" );
+_LIT( KUikonWatchersThreadName, "UikonWatchers" );
+_LIT( KAknCapServerThreadName, "akncapserver" ); 
+_LIT( KEikAppUiServerThreadName, "EikAppUiServerThread" );	
+_LIT( KEikAppClock2ThreadName, "adtupdater" );	
+_LIT( KEikAppBsengineThreadName, "bsengine" );	
+
+// shut critical thread may cause system to reset during shut up process.
+TBool IsSystemCriticalThread( const RThread& aThread )
+    {
+    if ( ( User::Critical( aThread ) == User::ESystemCritical ) ||
+         ( aThread.Name() == KViewServerThreadName ) ||
+         ( aThread.Name() == KAknCapServerThreadName ) ||
+         ( aThread.Name() == KUikonWatchersThreadName ) ||
+         ( aThread.Name() == KEikAppClock2ThreadName ) ||
+         ( aThread.Name() == KEikAppBsengineThreadName ) ||
+		 ( aThread.Name() == KEikAppUiServerThreadName ) )
+        {
+        return ETrue;
+        }
+
+    return EFalse;
+    }
+
+CAknCapServerShutdown::CAknCapServerShutdown()
+: iWs(CCoeEnv::Static()->WsSession())
+    {
+    }
+    
+CAknCapServerShutdown::~CAknCapServerShutdown()
+    {
+    if (iAppExitNotifiers)
+        {
+        iAppExitNotifiers->ResetAndDestroy();
+        }
+    delete iAppExitNotifiers;
+    delete iShutdownTimeout;
+    }
+    
+void CAknCapServerShutdown::ConstructL()
+    {
+#ifdef _DEBUG
+    RDebug::Print(_L("Creating app exit notifiers"));
+#endif
+    iAppExitNotifiers = new (ELeave) CArrayPtrFlat<CAppExitNotifier>(4);
+    }
+
+void CAknCapServerShutdown::ShutdownAppsL(
+    const TUid aRequesterUID, 
+    const RMessage2& aShutdownMessage, 
+    const TInt aTimeoutInMicroseconds)
+    {
+    GfxTransEffect::BeginFullScreen(
+        AknTransEffect::EApplicationExit,
+        TRect(0,0,0,0),
+        AknTransEffect::EParameterType,
+        AknTransEffect::GfxTransParam(KCapServerUid, AknTransEffect::TParameter::EAvkonCheck));
+      
+    // Exit all apps currently running, with the exception of the one whose UID is passed in.
+    iShutdownMessage = aShutdownMessage;
+
+    CArrayFixFlat<TInt>* wgIds = new(ELeave) CArrayFixFlat<TInt>(4);
+    CleanupStack::PushL(wgIds);
+    User::LeaveIfError(iWs.WindowGroupList(0, wgIds));
+    TInt lastEntry = wgIds->Count() - 1;
+
+    iTotalAppExitNotifiers = 0;
+    iAppExitNotifiers->ResetAndDestroy();
+
+    for ( TInt ii = lastEntry; ii >= 0; ii-- )
+      {
+      CApaWindowGroupName* doomed = CApaWindowGroupName::NewLC(iWs, wgIds->At(ii));
+      RThread thd;
+      TThreadId threadId;
+
+#ifdef _DEBUG
+      TBool isSystem = doomed->IsSystem();
+      TBool isHidden = doomed->Hidden();
+#endif // _DEBUG
+      // This UID comes from the app, not the mmp!
+      TUid uid = doomed->AppUid(); 
+      iWs.GetWindowGroupClientThreadId(wgIds->At(ii), threadId);
+      thd.Open(threadId);  
+	  CleanupClosePushL( thd );
+
+      // Is this app OK to kill? We don't kill the this app, EikSrv backdrop or the app that 
+      // instigated the shutdown.
+      if ((uid != aRequesterUID) && ( uid != KCapServerUid ) && ( uid != KFepSwitchWGId ) && 
+             ( doomed->Caption() != EIKON_SERVER_BACKDROP_WINDOW_GROUP_NAME ) &&
+			  !IsSystemCriticalThread( thd ) )  
+         {
+         TApaTask* harbingerOfDoom = new (ELeave) TApaTask(iWs);
+         CleanupDeletePushL(harbingerOfDoom);
+         harbingerOfDoom->SetWgId(wgIds->At(ii));
+                
+#ifdef _DEBUG   // Silliness to prevent "using lvalue as rvalue" warnings.
+         TPtrC caption(doomed->Caption()); // doomed->Caption());
+         TPtrC docname(doomed->DocName()); // doomed->DocName());
+         TPtrC wgname(doomed->WindowGroupName());  // doomed->WindowGroupName());
+             
+         _LIT(KDebugShutdownMsg1, "SHUTDOWN: Exiting App (ThreadId %d, WgId %d, ");
+         RDebug::Print(KDebugShutdownMsg1, TUint(harbingerOfDoom->ThreadId()), wgIds->At(ii));
+         _LIT(KDebugShutdownMsg2, "UID 0x%X); Caption: %S, ");
+         RDebug::Print(KDebugShutdownMsg2, uid.iUid, &caption);
+             
+         _LIT(KDebugShutdownMsg3, "Docname: %S, system %d, ");
+         RDebug::Print(KDebugShutdownMsg3, &docname, isSystem);
+             
+         _LIT(KDebugShutdownMsg4, "hidden %d, WGName : %S");
+         RDebug::Print(KDebugShutdownMsg4, isHidden, &wgname);
+         TPtrC threadName(thd.Name());
+         RDebug::Print(_L("thread:%S)"), &threadName );
+#endif // _DEBUG
+         CAppExitNotifier* exiter = CAppExitNotifier::NewL(harbingerOfDoom, this);
+         CleanupStack::Pop(); // harbingerOfDoom
+         CleanupStack::PushL(exiter);
+         iAppExitNotifiers->AppendL(exiter);
+         iTotalAppExitNotifiers++;
+         CleanupStack::Pop(); //exiter
+         exiter->ExitTask();
+         } 
+#ifdef _DEBUG           
+      else 
+         {
+         TPtrC caption = doomed->Caption();
+         TPtrC threadName(thd.Name());
+         RDebug::Print(_L("SHUTDOWN: privileged App %S(thread:%S) is not being closed"), &caption, &threadName );
+         }
+#endif
+
+      CleanupStack::PopAndDestroy( &thd ); //thd
+      CleanupStack::PopAndDestroy();  //doomed
+      }
+
+    // If no apps were running, complete straight away.
+    if (iTotalAppExitNotifiers == 0)
+        {
+        iShutdownMessage.Complete(KErrNone);
+        }
+    else
+        {
+        // Start the timeout timer.
+        iShutdownTimeout = CPeriodic::NewL(CActive::EPriorityHigh); 
+        
+        iShutdownTimeout->Start(
+            aTimeoutInMicroseconds, 
+            aTimeoutInMicroseconds, 
+            TCallBack(ShutdownTimeoutL, this));
+            
+        iShutdownState=EShutdownWaitingForApps;
+        }
+
+    CleanupStack::PopAndDestroy(); // wgIds
+    }
+    
+void CAknCapServerShutdown::CancelShutdownAppsL()
+    {
+    if ( !iShutdownMessage.IsNull() )
+        {
+        iShutdownMessage.Complete(KErrCancel);
+        }
+    }
+
+// Static callback from Shutdown timeout.
+TInt CAknCapServerShutdown::ShutdownTimeoutL(TAny* aPtr)
+    {
+    return (STATIC_CAST(CAknCapServerShutdown*,aPtr))->DoShutdownTimeoutL();
+    }
+
+TInt CAknCapServerShutdown::DoShutdownTimeoutL()
+    {
+    if (iShutdownState == EShutdownWaitingForApps)
+        { //The timer has completed because not all apps have closed cleanly in the allotted time.
+#ifdef _DEBUG
+        RDebug::Print(_L("SHUTDOWN: Timeout! Killing remaining apps"));
+#endif
+        delete iShutdownTimeout;
+        iShutdownTimeout = NULL;
+        
+        // Kill any remaining apps forcibly.
+        for (TInt ii = 0; ii < iAppExitNotifiers->Count(); ii++)
+            {
+            if (!iAppExitNotifiers->At(ii)->IsDead())
+                {
+                iAppExitNotifiers->At(ii)->KillTask();
+                }
+            }
+        
+        // Now the remaining apps have been killed, there is no need to wait any longer.
+        // We can allow the machine to turn off after a short delay.
+        iShutdownTimeout = CPeriodic::NewL(CActive::EPriorityHigh); 
+        
+        iShutdownTimeout->Start(
+            KEikServShutdownAppKillDelay, 
+            KEikServShutdownAppKillDelay,
+            TCallBack(ShutdownTimeoutL, this));
+            
+        iShutdownState = EShutdownKillingRogueApps;
+        }
+    else
+        { 
+        // The timer has completed because not all apps have responded to a kill request in the 
+        // allotted time (this is bad).
+#ifdef _DEBUG
+        RDebug::Print(_L("SHUTDOWN: Error! At least one app failed to respond to kill request. Shutting down..."));
+#endif
+        ProceedWithShutdown();
+        }
+
+    return EFalse;
+    }
+
+// Callback from CAppExitNotifier.
+void CAknCapServerShutdown::AppExitNotifierL(
+    const CAppExitNotifier* aNotifier, 
+    CAppExitNotifier::TAppExitMethod aHowClosed)
+    {
+    if (aHowClosed == CAppExitNotifier::EAppExitNormal)
+        {
+#ifdef _DEBUG
+        RDebug::Print(_L("SHUTDOWN: App with ThreadId %d has exited"), TUint(aNotifier->ThreadId()));
+#else
+        aNotifier->ThreadId(); // just for fixing warning
+#endif
+        }
+    else if (aHowClosed == CAppExitNotifier::EAppExitForced)
+        {
+#ifdef _DEBUG
+        RDebug::Print(_L("SHUTDOWN: App with ThreadId %d was killed"), TUint(aNotifier->ThreadId()));
+#else
+        aNotifier->ThreadId(); // just for fixing warning
+#endif
+        }
+    iTotalAppExitNotifiers--;
+    
+    // If all the apps have exited then complete the request.
+    if (iTotalAppExitNotifiers == 0)
+        {
+        ProceedWithShutdown();
+        }
+    }
+    
+// Cleanup of objects used in shutdown, and signal to client that apps are all closed.
+void CAknCapServerShutdown::ProceedWithShutdown()
+    {
+    // Complete the client message.
+    iShutdownMessage.Complete(KErrNone);
+    // Delete all the notifiers
+    iAppExitNotifiers->ResetAndDestroy();
+    // and stop the timeout timer.
+    delete iShutdownTimeout;
+    iShutdownTimeout=NULL;
+    }
+
+//
+// class CAppExitNotifier
+// 
+CAknCapServerShutdown::CAppExitNotifier* CAknCapServerShutdown::CAppExitNotifier::NewL(
+    TApaTask* aTask, 
+    CAknCapServerShutdown* aObserver)
+    {
+    CAppExitNotifier* self = new (ELeave) CAppExitNotifier(aTask,aObserver);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(); //self
+    return self;
+    }
+
+CAknCapServerShutdown::CAppExitNotifier::~CAppExitNotifier()
+    {
+    Cancel();
+    delete iTask;
+    }
+
+void CAknCapServerShutdown::CAppExitNotifier::ExitTask()
+    {
+    iExitMethod = EAppExitNormal;
+    iTask->EndTask();
+    }
+
+void CAknCapServerShutdown::CAppExitNotifier::KillTask()
+    {
+    iExitMethod = EAppExitForced;
+    iTask->KillTask();
+    }
+
+TBool CAknCapServerShutdown::CAppExitNotifier::IsDead()
+    {
+    return iIsDead;
+    }
+
+const TApaTask& CAknCapServerShutdown::CAppExitNotifier::Task() const
+    {
+    return *iTask;
+    }
+
+const TThreadId CAknCapServerShutdown::CAppExitNotifier::ThreadId() const
+    {
+    return iThreadId;
+    }
+
+void CAknCapServerShutdown::CAppExitNotifier::ConstructL()
+    {
+    iThreadId = iTask->ThreadId();
+    User::LeaveIfError(iThread.Open(iThreadId));
+    iThread.Logon(iStatus);
+    SetActive();
+    }
+
+void CAknCapServerShutdown::CAppExitNotifier::RunL()
+    {
+    iIsDead = ETrue;
+    iObserver->AppExitNotifierL(this,iExitMethod);
+    }
+
+void CAknCapServerShutdown::CAppExitNotifier::DoCancel()
+    {
+    iThread.LogonCancel(iStatus);
+    }
+
+CAknCapServerShutdown::CAppExitNotifier::CAppExitNotifier(TApaTask* aTask, 
+    CAknCapServerShutdown* aObserver) 
+: CActive(EPriorityStandard),
+    iObserver(aObserver),
+    iTask(aTask)
+    {
+    CActiveScheduler::Add(this);
+    }
+
+// End of file