--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailservermonitor/src/emailshutter.cpp Wed Sep 01 12:28:57 2010 +0100
@@ -0,0 +1,699 @@
+/*
+* 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 <e32base.h>
+#include <e32std.h>
+#include <e32des16.h> // Descriptors
+
+#include <e32property.h> // RProperty
+#include <apgtask.h> // TApaTaskList
+#include <w32std.h> // RWsSession
+#include <s32mem.h> // RDesRead/WriteStream
+
+#include <AlwaysOnlineManagerClient.h> // RAlwaysOnlineClientSession
+#include <CPsRequestHandler.h> // CPSRequestHandler
+#include <centralrepository.h> // CRepository
+#include <aisystemuids.hrh> // HomeScreen UIDs
+
+#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
+ { KGeneralSettingsAppUidAsTInt }, // General settings
+ };
+
+// Applications that should not be closed. Should include only system
+// applications that free the email resources by some other means.
+const TUid KApplicationsNotToBeClosed[] =
+ {
+ { AI_SID_AIFW_EXE }, // HomeScreen
+ { AI_UID3_AIFW_COMMON }, // HomeScreen
+ };
+
+// Non-UI clients that need to be closed
+const TUid KOtherClientsToClose[] =
+ {
+ { KPcsServerProcessUidAsTInt }, // PCS server
+ { FSMailServerUidAsTInt }, // FSMailServer
+ };
+
+// Plugin processes that need to be closed
+const TUid KPluginProcessesToClose[] =
+ {
+ // MfE plugin
+ { 0x20012BEE }, // KUidEasStartup
+ { 0x20012BEC }, // KUidEasTarmAccess
+ { 0x20012BD4 }, // KEasLogSenderServer
+ { 0x20012BE6 }, // KUidEasServer
+ // Oz plugin
+ { 0x2002136A }, // monitor
+ { 0x20021367 }, // server
+ };
+
+// Message store processes that need to be closed
+const TUid KMsgStoreProcessesToClose[] =
+ {
+ { KUidMessageStoreExe }, // MessageStoreExe.exe
+ { KUidEmailStorePreInstallExe } // MessageStorePreInstallExe
+ };
+
+const TInt KEmailUidExtraBuffer = 2 * KEmailPlatformApiUidItemSize;
+
+// ======== 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;
+ iInstStatusProperty.Close();
+ iPlatformApiAppsToClose.Close();
+ }
+
+// ---------------------------------------------------------------------------
+// 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( error, "RProperty::Define (EEmailPsKeyInstallationStatus) failed!" );
+ ERROR_1( error, " error code: ", error );
+ User::Leave( error );
+ }
+
+ error = iInstStatusProperty.Attach( KEmailShutdownPsCategory,
+ EEmailPsKeyInstallationStatus );
+ if( error != KErrNone )
+ {
+ ERROR( error, "RProperty::Attach (EEmailPsKeyInstallationStatus) failed!" );
+ ERROR_1( error, " error code: ", error );
+ User::Leave( error );
+ }
+
+ // Define P&S key used to register platform API applications
+ error = RProperty::Define( EEmailPsKeyPlatformApiAppsToCloseLength,
+ RProperty::EInt,
+ KAllowAllPolicy,
+ KWriteDeviceDataPolicy );
+
+ if( error != KErrNone && error != KErrAlreadyExists )
+ {
+ ERROR( error, "RProperty::Define (EEmailPsKeyPlatformApiAppsToCloseLength) failed!" );
+ ERROR_1( error, " error code: ", error );
+ }
+
+ // Define P&S key used to register platform API applications
+ error = RProperty::Define( EEmailPsKeyPlatformApiAppsToClose,
+ RProperty::EByteArray,
+ KAllowAllPolicy,
+ KWriteDeviceDataPolicy );
+
+ if( error != KErrNone && error != KErrAlreadyExists )
+ {
+ ERROR( error, "RProperty::Define (EEmailPsKeyPlatformApiAppsToClose) failed!" );
+ ERROR_1( error, " error code: ", 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 );
+
+ // First end our own applications that are defined in hard coded list
+ TInt count = sizeof(KApplicationsToClose) / sizeof(TUid);
+ for( TInt i = 0; i<count; i++ )
+ {
+ TApaTask task = taskList.FindApp( KApplicationsToClose[i] );
+ if ( task.Exists() )
+ {
+ INFO_1( "Closing UI app with UID: %d", KApplicationsToClose[i].iUid );
+
+ task.EndTask();
+ }
+ }
+
+ // Then end applications that are registered in P&S as platform API users
+ for( TInt i = 0; i<iPlatformApiAppsToClose.Count(); i++ )
+ {
+ TApaTask task = taskList.FindApp( iPlatformApiAppsToClose[i] );
+ if ( task.Exists() )
+ {
+ INFO_1( "Closing API UI app with UID: %d", iPlatformApiAppsToClose[i].iUid );
+
+ task.EndTask();
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &session );
+ }
+
+// ---------------------------------------------------------------------------
+// Define and publish the P&S key to inform all related services about the
+// installation, so that they can shutdown themselves gracefully
+// ---------------------------------------------------------------------------
+//
+void CEmailShutter::PublishPsKey( TInt aKey )
+ {
+ FUNC_LOG;
+ TInt error = RProperty::Define( aKey,
+ RProperty::EInt,
+ KAllowAllPolicy,
+ KPowerMgmtPolicy);
+
+ ERROR_1( error, "RProperty::Define error code: %d", error );
+
+ RProperty psProperty;
+ error = psProperty.Attach( KEmailShutdownPsCategory,
+ aKey );
+ ERROR_1( error, "RProperty::Attach error code: %d", error );
+
+ if( error == KErrNone )
+ {
+ error = psProperty.Set( KEmailShutterPsValue );
+
+ ERROR_1( error, "RProperty::Set error code: %d", error );
+ }
+ psProperty.Close();
+ }
+
+// -----------------------------------------------------------------------------
+// Closes all non-email related plugins/services
+// -----------------------------------------------------------------------------
+//
+void CEmailShutter::Close3rdPartyServices()
+ {
+ FUNC_LOG;
+ TRAP_IGNORE( ClosePcsServerL() );
+ TRAP_IGNORE( CloseAOPluginL() );
+ }
+
+// -----------------------------------------------------------------------------
+// Sends command to Always Online server to stop fs email plugin
+// -----------------------------------------------------------------------------
+//
+void CEmailShutter::CloseAOPluginL()
+ {
+ FUNC_LOG;
+
+ RAlwaysOnlineClientSession aoSession;
+ CleanupClosePushL( aoSession );
+ TPckgBuf<TUid> 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<TUid> 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;
+ }
+
+ // Check also clients registered as platform API users
+ if( iPlatformApiAppsToClose.Find( aSid ) != KErrNotFound )
+ {
+ 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();
+ }
+
+ // First read the platform API UIDs from P&S, those are needed later
+ TRAP_IGNORE( ReadPlatformApiUidsL() );
+
+ // 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 ) );
+ }
+
+// ---------------------------------------------------------------------------
+// Reads platform API process UIDs from Publish and Subscribe key
+// ---------------------------------------------------------------------------
+//
+void CEmailShutter::ReadPlatformApiUidsL()
+ {
+ FUNC_LOG;
+
+ iPlatformApiAppsToClose.Reset();
+
+ // Read buffer length
+ TInt bufLength( 0 );
+ User::LeaveIfError( RProperty::Get( KEmailShutdownPsCategory,
+ EEmailPsKeyPlatformApiAppsToCloseLength,
+ bufLength ) );
+
+ // Allocate buffer for reading and then read the list of UIDs from P&S.
+ // Adding some extra buffer just in case the size key and actual list
+ // are out of sync. This shouldn't happen, but you never know.
+ HBufC8* readBuf = HBufC8::NewLC( bufLength + KEmailUidExtraBuffer );
+ TPtr8 readPtr = readBuf->Des();
+
+ User::LeaveIfError( RProperty::Get( KEmailShutdownPsCategory,
+ EEmailPsKeyPlatformApiAppsToClose,
+ readPtr ) );
+
+ RDesReadStream readStream( readPtr );
+ CleanupClosePushL( readStream );
+
+ // Get items count from the actual buffer
+ TInt itemsCount = readPtr.Length() / KEmailPlatformApiUidItemSize;
+
+ for ( TInt ii = 0;ii < itemsCount; ++ii )
+ {
+ // Read next UID from the stream
+ TUid item = TUid::Uid( readStream.ReadInt32L() );
+
+ // Append only UIDs of such applications that should be closed
+ TInt count = sizeof(KApplicationsNotToBeClosed) / sizeof(TUid);
+ if( !FindFromArray( item, KApplicationsNotToBeClosed, count ) )
+ {
+ iPlatformApiAppsToClose.AppendL( item );
+ }
+ }
+
+ CleanupStack::PopAndDestroy( 2, readBuf );
+ }