diff -r 000000000000 -r 8466d47a6819 emailservices/emailservermonitor/src/emailshutter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emailservices/emailservermonitor/src/emailshutter.cpp Thu Dec 17 08:39:21 2009 +0200 @@ -0,0 +1,589 @@ +/* +* Copyright (c) 2009 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: +* Implementation of EmailShutter +* +*/ +// Include Files + +#include +#include +#include // Descriptors + +#include // RProperty +#include // TApaTaskList +#include // RWsSession + +#include // RAlwaysOnlineClientSession +#include // CPSRequestHandler +#include // CRepository + +#include "FreestyleEmailUiConstants.h" // FS Email UI UID +#include "fsmtmsconstants.h" // MCE, Phonebook & Calendar UIDs +#include "EmailStoreUids.hrh" // KUidMessageStoreExe + +#include "emailtrace.h" +#include "emailshutdownconst.h" +#include "emailshutter.h" +#include "emailservermonitorconst.h" +#include "emailservermonitorutilities.h" +#include "emailservermonitor.h" + + +// UI Applications to be closed +const TUid KApplicationsToClose[] = + { + KFSEmailUiUid, // Freestyle Email UI + { SettingWizardUidAsTInt }, // TP Wizard + { KMceAppUid }, // MCE + { KPhoneBookUid }, // Phonebook 1 & 2 + { KCalendarAppUid1 } // Calendar + }; + +// Non-UI clients that need to be closed +const TUid KOtherClientsToClose[] = + { + { FSMailServerUidAsTInt }, // FSMailServer + { KPcsServerProcessUidAsTInt } // PCS server + }; + +// Plugin processes that need to be closed +const TUid KPluginProcessesToClose[] = + { + // MfE plugin + { 0x10206961 }, // KUidEasServer + { 0x10206970 }, // KUidEasTarmAccess + { 0x10206972 }, // KUidEasStartup + { 0x20012BD4 }, // KEasLogSenderServer + // Oz plugin + { 0x2002136A }, // monitor + { 0x20021367 }, // server + }; + +// Message store processes that need to be closed +const TUid KMsgStoreProcessesToClose[] = + { + { KUidMessageStoreExe }, // MessageStoreExe.exe + { KUidEmailStorePreInstallExe } // MessageStorePreInstallExe + }; + + +// ======== MEMBER FUNCTION DEFINITIONS ======== + +// --------------------------------------------------------------------------- +// Two-phased class constructor. +// --------------------------------------------------------------------------- +// +CEmailShutter* CEmailShutter::NewL() + { + FUNC_LOG; + CEmailShutter* self = CEmailShutter::NewLC(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// Two-phased class constructor, leaves newly created object in cleanup stack. +// --------------------------------------------------------------------------- +// +CEmailShutter* CEmailShutter::NewLC() + { + FUNC_LOG; + CEmailShutter* self = new (ELeave) CEmailShutter(); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// --------------------------------------------------------------------------- +// Default constructor +// --------------------------------------------------------------------------- +// +CEmailShutter::CEmailShutter() + : CActive( EPriorityStandard ), iMonitor( NULL ) + { + FUNC_LOG; + } + +// --------------------------------------------------------------------------- +// Default destructor +// --------------------------------------------------------------------------- +// +CEmailShutter::~CEmailShutter() + { + FUNC_LOG; + } + +// --------------------------------------------------------------------------- +// Second phase class constructor. +// --------------------------------------------------------------------------- +// +void CEmailShutter::ConstructL() + { + FUNC_LOG; + // Define and attach/subscribe to P&S to get the shutdown event from + // installation initiator(s) + TInt error = iInstStatusProperty.Define( EEmailPsKeyInstallationStatus, + RProperty::EInt, + KAllowAllPolicy, + KPowerMgmtPolicy ); + if( error != KErrNone && error != KErrAlreadyExists ) + { + ERROR_1( error, "RProperty::Define failed, error code: ", error ); + User::Leave( error ); + } + + error = iInstStatusProperty.Attach( KEmailShutdownPsCategory, + EEmailPsKeyInstallationStatus ); + if( error != KErrNone ) + { + ERROR_1( error, "RProperty::Attach failed, error code: ", error ); + User::Leave( error ); + } + + CActiveScheduler::Add(this); + } + +// --------------------------------------------------------------------------- +// Starts observing P&S shutdown event +// --------------------------------------------------------------------------- +// +void CEmailShutter::StartObservingShutdownEvent() + { + FUNC_LOG; + SetActive(); + iInstStatusProperty.Subscribe( iStatus ); + } + +// --------------------------------------------------------------------------- +// Set P&S key after installation is done +// --------------------------------------------------------------------------- +// +void CEmailShutter::SetPsKeyInstallationFinished() + { + FUNC_LOG; + TInt error = iInstStatusProperty.Set( EEmailPsValueInstallationFinished ); + ERROR_1( error, "RProperty::Set error code: %d", error ); + } + +// --------------------------------------------------------------------------- +// Restart needed services after installation is finished +// --------------------------------------------------------------------------- +// +void CEmailShutter::RestartServicesAfterInstallation() + { + TRAP_IGNORE( StartAoPluginL() ); + TRAP_IGNORE( StartPcsServerL() ); + } + +// --------------------------------------------------------------------------- +// Set pointer to Email Server Monitor object +// --------------------------------------------------------------------------- +// +void CEmailShutter::SetMonitor( CEmailServerMonitor* aMonitor ) + { + iMonitor = aMonitor; + } + +// --------------------------------------------------------------------------- +// RunL of active object +// --------------------------------------------------------------------------- +// +void CEmailShutter::RunL() + { + FUNC_LOG; + if( iStatus == KErrNone ) + { + TInt value( 0 ); + TInt error = iInstStatusProperty.Get( value ); + ERROR_1( error, "RProperty::Get error code: %d", error ); + + // Verify that the P&S value indicates that installation is starting + if( error == KErrNone && + value == EEmailPsValueInstallationStarting ) + { + StartShutdown(); + + // Send "installation OK to continue" event to installation + // initiator once everyting is shutdown + error = iInstStatusProperty.Set( EEmailPsValueInstallationOkToStart ); + ERROR_1( error, "RProperty::Set error code: %d", error ); + + // Finally shutdown ourselves also + CActiveScheduler::Stop(); + } + else + { + // Re-subscribe + StartObservingShutdownEvent(); + } + } + else + { + ERROR_1( iStatus.Int(), "CEmailShutter::RunL error code: %d", iStatus.Int() ); + } + } + +// --------------------------------------------------------------------------- +// Cancel active object +// --------------------------------------------------------------------------- +// +void CEmailShutter::DoCancel() + { + FUNC_LOG; + iInstStatusProperty.Cancel(); + } + +// --------------------------------------------------------------------------- +// End client applications gracefully +// --------------------------------------------------------------------------- +// +void CEmailShutter::EndClients() + { + FUNC_LOG; + // End UI applications, ignore errors + TRAP_IGNORE( EndApplicationsL() ); + + // Define and publish the P&S key to give the clients change to close + // themselves gracefully + PublishPsKey( EEmailPsKeyShutdownClients ); + } + +// --------------------------------------------------------------------------- +// End UI applications gracefully +// --------------------------------------------------------------------------- +// +void CEmailShutter::EndApplicationsL() + { + FUNC_LOG; + RWsSession session; + User::LeaveIfError( session.Connect() ); + CleanupClosePushL( session ); + + TApaTaskList taskList( session ); + + TInt count = sizeof(KApplicationsToClose) / sizeof(TUid); + for( TInt i = 0; i id( KAlwaysOnlineEmailPluginUid ); + aoSession.SendSinglePacketL( EServerAPIBaseCommandStop, id ); + CleanupStack::PopAndDestroy( &aoSession ); + } + + +// ----------------------------------------------------------------------------- +// Sends command to Always Online server to start fs email plugin +// ----------------------------------------------------------------------------- +// +void CEmailShutter::StartAoPluginL() const + { + FUNC_LOG; + RAlwaysOnlineClientSession aoSession; + CleanupClosePushL( aoSession ); + TPckgBuf id( KAlwaysOnlineEmailPluginUid ); + aoSession.SendSinglePacketL( EServerAPIBaseCommandStart, id ); + CleanupStack::PopAndDestroy( &aoSession ); + } + +// ----------------------------------------------------------------------------- +// Closes PCS (Predictive Contact Search) server +// ----------------------------------------------------------------------------- +// +void CEmailShutter::ClosePcsServerL() + { + FUNC_LOG; + // If PCS server not running, don't request shutdown, because in this case + // the server need to be started before it can process the shutdown request + if( IsProcessRunning( KPcsServerProcessUidAsTInt ) ) + { + INFO( "Closing PCS server" ); + CPSRequestHandler* pcs = CPSRequestHandler::NewLC(); + pcs->ShutdownServerL(); + CleanupStack::PopAndDestroy( pcs ); + } + } + +// ----------------------------------------------------------------------------- +// Starts PCS (Predictive Contact Search) server +// ----------------------------------------------------------------------------- +// +void CEmailShutter::StartPcsServerL() const + { + FUNC_LOG; + CPSRequestHandler* pcs = CPSRequestHandler::NewL(); + delete pcs; + } + +// --------------------------------------------------------------------------- +// Try to find the UID given as parameter from the array given as parameter. +// +// @param aSid Process UID to be searched +// @param aArray Array from where to search +// @param aArrayCount Item count of the aArray +// @return ETrue if the UID can be found from the array, otherwise EFalse. +// --------------------------------------------------------------------------- +// +TBool CEmailShutter::FindFromArray( + const TUid aSid, + const TUid aArray[], + const TInt aArrayCount ) + { + for( TInt i = 0; i < aArrayCount; i++ ) + { + if( aArray[i] == aSid ) + { + return ETrue; + } + } + return EFalse; + } + +// --------------------------------------------------------------------------- +// Checks does this UID belong to the list of the services that we need to +// close down. +// +// @param aSid Process UID to check +// @param aMode Killing mode, are we now killing clients, plugins or msg store +// @return ETrue if this is one of the services we need to close in specified +// mode, otherwise EFalse +// --------------------------------------------------------------------------- +// +TBool CEmailShutter::NeedToKillThisProcess( + const TUid aSid, + const TEmailShutterKillingMode aMode ) + { + if( aMode == EKillingModeClients || + aMode == EKillingModeAll ) + { + // In case of clients we need to check applications and other clients + TInt count = sizeof(KApplicationsToClose) / sizeof(TUid); + if( FindFromArray( aSid, KApplicationsToClose, count ) ) + { + return ETrue; + } + + count = sizeof(KOtherClientsToClose) / sizeof(TUid); + if( FindFromArray( aSid, KOtherClientsToClose, count ) ) + { + return ETrue; + } + } + + if( aMode == EKillingModePlugins || + aMode == EKillingModeAll ) + { + TInt count = sizeof(KPluginProcessesToClose) / sizeof(TUid); + if( FindFromArray( aSid, KPluginProcessesToClose, count ) ) + { + return ETrue; + } + } + + if( aMode == EKillingModeMsgStore || + aMode == EKillingModeAll ) + { + TInt count = sizeof(KMsgStoreProcessesToClose) / sizeof(TUid); + if( FindFromArray( aSid, KMsgStoreProcessesToClose, count ) ) + { + return ETrue; + } + } + + return EFalse; + } + +// --------------------------------------------------------------------------- +// Kills all the related processes gracelessly. This is used as a backup for +// those processes that didn't close themselves gracefully. +// --------------------------------------------------------------------------- +// +TBool CEmailShutter::KillEmAll( + const TEmailShutterKillingMode aMode, /* = EKillingModeAll*/ + const TBool aOnlyCheckIfRunning /* = EFalse */ ) + { + FUNC_LOG; + // Having tried graceful shutdown, we need to kill any remaining processes + // matching the SID. Note that killing a process may re-order the list of + // remaining processes, so the search must start from the top again. + + TBool found( EFalse ); + TBool needToScanFullList; + TFullName fullName; + + do + { + needToScanFullList = EFalse; + TFindProcess findProcess; + + while( findProcess.Next(fullName) == KErrNone ) + { + RProcess process; + TInt error = process.Open( findProcess ); + // In case of error just skip this process, don't leave + if( error == KErrNone ) + { + TUid sid( process.SecureId() ); + if ( NeedToKillThisProcess( sid, aMode ) && // Is this our process and + process.ExitType() == EExitPending ) // and is the process alive + { + found = ETrue; + + // Kill the found process if aOnlyCheckIfRunning flag not set + if( !aOnlyCheckIfRunning ) + { + INFO_1( "Killing process with UID: %d", sid.iUid ); + + process.Kill(KErrNone); + needToScanFullList = ETrue; + } + } + } + process.Close(); + } + + } while (needToScanFullList); + + return found; + } + +// --------------------------------------------------------------------------- +// Highest level function to close everything in right order +// --------------------------------------------------------------------------- +// +void CEmailShutter::StartShutdown() + { + FUNC_LOG; + // Cancel Email Server monitoring before closing the server + if( iMonitor ) + { + iMonitor->Cancel(); + } + + // End all clients + EndClients(); + // Wait some time to give the clients some time to shut down themselves + Wait( KTimeToWaitApplicationsInSeconds ); + + // End all 3rd party clients + Close3rdPartyServices(); + WaitInCycles( KMaxTimeToWaitClientsInSeconds, EKillingModeClients ); + + // Kill gracelessly all remaining clients + KillEmAll( EKillingModeClients ); + + // Define and publish the P&S key to give the plugin servers change to + // close themselves gracefully + PublishPsKey( EEmailPsKeyShutdownPlugins ); + // Wait some time to give the plugins some time to shut down themselves + WaitInCycles( KMaxTimeToWaitPluginsInSeconds, EKillingModePlugins ); + // Kill gracelessly all remaining plugin processes + KillEmAll( EKillingModePlugins ); + + // Define and publish the P&S key to give the msg store change to close + // itself gracefully + PublishPsKey( EEmailPsKeyShutdownMsgStore ); + // Wait some time to give the msg store some time to shut down itself + WaitInCycles( KMaxTimeToWaitMsgStoreInSeconds, EKillingModeMsgStore ); + // Kill gracelessly all remaining message store processes + KillEmAll( EKillingModeMsgStore ); + + // Kill gracelessly all remaining processes + KillEmAll(); + + INFO( "Finished Shutdown" ); + } + +// --------------------------------------------------------------------------- +// Waits in cycles and checks between cycles have all relevant processes +// closed or do we still need to wait. Returns when either aMaxWaitTime +// has elapsed or when all relevant processes have been shutdown. +// --------------------------------------------------------------------------- +// +void CEmailShutter::WaitInCycles( + const TInt aMaxWaitTime, + const TEmailShutterKillingMode aMode ) + { + FUNC_LOG; + TInt totalWaitTime = 0; + do + { + // Do the wait and increase total waiting time counter + Wait( KWaitTimeCycleInSeconds ); + totalWaitTime += KWaitTimeCycleInSeconds; + // Do this as long as aMaxWaitTime has not elapsed and + // there are some process(es) to wait for + } while ( ( totalWaitTime < aMaxWaitTime ) && KillEmAll( aMode, ETrue ) ); + }