diff -r 000000000000 -r b497e44ab2fc devicediagnosticsfw/diagframework/src/diagengineimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devicediagnosticsfw/diagframework/src/diagengineimpl.cpp Thu Dec 17 09:07:52 2009 +0200 @@ -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 // CDiagPluginPool +#include // LOGSTRING +#include // MDiagPlugin +#include // TDiagTestExecParam +#include // TDiagSuiteExecParam +#include // CDiagResultsDbItemBuilder +#include // 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( 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 +