devicediagnosticsfw/diagframework/src/diagengineimpl.cpp
branchRCL_3
changeset 26 19bba8228ff0
parent 0 b497e44ab2fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/devicediagnosticsfw/diagframework/src/diagengineimpl.cpp	Wed Sep 01 12:27:42 2010 +0100
@@ -0,0 +1,1551 @@
+/*
+* Copyright (c) 2007 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:  Class definition of CDiagEngineImpl
+*
+*/
+
+
+// CLASS DECLARATION
+#include "diagengineimpl.h"                 // CDiagEngineImpl
+
+// SYSTEM INCLUDE FILES
+#include <DiagPluginPool.h>                 // CDiagPluginPool
+#include <DiagFrameworkDebug.h>             // LOGSTRING
+#include <DiagPlugin.h>                     // MDiagPlugin
+#include <DiagTestExecParam.h>              // TDiagTestExecParam
+#include <DiagSuiteExecParam.h>             // TDiagSuiteExecParam
+#include <DiagResultsDbItemBuilder.h>       // CDiagResultsDbItemBuilder
+#include <DiagResultsDbRecordEngineParam.h> // CDiagResultsDbRecordEngineParam
+
+// USER INCLUDE FILES
+#include "diagpluginexecplanimpl.h"         // CDiagPluginExecPlanImpl
+#include "diagexecplanentryimpltest.h"      // CDiagExecPlanEntryImplTest
+#include "diagenginestatemachine.h"         // DiagFwInternal::CStateMachine
+#include "diagenginecallhandler.h"          // CDiagEngineCallHandler
+#include "diagframework.pan"                // Panic Codes
+#include "diagengineconfig.h"               // TDiagEngineConfig
+
+// EVENT INCLUDE FILES
+#include "diagengineeventbasic.h"           // DiagFwInternal::CEventBasic
+#include "diagengineeventtestprogress.h"    // DiagFwInternal::CEventTestProgress
+
+using namespace DiagFwInternal;
+
+// DATA
+
+// ======== LOCAL FUNCTIONS ========
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::NewL()
+// ---------------------------------------------------------------------------
+//
+CDiagEngineImpl* CDiagEngineImpl::NewL( 
+        CAknViewAppUi&          aViewAppUi, 
+        MDiagEngineObserver&    aObserver,
+        RDiagResultsDatabase&   aDbSession,
+        CDiagPluginPool&        aPluginPool,
+        TBool                   aDisableDependency,
+        const RArray< TUid >&   aExecutionBatch )
+    {
+    CDiagEngineImpl* self = CDiagEngineImpl::NewLC( aViewAppUi,
+                                                    aObserver,
+                                                    aDbSession,
+                                                    aPluginPool,
+                                                    aDisableDependency,
+                                                    aExecutionBatch );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::NewLC()
+// ---------------------------------------------------------------------------
+//
+CDiagEngineImpl* CDiagEngineImpl::NewLC( 
+        CAknViewAppUi&          aViewAppUi, 
+        MDiagEngineObserver&    aObserver,
+        RDiagResultsDatabase&   aDbSession,
+        CDiagPluginPool&        aPluginPool,
+        TBool                   aDisableDependency,
+        const RArray< TUid >&   aExecutionBatch )
+    {
+    CDiagEngineImpl* self = new ( ELeave ) CDiagEngineImpl( aViewAppUi,
+                                                            aObserver,
+                                                            aDbSession,
+                                                            aPluginPool );
+
+    CleanupStack::PushL( self );
+    self->ConstructNewRecordL( aDisableDependency, aExecutionBatch );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::NewL()
+// ---------------------------------------------------------------------------
+//
+CDiagEngineImpl* CDiagEngineImpl::NewL( CAknViewAppUi&          aViewAppUi, 
+                                        MDiagEngineObserver&    aObserver,
+                                        RDiagResultsDatabase&   aDbSession,
+                                        CDiagPluginPool&        aPluginPool,
+                                        TUid                    aIncompleteRecordUid )
+    {
+    CDiagEngineImpl* self = CDiagEngineImpl::NewLC( aViewAppUi,
+                                                    aObserver,
+                                                    aDbSession,
+                                                    aPluginPool,
+                                                    aIncompleteRecordUid );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::NewLC()
+// ---------------------------------------------------------------------------
+//
+CDiagEngineImpl* CDiagEngineImpl::NewLC( CAknViewAppUi&    aViewAppUi, 
+                                   MDiagEngineObserver&    aObserver,
+                                   RDiagResultsDatabase&   aDbSession,
+                                   CDiagPluginPool&        aPluginPool,
+                                   TUid                    aIncompleteRecordUid )
+    {
+    CDiagEngineImpl* self = new ( ELeave ) CDiagEngineImpl( aViewAppUi,
+                                                            aObserver,
+                                                            aDbSession,
+                                                            aPluginPool );
+
+    CleanupStack::PushL( self );
+    self->ConstructIncompleteRecordL( aIncompleteRecordUid );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::CDiagEngineImpl
+// ---------------------------------------------------------------------------
+//
+CDiagEngineImpl::CDiagEngineImpl( CAknViewAppUi&          aViewAppUi,
+                                  MDiagEngineObserver&    aObserver,
+                                  RDiagResultsDatabase&   aDbSession,
+                                  CDiagPluginPool&        aPluginPool )
+    :   CActive( EPriorityStandard ),
+        iViewAppUi( aViewAppUi ),
+        iObserver( aObserver ),
+        iDbSession( aDbSession ),
+        iPluginPool( aPluginPool )
+    {
+    LOGSTRING( "---- DIAG ENGINE BEGIN ---- DIAG ENGINE BEGIN ----{" )
+    CActiveScheduler::Add( this );
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::ConstructNewRecordL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ConstructNewRecordL( TBool aDisableDependency,
+                                           const RArray< TUid >& aExecutionBatch )
+    {
+    ConstructCommonL();
+
+    LOGSTRING( "CDiagEngineImpl::ConstructNewRecordL()" )
+
+    iContinueIncompleteRecord = EFalse;
+    iEngineConfig.SetDependencyDisabled( aDisableDependency );
+
+    // convert uid array to plugin reference array.
+    // Also, make a copy of the plug-in UID array so that it can be
+    // passed to database.
+    TInt batchCount = aExecutionBatch.Count();
+
+    // uidList must be allocated in heap since it database will own the data later.
+    RArray< TUid >* uidList = new( ELeave )RArray< TUid >();
+    CleanupStack::PushL( uidList );     // to delete array itself.
+    CleanupClosePushL( *uidList );      // to call close.
+
+    uidList->ReserveL( batchCount );
+    
+    MDiagPlugin* plugin = NULL;
+
+    for ( TInt i = 0; i < batchCount ; i++ )
+        {
+        LOGSTRING2( "CDiagEngineImpl::ConstructNewRecordL() "
+            L"Add plugin 0x%08x", aExecutionBatch[i].iUid )
+            
+        iPluginPool.FindPlugin( aExecutionBatch[i], plugin );
+        iBatch.AppendL( plugin );
+        plugin = NULL;
+
+        uidList->AppendL( aExecutionBatch[i] );
+        }
+
+    CDiagResultsDbRecordEngineParam* engineParam = 
+        CDiagResultsDbRecordEngineParam::NewL(
+            uidList,                                // ownership transfer
+            !iEngineConfig.IsDependencyDisabled()   /* isDependencyExecution */ );
+
+    CleanupStack::Pop( uidList );   // CleanupClosePushL( *uidList )
+    CleanupStack::Pop( uidList );   // CleanupStack::PushL( uidList )
+    uidList = NULL;
+
+    CleanupStack::PushL( engineParam );
+    User::LeaveIfError( 
+        iDbRecord.CreateNewRecord( iDbSession, iRecordId, *engineParam ) );
+    CleanupStack::PopAndDestroy( engineParam );
+    engineParam = NULL;
+
+    iPlan = CDiagPluginExecPlanImpl::NewL( *this, iEngineConfig, *this );
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::ConstructIncompleteRecordL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ConstructIncompleteRecordL( TUid aIncompleteRecordUid )
+    {
+    ConstructCommonL();
+
+    LOGSTRING2( "CDiagEngineImpl::ConstructIncompleteRecordL() "
+        L"RecordId = 0x%08x", aIncompleteRecordUid.iUid )
+        
+    iRecordId = aIncompleteRecordUid;
+    iContinueIncompleteRecord = ETrue;
+
+    User::LeaveIfError( 
+        iDbRecord.Connect( iDbSession, 
+                           iRecordId,
+                           EFalse   /* aReadOnly */ ) );
+
+    // make sure that record is open for writing.
+    TBool isTestCompleted = EFalse;
+    User::LeaveIfError( iDbRecord.IsTestCompleted( isTestCompleted ) );
+    if ( isTestCompleted )
+        {
+        User::Leave( KErrLocked );
+        }
+
+    // recover original parameter
+    CDiagResultsDbRecordEngineParam* engineParam = NULL;
+    User::LeaveIfError(
+        iDbRecord.GetEngineParam( engineParam ) );
+
+    CleanupStack::PushL( engineParam );
+
+    // Recover original batch.
+    MDiagPlugin* plugin = NULL;
+    iEngineConfig.SetDependencyDisabled( !engineParam->DependencyExecution() );
+    const RArray< TUid >& uidArray = engineParam->ExecutionsUidArray();
+    TInt count = uidArray.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        LOGSTRING2( "CDiagEngineImpl::ConstructNewRecordL() "
+            L"Add plugin 0x%08x", uidArray[i].iUid )
+            
+        User::LeaveIfError( 
+            iPluginPool.FindPlugin( uidArray[i], plugin ) );
+        iBatch.AppendL( plugin );
+        plugin = NULL;
+        }
+    
+    CleanupStack::PopAndDestroy( engineParam );
+    engineParam = NULL;
+
+    iPlan = CDiagPluginExecPlanImpl::NewL( *this, iEngineConfig, *this );
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::ConstructCommonL()
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ConstructCommonL()
+    {
+    LOGSTRING( "CDiagEngineImpl::ConstructCommonL." )
+
+    // Read Cenrep key
+    iEngineConfig.ReadCenrepKeysL();
+
+    // Create state machine.
+    iStateMachine = CStateMachine::NewL( *this );
+
+    // Create call handler.
+    iCallHandler = CDiagEngineCallHandler::NewL( *this );
+
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::~CDiagEngineImpl
+// ---------------------------------------------------------------------------
+//
+CDiagEngineImpl::~CDiagEngineImpl()
+    {
+    LOGSTRING( "CDiagEngineImpl::~CDiagEngineImpl() Destructor" )
+
+    StopAllRequests();
+
+    CleanupIncompleteTestSession();
+
+    // always delete plan before record is closed.
+    delete iPlan;
+    iPlan = NULL;
+
+    iDbRecord.Close();
+
+    iBatch.Close(); // MUST NOT destroy since we don't own elements within it
+
+    delete iStateMachine;
+    iStateMachine = NULL;
+
+    delete iSuspendedResult;
+    iSuspendedResult = NULL;
+
+    delete iCallHandler;
+    iCallHandler = NULL;
+
+    LOGSTRING( "} ---- DIAG ENGINE END ---- DIAG ENGINE END ----" )
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::CleanupIncompleteTestSession
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::CleanupIncompleteTestSession()
+    {
+    if ( iStateMachine == NULL || 
+            iStateMachine->CurrentState() == EStateNotReady ||
+            iStateMachine->CurrentState() == EStateStopped )
+        {
+        // Test is never started or already finished. Nothing to clean up here.
+        return;
+        }
+
+    // At this point, we can either suspend or complete the test record.
+    // Normally, since state machine is not in EStateStopped state,
+    // record should suspended.
+    //
+    // However, even if it is not completely done executing the plan, 
+    // if last test is already completed, engine will report TestCompleted( ETrue ).
+    // Otherwise, when examining db record for resuming, the record will appear
+    // incomplete, but in reality there is no more test to execute and resuming the
+    // record will immediately finish the session, which is meaningless.
+    // Hence, when last test plug-in is executed, engine will record test completed,
+    // instead of suspend, even if there are suite items left in plan.
+
+    LOGSTRING2( "CDiagEngineImpl::CleanupIncompleteTestSession() State = %d", 
+        iStateMachine->CurrentState() )
+
+    switch( iStateMachine->CurrentState() )
+        {
+        case EStateStopped:
+            // all completed. Nothing to finalize.
+            break;
+
+        case EStateNotReady:        // fall through
+        case EStateCreatingPlan:
+            // Plan was not fully created.
+            // Mark the record as incomplete and let execution plan
+            // to figure out how to resume later.
+            // No need to call NotifyPluginsOfTestSessionEnd() since 
+            // TestSessionBeginL() was never called. 
+            iDbRecord.Suspend();    // in destructor. Error ignored.
+            break;
+        
+        case EStateCancelAll:
+            {
+            // Test session was being cancelled. Since we were in cancel all mode,
+            // it cannot be resumed. Mark the record completed.
+            NotifyPluginsOfTestSessionEnd();
+
+            TInt err =  iDbRecord.TestCompleted( EFalse /* aFullyComplete */ );
+            LOGSTRING2( "CDiagEngineImpl::CleanupIncompleteTestSession() "
+                L" TestCompleted( EFalse ) err = %d", err )
+            // in destructor. Error ignored.
+            }
+            break;
+
+        case EStateFinalizing:
+            {
+            // Engine was about to finalize, but never got a chance to.
+            // In this state, db record should always be closed with TestCompleted
+            // since it is a normal execution finish scenario and it cannot
+            // be resumed later.
+            NotifyPluginsOfTestSessionEnd();
+
+            TBool isFullyCompleted = ( iEngineError == KErrNone );
+            TInt err = iDbRecord.TestCompleted( isFullyCompleted );
+            LOGSTRING3( "CDiagEngineImpl::CleanupIncompleteTestSession() "
+                L"iDbRecord.TestCompleted( %d ) err = %d", isFullyCompleted, err )
+            
+            // We are in destructor. Ignore errors from db.
+            }
+            break;
+
+        default:
+            // In other states, engine was still executing some items.
+            // Check if it shoud be marked as suspended or not.
+            {
+            TBool allTestsCompleted = EFalse;
+            for ( TInt i = iPlan->CurrentIndex(); i < iPlan->Count(); i++ )
+                {
+                if ( (*iPlan)[i].Plugin().Type() == MDiagPlugin::ETypeTestPlugin &&
+                     (*iPlan)[i].State() != MDiagExecPlanEntry::EStateCompleted )
+                    {
+                    // Found a test entry that is not completed.
+                    allTestsCompleted = EFalse;
+                    break; //lint !e960  break OK here.
+                    }
+                }
+
+            NotifyPluginsOfTestSessionEnd();
+
+            if ( allTestsCompleted )
+                {
+                TInt err =  iDbRecord.TestCompleted( ETrue /* aFullyComplete */ );
+                LOGSTRING2( "CDiagEngineImpl::CleanupIncompleteTestSession() "
+                    L" iDbRecord.TestCompleted( ETrue ) err = %d", err )
+                }
+            else
+                {
+                TInt err = iDbRecord.Suspend();
+                LOGSTRING2( "CDiagEngineImpl::CleanupIncompleteTestSession(). "
+                    L"iDbRecord.Suspend() err = %d", err )
+                }
+            
+            }
+            break;
+
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::ExecuteL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ExecuteL()
+    {
+    __ASSERT_ALWAYS( iStateMachine->CurrentState() == EStateNotReady,
+                     Panic( EDiagFrameworkInvalidState ) );
+
+    iStateMachine->AddEventL( EEventExecute );
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::SetCustomParam
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::SetCustomParam( TAny* aCustomParams )
+    {
+    __ASSERT_ALWAYS( aCustomParams, Panic( EDiagFrameworkBadArgument ) );
+
+    // Custom parameter can be set only when engine is not running.
+    __ASSERT_ALWAYS( iStateMachine->CurrentState() == EStateNotReady, 
+                     Panic( EDiagFrameworkInvalidState ) );
+
+    iCustomParam = aCustomParams;
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::SuspendL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::SuspendL()
+    {
+    DiagFwInternal::TState state = iStateMachine->CurrentState();
+
+    // Suspendable states:
+    __ASSERT_ALWAYS( ( state == EStateRunning ||
+                       state == EStateCreatingPlan ||
+                       state == EStateFinalizing ||
+                       state == EStateStopped ),
+                     Panic( EDiagFrameworkInvalidState ) );
+
+    if ( state == EStateFinalizing || state == EStateStopped )
+        {
+        // ignore suspend request. All tests are already completed and
+        // we are just waiting to finalize db record and report final
+        // result.
+        return;
+        }
+
+    StopAllRequests();
+
+    LOGSTRING( "CDiagEngineImpl::SuspendL(). Adding suspend event" )
+    iStateMachine->AddEventL( EEventSuspend );
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::ResumeL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ResumeL()
+    {
+    __ASSERT_ALWAYS( iStateMachine->CurrentState() == EStateSuspended,
+                     Panic( EDiagFrameworkInvalidState ) );
+
+    LOGSTRING( "CDiagEngineImpl::SuspendL(). Adding resume event" )
+    AddResumeEventL( MDiagEngineObserver::EResumedByClient );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::ExecutionPlanL
+// ---------------------------------------------------------------------------
+//
+const MDiagPluginExecPlan& CDiagEngineImpl::ExecutionPlanL() const
+    {
+    return *iPlan;
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::ExecutionStopL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ExecutionStopL( TCancelMode aCancelMode )
+    {
+    DiagFwInternal::TState state = iStateMachine->CurrentState();
+
+    // Acceptable states for execution stop.
+    __ASSERT_ALWAYS( state == EStateCreatingPlan ||
+                     state == EStateRunning ||
+                     state == EStateSuspended ||
+                     state == EStateFinalizing ||
+                     state == EStateStopped,
+                     Panic( EDiagFrameworkInvalidState ) );
+
+    if ( state == EStateFinalizing || state == EStateStopped )
+        {
+        // ignore cancel request. All tests are already completed and
+        // we are just waiting to finalize db record and report final
+        // result.
+        return;
+        }
+
+    StopAllRequests();
+    
+    if ( aCancelMode == ESkip )
+        {
+        iStateMachine->AddEventL( EEventSkip );
+        }
+    else
+        {
+        iStateMachine->AddEventL( EEventCancelAll );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::ResetWatchdog
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ResetWatchdog()
+    {
+    iPlan->CurrentExecutionItem().ResetWatchdog();
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::ResetWatchdog
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ResetWatchdog( TDiagEngineWatchdogTypes aWatchdogType )
+    {
+    iPlan->CurrentExecutionItem().ResetWatchdog( aWatchdogType );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::ResetWatchdog
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ResetWatchdog( TTimeIntervalMicroSeconds32 aExpectedTimeToComplete )
+    {
+    iPlan->CurrentExecutionItem().ResetWatchdog( aExpectedTimeToComplete );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::ViewAppUi
+// ---------------------------------------------------------------------------
+//
+CAknViewAppUi& CDiagEngineImpl::ViewAppUi()
+    {
+    return iViewAppUi;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::ViewAppUi
+// ---------------------------------------------------------------------------
+//
+const CAknViewAppUi& CDiagEngineImpl::ViewAppUi() const
+    {
+    return iViewAppUi;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::DbRecord
+// ---------------------------------------------------------------------------
+//
+RDiagResultsDatabaseRecord& CDiagEngineImpl::DbRecord()
+    {
+    return iDbRecord;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::DbRecord
+// ---------------------------------------------------------------------------
+//
+const RDiagResultsDatabaseRecord& CDiagEngineImpl::DbRecord() const
+    {
+    return iDbRecord;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::PluginPool
+// ---------------------------------------------------------------------------
+//
+CDiagPluginPool& CDiagEngineImpl::PluginPool()
+    {
+    return iPluginPool;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::PluginPool
+// ---------------------------------------------------------------------------
+//
+const CDiagPluginPool& CDiagEngineImpl::PluginPool() const
+    {
+    return iPluginPool;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::AddToConfigListL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::AddToConfigListL(
+        MDiagEngineCommon::TConfigListType aListType, 
+        const TDesC& aText )
+    {
+    switch ( aListType )
+        {
+        case MDiagEngineCommon::EConfigListCallIngore:
+            iCallHandler->AddIgnoreNumberL( aText );
+            break;
+
+        default:
+            LOGSTRING2( "CDiagEngineImpl::AddToConfigListL(). Invalid ListType %d",
+                aListType )
+            Panic( EDiagFrameworkBadArgument );
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::RemoveFromConfigListL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::RemoveFromConfigListL(
+        MDiagEngineCommon::TConfigListType aListType,
+        const TDesC& aText )
+    {
+    switch ( aListType )
+        {
+        case MDiagEngineCommon::EConfigListCallIngore:
+            iCallHandler->RemoveIgnoreNumberL( aText );
+            break;
+
+        default:
+            LOGSTRING2( "CDiagEngineImpl::RemoveFromConfigListL(). Invalid ListType %d",
+                aListType )
+            Panic( EDiagFrameworkBadArgument );
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::CreateCommonDialogLC
+// ---------------------------------------------------------------------------
+//
+CAknDialog* CDiagEngineImpl::CreateCommonDialogLC( TDiagCommonDialog aDialogType,
+                                                   TAny* aInitData )
+    {
+    return iObserver.CreateCommonDialogLC( aDialogType, aInitData );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::ExecuteAppCommandL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ExecuteAppCommandL( TDiagAppCommand aCommand, 
+                                          TAny* aParam1,
+                                          TAny* aParam2 )
+    {
+    iObserver.ExecuteAppCommandL( aCommand, aParam1, aParam2 );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::StopWatchdogTemporarily
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::StopWatchdogTemporarily()
+    {
+    if ( iStateMachine == NULL || iPlan == NULL )
+        {
+        return;
+        }
+
+    if ( iStateMachine->CurrentState() == EStateRunning )
+        {
+        iPlan->CurrentExecutionItem().StopWatchdogTemporarily();
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::IsDependencyDisabled
+// ---------------------------------------------------------------------------
+//
+TBool CDiagEngineImpl::IsDependencyDisabled() const
+    {
+    return iEngineConfig.IsDependencyDisabled();
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCommon
+// CDiagEngineImpl::CustomParam
+// ---------------------------------------------------------------------------
+//
+TAny* CDiagEngineImpl::CustomParam() const
+    {
+    return iCustomParam;
+    }   //lint !e1763 Custom param is just passed along. Does not actually change engine.
+
+// ---------------------------------------------------------------------------
+// From class MDiagExecPlanEntryImplObserver
+// CDiagEngineImpl::ExecPlanEntryProgressL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ExecPlanEntryProgressL( 
+        CDiagExecPlanEntryImpl& aSender,
+        TUint aCurrentStep, 
+        TUint aTotalSteps )
+    {
+    LOGSTRING4( "CDiagEngineImpl::ExecPlanEntryProgressL: Plugin = 0x%08x, (%d / %d) ",
+        aSender.Plugin().Uid().iUid,
+        aCurrentStep, 
+        aTotalSteps )
+
+    if ( aSender.Plugin().Uid() == iPlan->CurrentExecutionItem().Plugin().Uid() )
+        {
+        CEventTestProgress* event = new ( ELeave ) CEventTestProgress(
+                aSender.Plugin(), aCurrentStep, aTotalSteps );
+
+        iStateMachine->AddEventL( event ); // ownership changed.
+        }
+    else
+        {
+        // probably timing issue. Ignore event.
+        __ASSERT_DEBUG( 0, Panic( EDiagFrameworkInternal ) );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagExecPlanEntryImplObserver
+// CDiagEngineImpl::ExecPlanEntryExecutedL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ExecPlanEntryExecutedL( CDiagExecPlanEntryImpl& aSender )
+    {
+    LOGSTRING2( "CDiagEngineImpl::ExecPlanEntryExecutedL: Plugin = 0x%08x",
+        aSender.Plugin().Uid().iUid )
+
+    if ( aSender.Plugin().Uid() != iPlan->CurrentExecutionItem().Plugin().Uid() )
+        {
+        // probably timing issue. Ignore event.
+        __ASSERT_DEBUG( 0, Panic( EDiagFrameworkInternal ) );
+        }
+    else
+        {
+        TInt error = KErrNone;
+        if ( aSender.IsStoppedByClient() )
+            {
+            error = KErrCancel;
+            }
+
+        CDiagResultsDatabaseItem* result = NULL;
+
+        if ( aSender.Plugin().Type() == MDiagPlugin::ETypeTestPlugin )
+            {
+            // Test was completed. Get test result.
+            CDiagExecPlanEntryImplTest& testEntry = 
+                static_cast< CDiagExecPlanEntryImplTest& >( aSender );
+
+            result = testEntry.GetLastTestResultL();
+
+            __ASSERT_ALWAYS( result != NULL, Panic( EDiagFrameworkNullTestResult ) );
+            }
+
+        NotifyResultAndContinueL( error, result );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagExecPlanEntryImplObserver
+// CDiagEngineImpl::ExecPlanEntryCriticalError
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ExecPlanEntryCriticalError( TInt aError )
+    {
+    LOGSTRING2( "CDiagEngineImpl::ExecPlanEntryCriticalError: "
+        L"Critical failure %d", aError )
+
+    // Unrecoverable error has occered. e.g. out of memory, disk full etc.
+    iStateMachine->HandleError( aError );
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineStateMachineObserver
+// CDiagEngineImpl::HandleStateChangedL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleStateChangedL( 
+        TState aPreviousState, 
+        TState aCurrentState,
+        const CEventBasic& aEventPreview )
+    {
+    // NOTE: This method is called by state machine as soon as an event that
+    // changes states is called. This means that it could execute within caller's
+    // call stack. (e.g. it could be still within application or plug-in's 
+    // call stack.) It is best to limit amount of implementation here to
+    // things that must be done as soon as an event occurs.
+    // 
+    // Suspend and Resume are exceptions since they require immediate notification
+    // to observer. Otherwise, observer might have mismatch in notifications.
+
+    LOGSTRING3( "CDiagEngineImpl::HandleStateChangedL(): "
+            L"Entering State : %d( %S )",
+            aCurrentState, &iStateMachine->StateName( aCurrentState ) )
+
+    switch ( aCurrentState )
+        {
+        case EStateSuspended:
+            // keep track of state befor suspended, so that we can resume
+            // to correct state.
+            iSuspendedPrevState = aPreviousState;
+
+            MDiagEngineObserver::TSuspendReason reason;
+            if ( aEventPreview.GetType() == EEventSuspend )
+                {
+                reason = MDiagEngineObserver::ESuspendByClient;
+                }
+            else
+                {
+                reason = MDiagEngineObserver::ESuspendByPhoneCall;
+                }
+
+            // This will also notify iObserver.
+            DoSuspendL( reason );
+            break;
+
+        case EStateRunning: 
+            if ( aEventPreview.GetType() == EEventResumeToRunning )
+                {
+                LOGSTRING( "CDiagEngineImpl::HandleStateChangedL(). Notify resume" )
+                iObserver.TestExecutionResumedL( iResumeReason );
+                }
+            break;
+
+        case EStateCreatingPlan:
+            if ( aEventPreview.GetType() == EEventResumeToCreatingPlan )
+                {
+                LOGSTRING( "CDiagEngineImpl::HandleStateChangedL(). Notify resume" )
+                iObserver.TestExecutionResumedL( iResumeReason );
+                }
+            break;
+        
+        default:
+            // Do nothing.
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineStateMachineObserver
+// CDiagEngineImpl::HandleEventL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleEventL( CEventBasic& aEvent )
+    {
+    LOGSTRING5( "CDiagEngineImpl::HandleEventL(): State=%d(%S), Event=%d(%S)",
+        iStateMachine->CurrentState(), 
+        &iStateMachine->StateName( iStateMachine->CurrentState() ),
+        aEvent.GetType(), &aEvent.ToString() )
+            
+    switch ( iStateMachine->CurrentState() )
+        {
+        case EStateNotReady:
+            LOGSTRING( "CDiagEngineImpl::HandleEventL: "
+                L"ERROR! Cannot accept events in EStateNotReady State" )
+            __ASSERT_DEBUG( 0, Panic( EDiagFrameworkCorruptStateMachine ) );
+            break;
+
+        case EStateCreatingPlan:
+            HandleEventInCreatingPlanStateL( aEvent );
+            break;
+
+        case EStateRunning:
+            HandleEventInRunningStateL( aEvent );
+            break;
+
+        case EStateCancelAll:
+            HandleEventInCancelAllStateL( aEvent );
+            break;
+
+        case EStateSuspended:
+            HandleEventInSuspendedStateL( aEvent );
+            break;
+
+        case EStateFinalizing:
+            HandleEventInFinalizingStateL( aEvent );
+            break;
+
+        case EStateStopped:
+            HandleEventInStoppedStateL( aEvent );
+            break;
+
+        case EStateAny:     // fall through
+        default:
+            __ASSERT_DEBUG( 0, Panic( EDiagFrameworkCorruptStateMachine ) );
+            break;
+        }
+    LOGSTRING( "CDiagEngineImpl::HandleEventL(): return" )
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleEventInCreatingPlanStateL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleEventInCreatingPlanStateL( CEventBasic& aEvent )
+    {
+    switch ( aEvent.GetType() )
+        {
+        case EEventExecute:                 // fall through
+        case EEventResumeToCreatingPlan:
+            StartCreateExecutionPlanL();
+            break;
+        
+        default:
+            LOGSTRING2( "CDiagEngineImpl::HandleEventInCreatingPlanStateL: "
+                        L"Invalid event = %d", aEvent.GetType() )
+            // Ignored.
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleEventInRunningStateL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleEventInRunningStateL( CEventBasic& aEvent )
+    {
+    switch ( aEvent.GetType() )
+        {
+        case EEventPlanCreated:         
+            // Normal case. Plan is created normally.
+            HandlePlanCreatedL();
+            break;
+        
+        case EEventExecuteNext:
+            ExecuteNextPluginL();
+            break;
+
+        case EEventSkip:
+            HandleSkipL();
+            break;
+
+        case EEventTestProgress:
+            NotifyTestProgressL( static_cast<CEventTestProgress&>( aEvent ) );
+            break;
+
+        case EEventResumeToRunning:
+            DoResumeL();
+            break;
+
+        default:
+            LOGSTRING2( "CDiagEngineImpl::HandleEventInRunningStateL "
+                        L"Invalid event = %d", aEvent.GetType() )
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleEventInCancelAllStateL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleEventInCancelAllStateL( CEventBasic& aEvent )
+    {
+    switch ( aEvent.GetType() )
+        {
+        case EEventCancelAll:
+        case EEventExecuteNext:
+            HandleCancelAllL();
+            break;
+
+        case EEventSuspend:                 // fall through
+        case EEventVoiceCallActive:
+            // suspend is always handed in its own state
+            __ASSERT_DEBUG( 0, Panic( EDiagFrameworkCorruptStateMachine ) );
+            break;
+
+        default:
+            // other events are ingored( e.g. progress ), since
+            // cancel has been requested
+            LOGSTRING2( "CDiagEngineImpl::HandleEventInCancelAllStateL "
+                        L"Invalid event = %d", aEvent.GetType() )
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleEventInSuspendedStateL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleEventInSuspendedStateL( CEventBasic& aEvent )
+    {
+    switch ( aEvent.GetType() )
+        {
+        case EEventSuspend:
+            // nothing to do. Suspend is immediate, so it is handled
+            // in HandleStateChangedL 
+            break;
+
+        default:
+            // suspended. ignore.
+            LOGSTRING2( "CDiagEngineImpl::HandleEventInSuspendedStateL "
+                        L"Invalid event = %d", aEvent.GetType() )
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleEventInFinalizingStateL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleEventInFinalizingStateL( CEventBasic& aEvent )
+    {
+    switch ( aEvent.GetType() )
+        {
+        case EEventAllPluginsCompleted:
+            FinalizeTestSessionL();
+            break;
+
+        default:
+            // ignore all others. This is because if the state machine
+            // gets here due to error, there may be left over events in
+            // event queue. Those should be ignored.
+            LOGSTRING2( "CDiagEngineImpl::HandleEventInFinalizingStateL "
+                        L"Invalid event = %d", aEvent.GetType() )
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleEventInStoppedStateL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleEventInStoppedStateL( CEventBasic& /* aEvent */ )
+    {
+    // ignore all events. This is because if the state machine
+    // gets here due to error, there may be left over events in
+    // event queue. Those should be ignored.
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineStateMachineObserver
+// CDiagEngineImpl::HandleError
+// ---------------------------------------------------------------------------
+//
+TState CDiagEngineImpl::HandleError( TState aCurrentState, TInt aError )
+    {
+    LOGSTRING4( "CDiagEngineImpl::HandleError() State %d(%S), ERROR %d",
+        aCurrentState,
+        &iStateMachine->StateName( aCurrentState ),
+        aError )
+
+    switch ( aCurrentState )
+        {
+        case EStateNotReady:    // fall through.
+        case EStateStopped:
+            // was not running.. Nothing to do.
+            return aCurrentState;
+
+        default:
+            {
+            iEngineError = aError;
+
+            // Database record is open. Suspend the record so that
+            // user can retry later.
+            iDbRecord.Suspend(); // error ignored
+
+            // Ignore error from application in this case since we are already
+            // handling error.
+            TRAP_IGNORE( iObserver.TestExecutionCompletedL( aError ) )
+            }
+            return EStateStopped;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::StartCreateExecutionPlanL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::StartCreateExecutionPlanL()
+    {
+    LOGSTRING( "CDiagEngineImpl::StartCreateExecutionPlanL() Start creating plan" )
+    if ( iContinueIncompleteRecord )
+        {
+        iPlan->InitializeL( iStatus );
+        }
+    else
+        {
+        iPlan->InitializeL( iStatus, iBatch );
+        }
+    SetActive();
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleEventExecute
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandlePlanCreatedL()
+    {
+    if ( iPlan->Count() == 0 )
+        {
+        // Error. There were no items in the plan.
+        iEngineError = KErrArgument;
+        iStateMachine->AddEventL( EEventAllPluginsCompleted );
+        return;
+        }
+
+    // First initialize each plugins for execution.
+    // Note that if initialization step fails, it will be caught by
+    // CStateMachine's active object, and will call ::HandleError()
+    LOGSTRING( "CDiagEngineImpl::HandlePlanCreatedL() : Phase I - Initaliaze all plugins" )
+    for ( TInt i = 0; i < iPlan->Count(); i++ )
+        {
+        MDiagPlugin& plugin = (*iPlan)[i].Plugin();
+        plugin.TestSessionBeginL( *this, iEngineConfig.IsDependencyDisabled(), iCustomParam );
+        }
+
+    LOGSTRING( "CDiagEngineImpl::HandlePlanCreatedL() : Phase II - Execution Begins" )
+    iPlan->ResetExecutionCursor();
+    iStateMachine->AddEventL( EEventExecuteNext );
+    iObserver.TestExecutionBeginL();
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::ExecuteNextPluginL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::ExecuteNextPluginL()
+    {
+    // first, check if cursor needs to be advanced
+    if ( iPlan->CurrentExecutionItem().State() == MDiagExecPlanEntry::EStateCompleted )
+        {
+        TBool moved = iPlan->MoveCursorToNext();
+        if ( !moved )
+            {
+            // cursor should always move. This is because execute next event
+            // should have never been created by NotifyResultAndContinueL
+            __ASSERT_DEBUG( 0, Panic( EDiagFrameworkInternal ) );
+            return;
+            }
+        }
+
+    // Check if we are in call. If so, suspend current execution immediately.
+    if ( iCallHandler->CurrentState() == EDiagEngineCallHandlerStateBusy )
+        {
+        LOGSTRING( "CDiagEngineImpl::ExecuteNextPluginL() Call in progress" )
+        iStateMachine->AddEventL( EEventVoiceCallActive );
+        return;
+        }
+
+    LOGSTRING2( "CDiagEngineImpl::ExecuteNextPluginL() : "
+        L"Executing plugin 0x%08x", 
+        iPlan->CurrentExecutionItem().Plugin().Uid().iUid )
+
+    iPlan->CurrentExecutionItem().ExecuteL();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::NotifyTestProgressL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::NotifyTestProgressL( CEventTestProgress& aEvent )
+    {
+    // make sure that we are reporting progress on currently executing test.
+    CDiagExecPlanEntryImpl& currItem = iPlan->CurrentExecutionItem();
+
+    if ( currItem.Plugin().Uid() == aEvent.Sender().Uid() &&
+         currItem.State() != MDiagExecPlanEntry::EStateCompleted )
+        {
+        LOGSTRING3( "CDiagEngineImpl::NotifyTestProgressL. "
+            L"Calling TestExecutionProgressL( %d, %d )", 
+            aEvent.CurrStep(), 
+            aEvent.TotalSteps() )
+        iObserver.TestExecutionProgressL( aEvent.CurrStep(), aEvent.TotalSteps() );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::NotifyResultAndContinueL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::NotifyResultAndContinueL( 
+        TInt aError,
+        CDiagResultsDatabaseItem* aResult )
+    {
+    // aResult can be NULL if it was executing suite.
+    if ( aResult )
+        {
+        CleanupStack::PushL( aResult );
+        }
+    
+    if ( aResult )
+        {
+        CleanupStack::Pop( aResult );
+        }
+
+    iObserver.TestExecutionPluginExecutedL( aError, aResult ); 
+    aResult = NULL; // aResult ownership transferred above.
+
+    if ( iPlan->IsLastPlugin() )
+        {
+        User::After(2000000);
+        iStateMachine->AddEventL( EEventAllPluginsCompleted );
+        }
+    else
+        {
+        iStateMachine->AddEventL( EEventExecuteNext );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleSkipL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleSkipL()
+    {
+    // if plan was empty, ( e.g. before any execution has actually started.
+    // do nothing.
+    if ( iPlan->Count() == 0 )
+        {
+        iEngineError = KErrArgument;
+        iStateMachine->AddEventL( EEventAllPluginsCompleted );
+        return;
+        }
+
+    // Stop execution.  While plug-ins are required to stop immediately,
+    // writing to results db is async. Completion is notified is
+    // ExecPlanEntryExecutedL()
+    iPlan->CurrentExecutionItem().StopExecutionByClientL( ESkip );
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::HandleCancelAllL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::HandleCancelAllL()
+    {
+    iEngineError = KErrCancel;
+
+    if ( iPlan->Count() == 0 )
+        {
+        // If plan was empty, ( e.g. before any execution has actually started ),
+        // do nothing and send back completed with KErrCancel.
+        iStateMachine->AddEventL( EEventAllPluginsCompleted );
+        return;
+        }
+
+    if ( iPlan->CurrentExecutionItem().State() == MDiagExecPlanEntry::EStateCompleted )
+        {
+        TBool moved = iPlan->MoveCursorToNext();
+        if ( !moved )
+            {
+            // cursor should always move. This is because execute next event
+            // should have never been created by NotifyResultAndContinueL
+            __ASSERT_DEBUG( 0, Panic( EDiagFrameworkInternal ) );
+            return;
+            }
+        }
+
+    iPlan->CurrentExecutionItem().StopExecutionByClientL( ECancelAll );
+    // Continue to ::ExecPlanEntryExecutedL
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::DoSuspendL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::DoSuspendL( MDiagEngineObserver::TSuspendReason aReason )
+    {
+    if ( iSuspendedPrevState == EStateNotReady ||
+         iSuspendedPrevState == EStateCreatingPlan ||
+         iSuspendedPrevState == EStateStopped )
+        {
+        // not much to do here.
+        }
+    else
+        {
+        StopAllRequests();
+
+        iSuspendReason = aReason;
+
+        iPlan->CurrentExecutionItem().SuspendL();
+        }
+
+    LOGSTRING( "CDiagEngineImpl::DoSuspendL: Engine Suspended" )
+    iObserver.TestExecutionSuspendedL( aReason );
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::AddResumeEventL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::AddResumeEventL( MDiagEngineObserver::TResumeReason aReason )
+    {
+    iResumeReason = aReason;
+    if ( iSuspendedPrevState == EStateNotReady ||
+         iSuspendedPrevState == EStateCreatingPlan )
+        {
+        iStateMachine->AddEventL( EEventResumeToCreatingPlan );
+        }
+    else
+        {
+        iStateMachine->AddEventL( EEventResumeToRunning );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::DoResumeL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::DoResumeL()
+    {
+    LOGSTRING( "CDiagEngineImpl::DoResumeL: Resuming Engine..." )
+    CDiagExecPlanEntryImpl& entry = iPlan->CurrentExecutionItem();
+
+    if ( entry.State() == MDiagExecPlanEntry::EStateCompleted )
+        {
+        // already completed. nothing to resume.
+        ExecuteNextPluginL();
+        }
+    else
+        {
+        entry.ResumeL();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::CreateDbItem
+//
+// ---------------------------------------------------------------------------
+//
+CDiagResultsDatabaseItem* CDiagEngineImpl::CreateDbItemL(
+        CDiagExecPlanEntryImpl& aCurrItem,
+        CDiagResultsDatabaseItem::TResult aResultType ) const
+    {
+    return CDiagResultsDbItemBuilder::CreateSimpleDbItemL( aCurrItem.Plugin().Uid(),
+                                                           aCurrItem.AsDependency(),
+                                                           aResultType );
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::NotifyPluginsOfTestSessionEnd
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::NotifyPluginsOfTestSessionEnd()
+    {
+    LOGSTRING( "CDiagEngineImpl::NotifyPluginsOfTestSessionEnd() : "
+        L"Phase III - Cleaning up stage" )
+    // unlike initialization stage, it will TRAP all errors so that 
+    // every plug-ins will have a chance to run its clean up code.
+    for ( TInt index = 0; index < iPlan->Count(); index++ )
+        {
+        MDiagPlugin& plugin = (*iPlan)[index].Plugin();
+        TRAPD( err, plugin.TestSessionEndL( 
+            *this, iEngineConfig.IsDependencyDisabled(), iCustomParam ) );
+        if ( err != KErrNone )
+            {
+            LOGSTRING3( "CDiagEngineImpl::NotifyPluginsOfTestSessionEnd(): "
+                L"Plug-in Uid %d CleanupL failed with error %d", 
+                plugin.Uid().iUid, err )
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::StopAllRequests
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::StopAllRequests()
+    {
+    Cancel();
+    StopWatchdogTemporarily();
+    }
+
+// ---------------------------------------------------------------------------
+// CDiagEngineImpl::FinalizeTestSessionL
+//
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::FinalizeTestSessionL()
+    {
+    LOGSTRING( "CDiagEngineImpl::FinalizeTestSessionL() " )
+    
+    // This causes state to change to EStateStopped
+    //iStateMachine->AddEventL( EEventFinalized );
+
+    // Call TestSessionEnd on all plug-ins
+    NotifyPluginsOfTestSessionEnd();
+
+    // Mark DB completed.
+    TBool isFullyCompleted = ( iEngineError == KErrNone );
+    
+    TInt err = iDbRecord.TestCompleted( isFullyCompleted );
+    if ( err != KErrNone )
+        {
+        LOGSTRING3( "CDiagEngineImpl::FinalizeTestSessionL() "
+            L"iDbRecord.TestCompleted( %d ) return err %d", 
+            isFullyCompleted, 
+            err )
+        iEngineError = err;
+        }
+    
+    // Let observer know that test is completed.
+    iObserver.TestExecutionCompletedL( iEngineError );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MDiagEngineCallHandlerObserver
+// CDiagEngineImpl::CallHandlerStateChangedL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::CallHandlerStateChangedL( TDiagEngineCallHandlerState aState )
+    {
+    if ( aState == EDiagEngineCallHandlerStateBusy && 
+            ( iStateMachine->CurrentState() == EStateRunning) )
+        {
+        iStateMachine->AddEventL( EEventVoiceCallActive );
+        }
+    else if ( aState == EDiagEngineCallHandlerStateIdle && 
+            iStateMachine->CurrentState() == EStateSuspended  &&
+            iSuspendReason == MDiagEngineObserver::ESuspendByPhoneCall )
+        {
+        AddResumeEventL( MDiagEngineObserver::EAutoResumedByCallHangup );
+        }
+    else
+        {
+        // Ignored
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class CActive
+// CDiagEngineImpl::RunL
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::RunL()
+    {
+    LOGSTRING2( "CDiagEngineImpl::RunL() error %d", iStatus.Int() )
+    
+    User::LeaveIfError( iStatus.Int() );
+    
+    switch ( iStateMachine->CurrentState()  )
+        {
+        case EStateCreatingPlan:
+            // plan created successfully.
+            iStateMachine->AddEventL( EEventPlanCreated );
+            break;
+
+        default:
+            __ASSERT_DEBUG( 0, Panic( EDiagFrameworkCorruptStateMachine ) );
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class CActive
+// CDiagEngineImpl::DoCancel
+// ---------------------------------------------------------------------------
+//
+void CDiagEngineImpl::DoCancel()
+    {
+    switch ( iStateMachine->CurrentState() )
+        {
+        case EStateCreatingPlan:
+            iPlan->Cancel();
+            break;
+
+        default:
+            // Nothing to do
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class CActive
+// CDiagEngineImpl::RunError
+// ---------------------------------------------------------------------------
+//
+TInt CDiagEngineImpl::RunError( TInt aError )
+    {
+    if ( iStateMachine )
+        {
+        iStateMachine->HandleError( aError );
+        }
+
+    return KErrNone;
+    }
+
+// End of File
+