--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailservermonitor/src/emailservermonitor.cpp Wed Sep 01 12:28:57 2010 +0100
@@ -0,0 +1,408 @@
+/*
+* 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 EmailServerMonitor
+*
+*/
+
+// Include Files
+#include <e32base.h>
+#include <e32std.h>
+#include <e32des16.h> // Descriptors
+#include <apacmdln.h>
+#include <apgcli.h>
+
+#include <AlwaysOnlineManagerClient.h> // RAlwaysOnlineClientSession
+#include <CPsRequestHandler.h> // CPSRequestHandler
+
+#include "emailtrace.h"
+#include "emailservermonitorutilities.h"
+#include "emailservermonitor.h"
+#include "emailservermonitorconst.h"
+#include "emailshutter.h"
+
+const TUint KOneSecondInMicroSeconds = 1000000;
+
+const TInt KExternalServiceRestartDelay = 5 * KOneSecondInMicroSeconds;
+const TInt KInstallatioFinishedFlagSettingDelay = 2 * KOneSecondInMicroSeconds;
+
+// ======== MEMBER FUNCTION DEFINITIONS ========
+
+/**
+ * Two-phased class constructor.
+ */
+CEmailServerMonitor* CEmailServerMonitor::NewL()
+ {
+ FUNC_LOG;
+ CEmailServerMonitor* self = CEmailServerMonitor::NewLC();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+/**
+ * Two-phased class constructor.
+ */
+CEmailServerMonitor* CEmailServerMonitor::NewLC()
+ {
+ FUNC_LOG;
+ CEmailServerMonitor* self = new (ELeave) CEmailServerMonitor();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+/**
+ * Destructor of CEmailServerMonitor class.
+ */
+CEmailServerMonitor::~CEmailServerMonitor()
+ {
+ FUNC_LOG;
+ iApaLsSession.Close();
+ iProcess.Close();
+ iDelayTimer.Close();
+ if( iExternalServiceRestartTimer )
+ {
+ delete iExternalServiceRestartTimer;
+ iExternalServiceRestartTimer = NULL;
+ }
+ }
+
+/**
+ * Default class constructor.
+ * Only NewL can be called
+ */
+CEmailServerMonitor::CEmailServerMonitor()
+ : CActive( EPriorityStandard ),
+ iState( EEsmStateIdle ),
+ iRestarts( 0 ),
+ iShutter( NULL ),
+ iExternalServicesRestartState( EEsmEsrStateRestartNotNeeded )
+ {
+ FUNC_LOG;
+ }
+
+/**
+ * Second phase class constructor.
+ */
+void CEmailServerMonitor::ConstructL()
+ {
+ FUNC_LOG;
+ User::LeaveIfError( iApaLsSession.Connect() );
+ User::LeaveIfError( iDelayTimer.CreateLocal() );
+
+ CActiveScheduler::Add(this);
+ }
+
+/**
+ * Start email server monitoring.
+ */
+void CEmailServerMonitor::Start()
+ {
+ FUNC_LOG;
+ iLastRestartTime.UniversalTime();
+
+ // Initiate delayed restart and set correct state
+ InitiateDelayedRestart();
+ iState = EEsmStateInitializing;
+ }
+
+/**
+ * Set pointer to shutter.
+ */
+void CEmailServerMonitor::SetShutter( CEmailShutter* aShutter )
+ {
+ iShutter = aShutter;
+ }
+
+/**
+ * Set Restart External Services flag.
+ */
+void CEmailServerMonitor::SetRestartExternalServicesFlag( TBool aRestartFlag /*= ETrue*/ )
+ {
+ if( aRestartFlag )
+ {
+ iExternalServicesRestartState = EEsmEsrStateRestartNeeded;
+ }
+ else
+ {
+ iExternalServicesRestartState = EEsmEsrStateRestartNotNeeded;
+ }
+ }
+
+/**
+ * Called when external service restart timer has expired, so it's time to do
+ * some starting
+ */
+void CEmailServerMonitor::TimerEventL( CEmailServerMonitorTimer* /*aTriggeredTimer*/ )
+ {
+ // Shutter is used in all cases, so verify it exists at the beginning
+ if( iShutter )
+ {
+ switch( iExternalServicesRestartState )
+ {
+ case EEsmEsrStateRestartInitiated:
+ {
+ // Restart external services and change state
+ iShutter->RestartServicesAfterInstallation();
+ iExternalServicesRestartState = EEsmEsrStateFirstServiceRestarted;
+
+ // Restart the timer to set the installation finished flag
+ // with some more delay
+ iExternalServiceRestartTimer->Start( KInstallatioFinishedFlagSettingDelay );
+ }
+ break;
+
+ case EEsmEsrStateFirstServiceRestarted:
+ {
+ // Set the installation finished flag and clear state variable
+ iShutter->SetPsKeyInstallationFinished();
+ iExternalServicesRestartState = EEsmEsrStateRestartNotNeeded;
+ }
+ break;
+
+ default:
+ // Do nothing, shouldn't happen
+ break;
+ }
+ }
+ }
+
+/**
+ * Start Email Server and start monitoring it
+ */
+TBool CEmailServerMonitor::StartEmailServerMonitoring()
+ {
+ FUNC_LOG;
+ // Give iProcess as parameter for IsProcessRunning so that it will
+ // be updated in case that the Email Server process is running.
+ TBool running = IsProcessRunning( KEmailServerUid, &iProcess );
+
+ // Start Email Server if it's not yet running
+ if( !running )
+ {
+ iRestarts++;
+
+ TThreadId threadId;
+ TRequestStatus reqStatusForRendezvous;
+ TRAPD( error, StartApplicationL( KEmailServerExe(), threadId, reqStatusForRendezvous ) );
+
+ // If application was started succesfully
+ if( error == KErrNone )
+ {
+ User::WaitForRequest( reqStatusForRendezvous );
+
+ // If process started succesfully, we are ready for observing
+ if( reqStatusForRendezvous.Int() == KErrNone )
+ {
+ // Close previous process handle
+ iProcess.Close();
+
+ // Get handle to newly created process using the threadId
+ RThread thread;
+ TInt error = thread.Open( threadId );
+ if( error == KErrNone )
+ {
+ error = thread.Process( iProcess );
+ thread.Close();
+ // Indicate success only if iProcess update succeeded, as it's
+ // assumed to be up-to-date if Email Server process is running
+ if( error == KErrNone )
+ {
+ running = ETrue;
+ }
+ }
+ }
+ }
+ }
+
+ if( running )
+ {
+ DoStartMonitoring();
+ }
+ else
+ {
+ INFO( "Restart failed!" );
+ }
+
+ return running;
+ }
+
+/**
+ * Starts the actual monitoring. Assumes that Email Server is running
+ * and Monitor's internal variables are set accordingly.
+ */
+void CEmailServerMonitor::DoStartMonitoring()
+ {
+ FUNC_LOG;
+ SetActive();
+ iProcess.Logon( iStatus );
+ iState = EEsmStateMonitoring;
+ }
+
+/**
+ * Start specified application, leaves if failed to start the application
+ */
+void CEmailServerMonitor::StartApplicationL(
+ const TDesC& aAppName,
+ TThreadId& aThreadId,
+ TRequestStatus& aReqStatusForRendezvous )
+ {
+ CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
+ cmdLine->SetExecutableNameL( aAppName );
+ // Launch Email Server in background so that it doesn't steal
+ // the focus during it's construction
+ cmdLine->SetCommandL( EApaCommandBackground );
+
+ User::LeaveIfError( iApaLsSession.StartApp( *cmdLine, aThreadId, &aReqStatusForRendezvous ) );
+
+ CleanupStack::PopAndDestroy( cmdLine );
+ }
+
+/**
+ * DoCancel of active object
+ */
+void CEmailServerMonitor::DoCancel()
+ {
+ FUNC_LOG;
+ iState = EEsmStateIdle;
+ iProcess.LogonCancel( iStatus );
+ iDelayTimer.Cancel();
+ if( iExternalServiceRestartTimer )
+ {
+ iExternalServiceRestartTimer->Cancel();
+ }
+ }
+
+/**
+ * RunL of active object
+ */
+void CEmailServerMonitor::RunL()
+ {
+ FUNC_LOG;
+
+ INFO_1( "iStatus: %d", iStatus.Int() );
+ INFO_1( "iState: %d", iState );
+
+ switch( iState )
+ {
+ case EEsmStateMonitoring:
+ {
+ // Write the process exit information to the debug log.
+ INFO_1( "ExitType: %d", iProcess.ExitType() );
+ INFO_1( "ExitReason: %d", iProcess.ExitReason() );
+ HandleMonitorEvent();
+ }
+ break;
+
+ case EEsmStateInitializing:
+ case EEsmStateRestarting:
+ {
+ // Restart Email server and start monitoring it again
+ if( !StartEmailServerMonitoring() )
+ {
+ // If start failed initiate new delayed restart
+ INFO( "Initiating new delayed restart" );
+ InitiateDelayedRestart();
+ }
+ // If Email server is up and running and iExternalServicesRestartState
+ // flag is set, initiate delayed restart of external services
+ else if( iExternalServicesRestartState == EEsmEsrStateRestartNeeded )
+ {
+ // Once restart is initiated, update the state
+ iExternalServicesRestartState = EEsmEsrStateRestartInitiated;
+
+ // Create the timer and start it
+ TInt timerError = KErrNone;
+ if( !iExternalServiceRestartTimer )
+ {
+ TRAP( timerError, iExternalServiceRestartTimer = CEmailServerMonitorTimer::NewL( this ) );
+ }
+ if( timerError == KErrNone )
+ {
+ iExternalServiceRestartTimer->Start( KExternalServiceRestartDelay );
+ }
+ }
+ }
+ break;
+
+ case EEsmStateIdle:
+ default:
+ {
+ // Shouldn't happen
+ INFO( "Unknown state or not observing!" );
+ }
+ }
+ }
+
+/**
+ * Handle email server monitoring event
+ */
+void CEmailServerMonitor::HandleMonitorEvent()
+ {
+ FUNC_LOG;
+ TExitType exitType = iProcess.ExitType();
+ if ( exitType == EExitPanic )
+ {
+ INFO( "Initiating delayed restart of Email Server" );
+ InitiateDelayedRestart();
+ }
+ else if ( exitType == EExitPending )
+ {
+ INFO( "Process is still alive, restarting monitoring" );
+ DoStartMonitoring();
+ }
+ else
+ {
+ INFO( "Email Server terminated, not restarting!" );
+ iState = EEsmStateIdle;
+ }
+ }
+
+/**
+ * Initiate an asynchronous delayed restart
+ */
+void CEmailServerMonitor::InitiateDelayedRestart()
+ {
+ FUNC_LOG;
+ TTime now;
+ now.UniversalTime();
+
+ // Calculate minutes from last restart
+ TTimeIntervalMinutes minutesSinceLastRestart = 0;
+ now.MinutesFrom( iLastRestartTime, minutesSinceLastRestart );
+ INFO_1( "Minutes since last restart=%d", minutesSinceLastRestart.Int() );
+
+ iLastRestartTime = now;
+
+ // If the process has been running successfully long enough then reset
+ // the restart counter.
+ if( minutesSinceLastRestart >= TTimeIntervalMinutes( KEsmUptimeToResetRestartCounter ) )
+ {
+ INFO( "Long enough uptime, reset restart counter" );
+ iRestarts = 0;
+ }
+
+ // Initiate new delayed restart, if restart limit is not exceeded
+ if( iRestarts < KEsmMaxRestarts )
+ {
+ iDelayTimer.After( iStatus, KEsmRestartDelayInSeconds * KOneSecondInMicroSeconds );
+ SetActive();
+ iState = EEsmStateRestarting;
+ }
+ else
+ {
+ INFO( "Maximum restarts exceeded!" );
+ iState = EEsmStateIdle;
+ }
+ }