/*
* 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;
}
}