diff -r 000000000000 -r 2f259fa3e83a uifw/AknGlobalUI/AknCapServer/src/AknCapServerShutdown.cpp --- /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 +#include +#include +#include +#include + +#include +#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(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* wgIds = new(ELeave) CArrayFixFlat(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