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