emailservices/emailservermonitor/src/emailservermonitor.cpp
branchRCL_3
changeset 64 3533d4323edc
--- /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;
+        }
+    }