devicediagnosticsfw/diagframework/src/diagpluginexecplanimpl.cpp
branchRCL_3
changeset 26 19bba8228ff0
parent 0 b497e44ab2fc
equal deleted inserted replaced
25:b183ec05bd8c 26:19bba8228ff0
       
     1 /*
       
     2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Class definition of CDiagPluginExecPlanImpl
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 // CLASS DECLARATION
       
    20 #include "diagpluginexecplanimpl.h"
       
    21 
       
    22 // SYSTEM INCLUDE FILES
       
    23 #include <e32def.h>
       
    24 #include <cstack.h>                     // CStack
       
    25 #include <DiagPlugin.h>                 // MDiagPlugin
       
    26 #include <DiagSuitePlugin.h>            // MDiagSuitePlugin
       
    27 #include <DiagTestPlugin.h>             // MDiagTestPlugin
       
    28 #include <DiagPluginPool.h>             // CDiagPluginPool
       
    29 #include <DiagResultsDatabase.h>        // RDiagResultsDatabaseRecord
       
    30 #include <DiagResultsDbItemBuilder.h>   // CDiagResultsDbItemBuilder
       
    31 #include <DiagResultDetail.h>           // MDiagResultDetail
       
    32 #include <DiagFrameworkDebug.h>         // For debug log
       
    33 #include <DiagResultsDbRecordEngineParam.h> // CDiagResultsDbRecordEngineParam
       
    34 
       
    35 // USER INCLUDE FILES
       
    36 #include "diagframework.pan"            // panic codes
       
    37 #include "diagexecplanentryimpl.h"      // CDiagExecPlanEntryImpl
       
    38 #include "diagexecplanentryimpltest.h"  // CDiagExecPlanEntryImplTest
       
    39 #include "diagexecplanentryimplsuite.h" // CDiagExecPlanEntryImplSuite
       
    40 #include "diagcleanupresetanddestroy.h" // CleanupRPointerArrayPushL
       
    41 #include "diagengineconfig.h"           // TDiagEngineConfig
       
    42 
       
    43 
       
    44 // DATA
       
    45 
       
    46 // MACROS
       
    47 // Uncomment the line below to enable more plan creation log.
       
    48 // #define _DEBUG_EXEC_PLAN
       
    49 
       
    50 
       
    51 // LOCAL DATA TYPES
       
    52 /**
       
    53 * Used for keeping track of suite level stack.
       
    54 * It is used in InsertSuiteTransitionsL() function. ( STEP_5 )
       
    55 */
       
    56 struct TTransitionStackEntry
       
    57     {
       
    58     /**
       
    59     * iLeavelUid - Uid of the current level. 
       
    60     */
       
    61     TUid  iLevelUid;
       
    62     
       
    63     /**
       
    64     * iPrepareIndex - Index in the plan where ETypeSuitePrepare entry is. 
       
    65     *   This information is used to update the suite iAsDependent field.
       
    66     */
       
    67     TInt    iPrepareIndex;         
       
    68     };    
       
    69 
       
    70 
       
    71 // ======== LOCAL FUNCTIONS ========
       
    72 
       
    73 
       
    74 // ======== MEMBER FUNCTIONS ========
       
    75 
       
    76 // ---------------------------------------------------------------------------
       
    77 // CDiagPluginExecPlanImpl::NewL
       
    78 // ---------------------------------------------------------------------------
       
    79 //
       
    80 CDiagPluginExecPlanImpl* CDiagPluginExecPlanImpl::NewL( 
       
    81         MDiagEngineCommon& aEngine,
       
    82         const TDiagEngineConfig& aEngineConfig,
       
    83         MDiagExecPlanEntryImplObserver& aEntryObserver )
       
    84     {
       
    85     CDiagPluginExecPlanImpl* self = new ( ELeave ) CDiagPluginExecPlanImpl( 
       
    86         aEngine,
       
    87         aEngineConfig,
       
    88         aEntryObserver );
       
    89 
       
    90     return self;
       
    91     }
       
    92 
       
    93 // ---------------------------------------------------------------------------
       
    94 // CDiagPluginExecPlanImpl::CDiagPluginExecPlanImpl
       
    95 // ---------------------------------------------------------------------------
       
    96 //
       
    97 CDiagPluginExecPlanImpl::CDiagPluginExecPlanImpl( 
       
    98         MDiagEngineCommon& aEngine,
       
    99         const TDiagEngineConfig& aEngineConfig,
       
   100         MDiagExecPlanEntryImplObserver& aEntryObserver )
       
   101     :   CActive( EPriorityLow ),
       
   102         iEngine( aEngine ),
       
   103         iEngineConfig( aEngineConfig ),
       
   104         iPlanEntryObserver( aEntryObserver )
       
   105     {
       
   106     CActiveScheduler::Add( this );
       
   107     }
       
   108 
       
   109 // ---------------------------------------------------------------------------
       
   110 // CDiagPluginExecPlanImpl::~CDiagPluginExecPlanImpl
       
   111 // ---------------------------------------------------------------------------
       
   112 //
       
   113 CDiagPluginExecPlanImpl::~CDiagPluginExecPlanImpl()
       
   114     {
       
   115     Cancel();
       
   116     iPlan.ResetAndDestroy();
       
   117     iPlan.Close();
       
   118     iExecutedEntries.ResetAndDestroy();
       
   119     iExecutedEntries.Close();
       
   120     }
       
   121 
       
   122 
       
   123 // ---------------------------------------------------------------------------
       
   124 // CDiagPluginExecPlanImpl::InitaliazeL
       
   125 //      Creating a fresh session.
       
   126 // ---------------------------------------------------------------------------
       
   127 //
       
   128 void CDiagPluginExecPlanImpl::InitializeL( TRequestStatus& aStatus, 
       
   129                                            const RPointerArray< MDiagPlugin >& aBatch )
       
   130     {
       
   131     LOGSTRING( "CDiagPluginExecPlanImpl::InitializeL: new session")
       
   132 
       
   133     __ASSERT_ALWAYS( iState == EStateIdle, Panic( EDiagFrameworkInternal ) );
       
   134 
       
   135     aStatus = KRequestPending;
       
   136     iClientStatus = &aStatus;
       
   137 
       
   138     iExecutedEntries.ResetAndDestroy();
       
   139     iPlan.ResetAndDestroy();
       
   140     iResumeIndex = 0;
       
   141 
       
   142     // pre-step execution step. copy the argument to a local plan
       
   143     TInt i;
       
   144     for ( i = 0; i < aBatch.Count();  i++ )
       
   145         {
       
   146         __ASSERT_ALWAYS( aBatch[i] != NULL, Panic( EDiagFrameworkBadArgument ) );
       
   147 
       
   148         CDiagExecPlanEntryImpl* newEntry = CreateDefaultPlanEntryLC(
       
   149             *(aBatch[i]),
       
   150             EFalse );   // aAsDependency
       
   151 
       
   152         iPlan.AppendL( newEntry );  // ownership transferred.
       
   153         CleanupStack::Pop( newEntry ); 
       
   154         newEntry = NULL;
       
   155         }
       
   156 
       
   157     LOGSTRING( "CDiagPluginExecPlanImpl::InitializeL: Initial Batch" )
       
   158     LogPlanL();
       
   159 
       
   160     ChangeState( EStateExpandDependencyAndSuites );
       
   161     }
       
   162 
       
   163 // ---------------------------------------------------------------------------
       
   164 // CDiagPluginExecPlanImpl::InitializeL
       
   165 //      Continuing from incomplete session.
       
   166 // ---------------------------------------------------------------------------
       
   167 //
       
   168 void CDiagPluginExecPlanImpl::InitializeL( TRequestStatus& aStatus )
       
   169     {
       
   170     LOGSTRING( "CDiagPluginExecPlanImpl::InitaliazeL: continue" )
       
   171 
       
   172     // validate input.
       
   173     __ASSERT_ALWAYS( iState == EStateIdle, Panic( EDiagFrameworkInternal ) );
       
   174 
       
   175     // if we are resuming incomplete session, it must incomplete.
       
   176     TBool isRecordCompleted = EFalse;
       
   177     User::LeaveIfError( iEngine.DbRecord().IsTestCompleted( isRecordCompleted ) );
       
   178     __ASSERT_ALWAYS( !isRecordCompleted, Panic( EDiagFrameworkBadArgument ) );
       
   179 
       
   180     aStatus = KRequestPending;
       
   181     iClientStatus = &aStatus;
       
   182     iResumeIndex = 0;
       
   183 
       
   184     iExecutedEntries.ResetAndDestroy();
       
   185     iPlan.ResetAndDestroy();
       
   186 
       
   187     // Retrieve records from database and use it as base for creating 
       
   188     // a new plan.
       
   189     RPointerArray< CDiagResultsDatabaseItem > previousResults;
       
   190     DiagFwInternal::CleanupRPointerArrayPushL< CDiagResultsDatabaseItem >( &previousResults );
       
   191 
       
   192     User::LeaveIfError( 
       
   193         iEngine.DbRecord().GetTestResults( previousResults ) );
       
   194 
       
   195     TInt resultCount = previousResults.Count();
       
   196     for( TInt i = 0; i < resultCount; i++ )
       
   197         {
       
   198         // Get the test plug-in.
       
   199         // Note that FindPlugin does not transfer ownership and hence testPlugin
       
   200         // and does not need to be deallocated.
       
   201         MDiagPlugin& testPlugin = 
       
   202             iEngine.PluginPool().FindPluginL( previousResults[i]->TestUid() );
       
   203 
       
   204         // This should have been a test plug-in
       
   205         __ASSERT_DEBUG( testPlugin.Type() == MDiagPlugin::ETypeTestPlugin,
       
   206             Panic( EDiagFrameworkInternal ) );
       
   207 
       
   208         CDiagExecPlanEntryImplTest* testEntry = 
       
   209             CDiagExecPlanEntryImplTest::NewLC( 
       
   210                 iEngine,
       
   211                 iEngineConfig,
       
   212                 iPlanEntryObserver,
       
   213                 static_cast< MDiagTestPlugin& >( testPlugin ),
       
   214                 previousResults[i]->WasDependency(),
       
   215                 previousResults[i]->TestResult() );
       
   216 
       
   217         if ( testEntry->Result() == CDiagResultsDatabaseItem::EQueuedToRun )
       
   218             {
       
   219             // it was queued to be executed.
       
   220             iPlan.AppendL( testEntry ); // ownership transferred.
       
   221             }
       
   222         else
       
   223             {
       
   224             // it was already executed. 
       
   225             iExecutedEntries.AppendL( testEntry ); // ownership transferred.
       
   226             }
       
   227         CleanupStack::Pop( testEntry );
       
   228         testEntry = NULL;
       
   229         }
       
   230 
       
   231     CleanupStack::PopAndDestroy( &previousResults );
       
   232 
       
   233     iResumeIndex = iExecutedEntries.Count();
       
   234 
       
   235     if ( iResumeIndex != 0 )
       
   236         {
       
   237         LOGSTRING( "CDiagPluginExecPlanImpl::InitializeL: Queued Items" )
       
   238         LogPlanL();
       
   239 
       
   240         ChangeState( EStateExpandDependencyAndSuites );
       
   241         }
       
   242     else
       
   243         {
       
   244         LOGSTRING( "CDiagPluginExecPlanImpl::InitializeL: "
       
   245             L"Items in DB may be invalid. Fully recreate plan" )
       
   246 
       
   247         // If iResumeIndex is 0, it means that all items in the db are 
       
   248         // marked as EQueuedToRun. Because of the async nature of db,
       
   249         // it could also indicate that not previous plan was not fully
       
   250         // written to the database. In this case, read the engine parameter
       
   251         // and try to recreate the plan from scratch.
       
   252         //
       
   253         // If it was already fully written but hadn't had a chance to really
       
   254         // execute anything, this will not cause any ill effects since
       
   255         // plan created should be identical and simply reset 
       
   256         // all results in db to EQueuedToRun.
       
   257         iExecutedEntries.ResetAndDestroy();
       
   258         iPlan.ResetAndDestroy();
       
   259 
       
   260         RPointerArray< MDiagPlugin > batch;
       
   261         CleanupClosePushL( batch );    // items are not owned, so no need for "Destroy"
       
   262 
       
   263         CDiagResultsDbRecordEngineParam* engineParam = NULL;
       
   264         User::LeaveIfError( 
       
   265             iEngine.DbRecord().GetEngineParam( engineParam ) );
       
   266 
       
   267         CleanupStack::PushL( engineParam );
       
   268 
       
   269         const RArray< TUid >& batchUids = engineParam->ExecutionsUidArray();
       
   270 
       
   271         // Read original Uids from previous engine param.
       
   272         for( TInt i = 0; i < batchUids.Count(); i++ )
       
   273             {
       
   274             MDiagPlugin* testPlugin = NULL;
       
   275             User::LeaveIfError( 
       
   276                 iEngine.PluginPool().FindPlugin( batchUids[i], testPlugin ) );
       
   277 
       
   278             __ASSERT_DEBUG( testPlugin != NULL, Panic( EDiagFrameworkInternal ) );
       
   279             if ( testPlugin )  //lint !e774 This will be evaluated on non-debug build.
       
   280                 {
       
   281                 batch.AppendL( testPlugin );
       
   282                 }
       
   283             }
       
   284 
       
   285         CleanupStack::PopAndDestroy( engineParam );
       
   286         engineParam = NULL;
       
   287 
       
   288         // Call the normal InitializeL() method as if it is a new session.
       
   289         InitializeL( aStatus, batch );
       
   290 
       
   291         CleanupStack::PopAndDestroy( &batch );  // calls Close()
       
   292         }
       
   293     }
       
   294 
       
   295 // ---------------------------------------------------------------------------
       
   296 // CDiagPluginExecPlanImpl::operator[]
       
   297 // ---------------------------------------------------------------------------
       
   298 //
       
   299 CDiagExecPlanEntryImpl& CDiagPluginExecPlanImpl::operator[]( TInt aIndex )
       
   300     {
       
   301     return *iPlan[aIndex];
       
   302     }
       
   303 
       
   304 // ---------------------------------------------------------------------------
       
   305 // CDiagPluginExecPlanImpl::CurrentExecutionItem
       
   306 // ---------------------------------------------------------------------------
       
   307 //
       
   308 CDiagExecPlanEntryImpl& CDiagPluginExecPlanImpl::CurrentExecutionItem() 
       
   309     {
       
   310     return *iPlan[iExecutionCursor];
       
   311     }
       
   312 
       
   313 // ---------------------------------------------------------------------------
       
   314 // CDiagPluginExecPlanImpl::ResetExecutionCursor
       
   315 // ---------------------------------------------------------------------------
       
   316 //
       
   317 void CDiagPluginExecPlanImpl::ResetExecutionCursor()
       
   318     {
       
   319     iExecutionCursor = 0;
       
   320     }
       
   321 
       
   322 // ---------------------------------------------------------------------------
       
   323 // CDiagPluginExecPlanImpl::MoveCursorToNext
       
   324 // ---------------------------------------------------------------------------
       
   325 //
       
   326 TBool CDiagPluginExecPlanImpl::MoveCursorToNext()
       
   327     {
       
   328     TBool value = EFalse;
       
   329 
       
   330     if ( iExecutionCursor < iPlan.Count() - 1 )
       
   331         {
       
   332         iExecutionCursor++;
       
   333         value = ETrue;
       
   334         }
       
   335     else
       
   336         {
       
   337         // cannot move beyond the last item.
       
   338         }
       
   339 
       
   340     return value;
       
   341     }
       
   342 
       
   343 // ======== From CActive =========
       
   344 // ---------------------------------------------------------------------------
       
   345 // From CActive
       
   346 // CDiagPluginExecPlanImpl::RunL
       
   347 // ---------------------------------------------------------------------------
       
   348 //
       
   349 void CDiagPluginExecPlanImpl::RunL()
       
   350     {
       
   351     /*----------------------------------------------------------------------
       
   352        Create execution plan:
       
   353        Overview:
       
   354        
       
   355             STEP_1. Expand Dependency 
       
   356             STEP_2. Expand Suites.
       
   357             STEP_3. Repeat STEP_1 & STEP_2 until no changes are made to the plan
       
   358             STEP_4. Check and remove empty suites
       
   359             STEP_5. Add Prepare/Finalize suite execution.
       
   360             STEP_6. Store execution plan to results db. 
       
   361             STEP_7. Append items that were executed in the previous test
       
   362                     to the beginning of the test.
       
   363        
       
   364        Details:
       
   365         STEP_1. Expand Dependency
       
   366             In this step, each item is checked for dependency and 
       
   367             dependent items will be inserted into plan.
       
   368             Note that if dependent item also depends on something else, those
       
   369             will be added immediately.
       
   370        
       
   371             All items inserted during this phase is inserted as dependent.
       
   372        
       
   373         STEP_2. Expand suites
       
   374             Suites are expandeded to individual tests or suites. Suite
       
   375             item will be expanded between parent suite's Prepare and 
       
   376             Finalize items. 
       
   377             
       
   378             iAsDependent value will be inherited from the parent suite
       
   379             that it expanded from. E.g. if suite was dependent, then so will
       
   380             all the items that included from that suite.
       
   381         
       
   382             Note that it does not remove the original suite entry in the plan. 
       
   383             This is to make sure that dependencies inserted will be grouped
       
   384             within the same group as the plug-ins that depended on it.
       
   385             If they are removed, and re-inserted later in STEP_5, it will
       
   386             cause the dependent items to be outside of the original grouping.
       
   387                 e.g.  S1 = {P1}
       
   388                       S2 = {P2, P3}
       
   389 
       
   390                       and P2 depends on P1
       
   391 
       
   392                 When dependency and suites are expanded with original
       
   393                 suite removed, after STEP_3, the plan will look like this:
       
   394                     (* indicates iAsDependent == ETrue)
       
   395 
       
   396                       0     1    2
       
   397                       *P1   P2   P3
       
   398 
       
   399                 When it tries to add suite transition back in to the plan,
       
   400                 it will look like this:
       
   401                     (* indicates iAsDependent == ETrue)
       
   402                     (< indicates suite prepare execution.)
       
   403                     (> indicates suite finalize execution.)
       
   404 
       
   405                       0    1    2    3    4   5   6
       
   406                       <S1  *P1  S1>  <S2  P2  P3  S2>
       
   407 
       
   408                 which is somewhat incorrect since *P1 is added due to 
       
   409                 dependency. 
       
   410                 
       
   411                 Instead, if original suite grouping is kept, after STEP_3
       
   412 
       
   413                     0    1    2    3    4
       
   414                     <S2  *P1  P2   P3   S2>
       
   415 
       
   416                 After STEP_5
       
   417 
       
   418                     0    1    2    3    4   5   6
       
   419                     <S2  <S1  *P1  S1>  P2  P3  S2>
       
   420                              
       
   421                 which is more correct.
       
   422             
       
   423             Note that this will be done in breadth first style. If there is a
       
   424             nested suites, it will not be expanded until next cycle. 
       
   425             This is to allow dependencies of the suite to be expanded before
       
   426             being removed.
       
   427        
       
   428         STEP_3. Repeat STEP_1 & STEP_2 until no changes are made.
       
   429             This step ensures that suites are expanded, and all dependent
       
   430             items are added to the plan.
       
   431        
       
   432         STEP_4. Remove Empty suites
       
   433             Because dependent items can be moved, it is possible that plan ends
       
   434             up with empty suites. This section will check for 
       
   435             suite prepare/finalize that has nothing inside, and remove them.
       
   436 
       
   437         STEP_5. Add Prepare/Finalize steps for suites.
       
   438             As a final step, it will navigate all the entries in the plan, and
       
   439             insert proper prepare/finalize steps. This is based on stack,
       
   440             where every suite prepare is pushed into a stack, and poped when
       
   441             suite finalize is called. e.g. consider following plug-ins:
       
   442 
       
   443                 S1 = { P1, P2 }
       
   444                 S2 = { P3, P4 }
       
   445 
       
   446                 And P3 depends on P2.
       
   447 
       
   448             And resulting plan after STEP_4 looked like this:
       
   449 
       
   450                 0    1     2    3    4
       
   451                 <S2  *P2   P3   P4   S2>
       
   452 
       
   453             After STEP_5, it should look like this:
       
   454 
       
   455                 0    1    2    3    4    5    6
       
   456                 <S2  <S1  *P2  S1>  P3   P4   S2>
       
   457 
       
   458         STEP_6. Store execution plan to results db. 
       
   459             This allows continuation of the incomplete results.
       
   460             Only test plug-ins are written to the database. 
       
   461 
       
   462         STEP_7. Append items that were executed in the previous test
       
   463             to the beginning of the test.
       
   464 
       
   465         Other Notes:
       
   466 
       
   467         NOTE_1) This logic currently does not check for circular dependencies.
       
   468            If circular dependency exists, the program will go into an
       
   469            infinite loop in ExpandDependenciesL().
       
   470 
       
   471         NOTE_2) Inserting duplicate items.
       
   472             Due to dependencies, duplicate entries may exist in the plan.
       
   473 
       
   474             When items are inserted during STEP_1 - STEP_2, it will be checked
       
   475             for duplicates.
       
   476        
       
   477             Duplicate removal policy is as follows:
       
   478             RULE_A) If an item with "iAsDependent == ETrue" is being inserted,
       
   479                 AND if an item already exist in the plan before current index,
       
   480                 then it will not be inserted. 
       
   481 
       
   482             RULE_B) Any items inserted with "iAsDependent == EFalse" will 
       
   483                always be inserted at the requested index.
       
   484                This is because they are considered to be user input, and
       
   485                plan will not try to re-order the execution order that 
       
   486                client or user has specified.
       
   487 
       
   488             RULE_C) The first instance of an item has higher priority than later
       
   489                instances. Later instace of duplicate will be removed, unless
       
   490                it violates RULE_B. (e.g. item has "iAsDependent == EFalse".)
       
   491 
       
   492             This has a side effect: item may execute twice in certain cases.
       
   493             E.g. original plan has two plug-ins:  P1, P2, P3
       
   494             P1 depends on P2, and P3 also depends ond P2
       
   495 
       
   496             Original Input:   0   1   2
       
   497                               P1  P2  P3
       
   498 
       
   499             After STEP_3, it should look like this. 
       
   500                     (* indicates iAsDependent == ETrue)
       
   501 
       
   502                               0    1    2   3    4
       
   503                               *P2  P1   P2  *P2  P3
       
   504 
       
   505             During STEP_4, duplicates are removed, and it should look like this:
       
   506                     (* indicates iAsDependent == ETrue)
       
   507 
       
   508                               0    1    2   4
       
   509                               *P2  P1   P2  P3
       
   510 
       
   511             Note that there are two P2s in the plan; 
       
   512             at 0 with iAsDependent == ETrue and at 2 with iAsDependent == EFalse
       
   513 
       
   514             There may be some discussions on whether this is how it should be.
       
   515             However, at this point, it seems that it is more important that
       
   516             execution appears to the user in the order specified. 
       
   517 
       
   518             To make sure that user sees that P2 is executed only once, plug-in
       
   519             developer may need to make sure that if a plug-in provides services,
       
   520             it should also handle cases where it is executed twice.
       
   521 
       
   522             In reality, such cases can be avoided by grouping the plug-ins 
       
   523             in the correct order, hence it should not be an issue.
       
   524 
       
   525     ----------------------------------------------------------------------*/
       
   526 
       
   527     // First, error handling.
       
   528     LOGSTRING3( "CDiagPluginExecPlanImpl::RunL: State = %d, Err = %d",
       
   529         iState, iStatus.Int() )
       
   530 
       
   531     User::LeaveIfError( iStatus.Int() );
       
   532 
       
   533     switch ( iState )
       
   534         {
       
   535         case EStateExpandDependencyAndSuites:
       
   536             {
       
   537             LOGSTRING( "CDiagPluginExecPlanImpl::RunL: STEP_1")
       
   538             // STEP_1. Expand dependency. 
       
   539             if ( !iEngineConfig.IsDependencyDisabled() )
       
   540                 {
       
   541                 ExpandDependenciesL();
       
   542                 }
       
   543 
       
   544             LOGSTRING( "CDiagPluginExecPlanImpl::RunL: STEP_2")
       
   545             // STEP_2. Expand suites.
       
   546             if ( ExpandSuitesL() )
       
   547                 {
       
   548                 // STEP_3. Repeat STEP_1, STEP_2 until no changes are made.
       
   549                 // Do a self transition to repeat STEP_1 and STEP_2
       
   550                 ChangeState( EStateExpandDependencyAndSuites );
       
   551                 }
       
   552             else
       
   553                 {
       
   554                 // no changes are made to the plan. Move to STEP_4
       
   555                 ChangeState( EStateRemoveEmptySuites );
       
   556                 }
       
   557             }
       
   558             break;
       
   559 
       
   560         case EStateRemoveEmptySuites:
       
   561             LOGSTRING( "CDiagPluginExecPlanImpl::RunL: STEP_4")
       
   562             // STEP_4. Remove empty suites. This can happen because of duplicate
       
   563             // dependencies moving later dependent test to earlier position.
       
   564             RemoveEmptySuites();
       
   565 
       
   566             #ifdef _DEBUG_EXEC_PLAN
       
   567             LOGSTRING( "CDiagPluginExecPlanImpl:CreatePlanL: "
       
   568                 L"Before Inserting Suite Transtions" )
       
   569             LogPlanL();
       
   570             #endif // _DEBUG_EXEC_PLAN
       
   571 
       
   572             // Continue to STEP_5
       
   573             ChangeState( EStateInsertSuiteTransitions );
       
   574             break;
       
   575 
       
   576         case EStateInsertSuiteTransitions:
       
   577             LOGSTRING( "CDiagPluginExecPlanImpl::RunL: STEP_5 - Insert Suite Transtions")
       
   578             // STEP_5. Add pre/post suite execution
       
   579             InsertSuiteTransitionsL();
       
   580 
       
   581             // STEP_6. Store plan to db.
       
   582             LOGSTRING( "CDiagPluginExecPlanImpl::RunL: STEP_6 - Store to db")
       
   583             // this time, manually update state, since storing 
       
   584             // to database needs to use iStatus
       
   585             iState = EStateStoreToDb;
       
   586 
       
   587             // Move cursor to one before so that it can start checking from
       
   588             // the beginning. StoreNextTestPluginToDbL() will move the cursor
       
   589             // as soon as it enters.
       
   590             iExecutionCursor = -1;
       
   591             StoreNextTestPluginToDbL();
       
   592             
       
   593             break;
       
   594 
       
   595         case EStateStoreToDb:
       
   596             LOGSTRING2( "CDiagPluginExecPlanImpl::RunL: STEP_6 - "
       
   597                 L"item 0x%08x stored.",
       
   598                 iPlan[iExecutionCursor]->Plugin().Uid().iUid )
       
   599 
       
   600             StoreNextTestPluginToDbL();
       
   601             break;
       
   602 
       
   603         case EStatePlanCreated:
       
   604             // STEP_7. Prepend the items that were executed in last session
       
   605             // to the beginning of the execution plan.
       
   606             LOGSTRING( "CDiagPluginExecPlanImpl::RunL: STEP_7 - prepend executed items" )
       
   607             PrependExecutedItemsL();
       
   608 
       
   609             LOGSTRING( "CDiagPluginExecPlanImpl::RunL: Final Plan" )
       
   610             LogPlanL();
       
   611             
       
   612             LOGSTRING2( "CDiagPluginExecPlanImpl::RunL: Resume at index %d", iResumeIndex )
       
   613 
       
   614             LogPlanInRecordL();
       
   615 
       
   616             ResetExecutionCursor();
       
   617 
       
   618             ReportResult( KErrNone );
       
   619             break;
       
   620 
       
   621         case EStateIdle:
       
   622         default:
       
   623             __ASSERT_DEBUG( 0, Panic( EDiagFrameworkInternal ) );
       
   624             break;
       
   625         }
       
   626     }
       
   627 
       
   628 // ---------------------------------------------------------------------------
       
   629 // From CActive
       
   630 // CDiagPluginExecPlanImpl::DoCancel
       
   631 // ---------------------------------------------------------------------------
       
   632 //
       
   633 void CDiagPluginExecPlanImpl::DoCancel()
       
   634     {
       
   635     iPlan.ResetAndDestroy();
       
   636     iExecutedEntries.ResetAndDestroy();
       
   637     iState = EStateIdle;
       
   638 
       
   639     ReportResult( KErrCancel );
       
   640     }
       
   641 
       
   642 // ---------------------------------------------------------------------------
       
   643 // From CActive
       
   644 // CDiagPluginExecPlanImpl::RunError
       
   645 // ---------------------------------------------------------------------------
       
   646 //
       
   647 TInt CDiagPluginExecPlanImpl::RunError( TInt aError )
       
   648     {
       
   649     iPlan.ResetAndDestroy();
       
   650     iExecutedEntries.ResetAndDestroy();
       
   651     iState = EStateIdle;
       
   652 
       
   653     ReportResult( aError );
       
   654 
       
   655     return KErrNone;
       
   656     }
       
   657 
       
   658 // ---------------------------------------------------------------------------
       
   659 // From MDiagPluginExecPlan
       
   660 // CDiagPluginExecPlanImpl::CurrentIndex
       
   661 // ---------------------------------------------------------------------------
       
   662 //
       
   663 TInt CDiagPluginExecPlanImpl::CurrentIndex() const
       
   664     {
       
   665     return iExecutionCursor;
       
   666     }
       
   667 
       
   668 
       
   669 // ---------------------------------------------------------------------------
       
   670 // From MDiagPluginExecPlan
       
   671 // CDiagPluginExecPlanImpl::CurrentTestIndex
       
   672 // ---------------------------------------------------------------------------
       
   673 //
       
   674 TInt CDiagPluginExecPlanImpl::CurrentTestIndex( TBool aIncludeDependency ) const
       
   675     {
       
   676     TInt count = 0;
       
   677 
       
   678     for ( TInt i = 0; i < iPlan.Count() && i < iExecutionCursor; i++ )
       
   679         {
       
   680         if ( iPlan[i]->Plugin().Type() == MDiagPlugin::ETypeTestPlugin )
       
   681             {
       
   682             // if caller wants to include both explicit and dependent
       
   683             // or if plug-in is not depentent test, count.
       
   684             if ( aIncludeDependency || ( !iPlan[i]->AsDependency() ) )
       
   685                 {
       
   686                 count++;
       
   687                 }
       
   688             }
       
   689         }
       
   690     
       
   691     // subtract 1 if we only went past the last test.
       
   692     if ( count >= TestCount( aIncludeDependency ) )
       
   693         {
       
   694         count--;
       
   695         }
       
   696     return count;
       
   697     }
       
   698 
       
   699 
       
   700 // ---------------------------------------------------------------------------
       
   701 // From MDiagPluginExecPlan
       
   702 // CDiagPluginExecPlanImpl::TestCount
       
   703 // ---------------------------------------------------------------------------
       
   704 //
       
   705 TInt CDiagPluginExecPlanImpl::TestCount( TBool aIncludeDependency ) const
       
   706     {
       
   707     TInt count = 0;
       
   708 
       
   709     for ( TInt i = 0; i < iPlan.Count(); i++ )
       
   710         {
       
   711         if ( iPlan[i]->Plugin().Type() == MDiagPlugin::ETypeTestPlugin )
       
   712             {
       
   713             // if caller wants to include both explicit and dependent
       
   714             // or if plug-in is not depentent test, count.
       
   715             if ( aIncludeDependency || ( !iPlan[i]->AsDependency() ) )
       
   716                 count++;
       
   717             }
       
   718         }
       
   719     return count;
       
   720     }
       
   721 
       
   722 // ---------------------------------------------------------------------------
       
   723 // From MDiagPluginExecPlan
       
   724 // CDiagPluginExecPlanImpl::operator[] () const
       
   725 // ---------------------------------------------------------------------------
       
   726 //
       
   727 const MDiagExecPlanEntry& CDiagPluginExecPlanImpl::operator[] ( TInt aIndex ) const
       
   728     {
       
   729     __ASSERT_ALWAYS( aIndex >= 0 && aIndex < iPlan.Count(), 
       
   730                      Panic( EDiagFrameworkArrayBounds ) );
       
   731     return *( static_cast< MDiagExecPlanEntry* >( iPlan[aIndex] ) );
       
   732     }
       
   733 
       
   734 // ---------------------------------------------------------------------------
       
   735 // From MDiagPluginExecPlan
       
   736 // CDiagPluginExecPlanImpl::CurrentExecutionItem const
       
   737 // ---------------------------------------------------------------------------
       
   738 //
       
   739 const MDiagExecPlanEntry& CDiagPluginExecPlanImpl::CurrentExecutionItem() const
       
   740     {
       
   741     __ASSERT_ALWAYS( iExecutionCursor >= 0 && iExecutionCursor < iPlan.Count(), 
       
   742                      Panic( EDiagFrameworkArrayBounds ) );
       
   743     return *( static_cast< MDiagExecPlanEntry* >( iPlan[iExecutionCursor] ) );
       
   744     }
       
   745 
       
   746 
       
   747 // ---------------------------------------------------------------------------
       
   748 // From MDiagPluginExecPlan
       
   749 // CDiagPluginExecPlanImpl::IsLastTest
       
   750 // ---------------------------------------------------------------------------
       
   751 //
       
   752 TBool CDiagPluginExecPlanImpl::IsLastTest() const
       
   753     {
       
   754     if ( TestCount( ETrue ) == 0 )
       
   755         {
       
   756         // there was no test in the plan.. 
       
   757         // In this case, it is always ETrue.
       
   758         return ETrue;
       
   759         }
       
   760 
       
   761     return ( CurrentTestIndex( ETrue ) == TestCount( ETrue ) - 1 );
       
   762     }
       
   763 
       
   764 // ---------------------------------------------------------------------------
       
   765 // From MDiagPluginExecPlan
       
   766 // CDiagPluginExecPlanImpl::IsLastPlugin
       
   767 // ---------------------------------------------------------------------------
       
   768 //
       
   769 TBool CDiagPluginExecPlanImpl::IsLastPlugin() const
       
   770     {
       
   771     if ( iPlan.Count() == 0 )
       
   772         {
       
   773         // if plan was empty, always consider it to be the last.
       
   774         return ETrue;
       
   775         }
       
   776 
       
   777     return iExecutionCursor == ( iPlan.Count() -1 );
       
   778     }
       
   779 
       
   780 
       
   781 // ---------------------------------------------------------------------------
       
   782 // From MDiagPluginExecPlan
       
   783 // CDiagPluginExecPlanImpl::Count
       
   784 // ---------------------------------------------------------------------------
       
   785 //
       
   786 TInt CDiagPluginExecPlanImpl::Count() const
       
   787     {
       
   788     return iPlan.Count();
       
   789     }
       
   790 
       
   791 // ---------------------------------------------------------------------------
       
   792 // From MDiagPluginExecPlan
       
   793 // CDiagPluginExecPlanImpl::ResumeIndex
       
   794 // ---------------------------------------------------------------------------
       
   795 //
       
   796 TInt CDiagPluginExecPlanImpl::ResumeIndex() const
       
   797     {
       
   798     return iResumeIndex;
       
   799     }
       
   800 
       
   801 // ---------------------------------------------------------------------------
       
   802 // CDiagPluginExecPlanImpl::ChangeState
       
   803 // ---------------------------------------------------------------------------
       
   804 //
       
   805 void CDiagPluginExecPlanImpl::ChangeState( TState aState )
       
   806     {
       
   807     LOGSTRING3( "CDiagPluginExecPlanImpl::ChangeState: state change %d -> %d",
       
   808         iState, aState )
       
   809 
       
   810     iState = aState;
       
   811 
       
   812     TRequestStatus* stat = &iStatus;
       
   813     User::RequestComplete( stat, KErrNone );
       
   814     SetActive();
       
   815     }
       
   816 
       
   817 // ---------------------------------------------------------------------------
       
   818 // CDiagPluginExecPlanImpl::ExpandDependenciesL
       
   819 // ---------------------------------------------------------------------------
       
   820 //
       
   821 TBool CDiagPluginExecPlanImpl::ExpandDependenciesL()
       
   822     {
       
   823     // STEP_1. Expand dependency.
       
   824     // Before modifying this function, please see STEP_1 comments in CreatePlanL()
       
   825     TInt planIdx = 0;
       
   826     TBool planChanged( EFalse );
       
   827     while ( planIdx < iPlan.Count() )
       
   828         {
       
   829         TBool itemAdded = EFalse;
       
   830 
       
   831         // we are only interested in type ETypeTestExec or ETypeSuiteUnexpanded. 
       
   832         // If it is ETypeSuitePrepare or ETypeSuiteFinalize, that means 
       
   833         // that it is a suite and it has been already been expanded to 
       
   834         // prepare/finalize. Since dependencies are resolved before suites 
       
   835         // are expanded, we are not interested in re-evaluating expanded tests.
       
   836         if ( iPlan[planIdx]->Type() == CDiagExecPlanEntryImpl::ETypeTestExec ||
       
   837              iPlan[planIdx]->Type() == CDiagExecPlanEntryImpl::ETypeSuiteUnexpanded )
       
   838             {
       
   839             // dependencies should be rare. So granuality 1 should be fine.
       
   840             CPtrCArray* depList = new( ELeave )CPtrCArray( 1 );
       
   841             CleanupStack::PushL( depList );
       
   842             iPlan[planIdx]->Plugin().GetLogicalDependenciesL( *depList );
       
   843 
       
   844             // iterate through the dependiencies BACKWARDS to make sure
       
   845             // that dependencies are inserted in the same order 
       
   846             // specified. If it is not added backwards, developers may 
       
   847             // be surprised that dependencies are executed 
       
   848             // in reverse order of what is specified in the XML.
       
   849             for ( TInt depIdx = depList->Count() - 1; depIdx >= 0; depIdx-- )
       
   850                 {
       
   851                 // If dependency is specified, but the dependent plug-in is 
       
   852                 // not found in plug-in pool, this probably means 
       
   853                 // plug-in database is corrupted.
       
   854                 MDiagPlugin& plugin = iEngine.PluginPool().FindPluginL( ( *depList )[ depIdx ] );
       
   855 
       
   856                 if ( InsertPluginL( plugin, 
       
   857                                     ETrue, 
       
   858                                     planIdx ) )
       
   859                     {
       
   860                     itemAdded = ETrue;
       
   861                     }
       
   862                 }
       
   863             CleanupStack::PopAndDestroy( depList );
       
   864             depList = NULL;
       
   865             }
       
   866 
       
   867         // Advance to next item in plan only if no new item is added.
       
   868         // This ensures that items just added are re-evaluated for
       
   869         // dependency, and expand if it is an unexpanded suite.
       
   870         if ( !itemAdded )
       
   871             {
       
   872             planIdx++;
       
   873             }
       
   874         else
       
   875             {
       
   876             planChanged = ETrue;
       
   877             }
       
   878         }
       
   879 
       
   880     return planChanged;
       
   881     }
       
   882 
       
   883 
       
   884 // ---------------------------------------------------------------------------
       
   885 // CDiagPluginExecPlanImpl::ExpandSuitesL
       
   886 // ---------------------------------------------------------------------------
       
   887 //
       
   888 TBool CDiagPluginExecPlanImpl::ExpandSuitesL() 
       
   889     {
       
   890     // STEP_2. Expand suites.
       
   891     // Before modifying this function, please see STEP_1 comments in CreatePlanL()
       
   892     TBool planChanged = EFalse;
       
   893     TInt i = 0;
       
   894     while ( i < iPlan.Count() )
       
   895         {
       
   896         if ( iPlan[i]->Type() == CDiagExecPlanEntryImpl::ETypeSuiteUnexpanded )
       
   897             {
       
   898             // If it is unexpanded, it must be a suite.
       
   899             __ASSERT_DEBUG( iPlan[i]->Plugin().Type() == MDiagPlugin::ETypeSuitePlugin,
       
   900                             Panic( EDiagFrameworkInternal ) );
       
   901             planChanged = ETrue;
       
   902 
       
   903             // Change type from ETestExec to ETypeSuitePrepare. This indicates
       
   904             // that the suite item in the plan has been examined and
       
   905             // expanded.
       
   906             iPlan[i]->SetType( CDiagExecPlanEntryImpl::ETypeSuitePrepare );
       
   907 
       
   908             // dependency is inherited
       
   909             TBool asDependency = iPlan[i]->AsDependency();
       
   910             
       
   911             // Get Children from the plug-in
       
   912             MDiagSuitePlugin& suite = static_cast<MDiagSuitePlugin&>( iPlan[i]->Plugin() );
       
   913             RPointerArray<MDiagPlugin> children;
       
   914             CleanupClosePushL( children );
       
   915 
       
   916             suite.GetChildrenL( children, MDiagSuitePlugin::ESortByPosition );
       
   917 
       
   918             i++; // insert rest after current item.
       
   919 
       
   920             TInt childIdx = 0;
       
   921             while ( childIdx < children.Count() )
       
   922                 {
       
   923                 if ( InsertPluginL( *( children[childIdx] ), 
       
   924                                     asDependency, 
       
   925                                     i ) )
       
   926                     {
       
   927                     // new item is added. Move to next
       
   928                     i++;
       
   929                     }
       
   930                 childIdx++;
       
   931                 }
       
   932 
       
   933             children.Reset();   // children pointers are not owned 
       
   934             CleanupStack::PopAndDestroy( &children );
       
   935 
       
   936             // insert suite finalize entry into plan
       
   937             CDiagExecPlanEntryImplSuite* finalizeEntry = 
       
   938                 CDiagExecPlanEntryImplSuite::NewLC(
       
   939                     iEngine,
       
   940                     iEngineConfig,
       
   941                     iPlanEntryObserver,
       
   942                     suite,
       
   943                     asDependency,
       
   944                     CDiagExecPlanEntryImpl::ETypeSuiteFinalize );
       
   945 
       
   946             iPlan.InsertL( static_cast< CDiagExecPlanEntryImpl* >( finalizeEntry ), i );   
       
   947             CleanupStack::Pop( finalizeEntry ); // owership transferred
       
   948             finalizeEntry = NULL;
       
   949             i++;
       
   950             }
       
   951         else
       
   952             {
       
   953             // this one is not suite, so examine the next one.
       
   954             i++;    
       
   955             }
       
   956         }
       
   957 
       
   958     return planChanged;
       
   959     }
       
   960 
       
   961 // Looking for STEP_3?  It is in RunL() .. 
       
   962 
       
   963 // ---------------------------------------------------------------------------
       
   964 // CDiagPluginExecPlanImpl::RemoveEmptySuites
       
   965 // ---------------------------------------------------------------------------
       
   966 //
       
   967 void CDiagPluginExecPlanImpl::RemoveEmptySuites()
       
   968     {
       
   969     // STEP_4. Remove empty suites
       
   970     // Before modifying this function, please see STEP_1 comments in CreatePlanL()
       
   971 
       
   972     // Checking for duplicate is done by checking if suite prepare/finalize
       
   973     // is in the plan next to each other.
       
   974     //
       
   975     // NOTE_4
       
   976     // After a empty suite is removed, step back one index.
       
   977     // so that the previous item will be re-evaluated, in case removing them cased 
       
   978     // the parent suite to be empty as well.
       
   979     //      e.g
       
   980     //      i == 1
       
   981     //      index:   0   [1]  2   3
       
   982     //               <A  <B   B>  A> 
       
   983     //  after removal, now prepare/finalize A becomes next to each other
       
   984     //
       
   985     //      i == 1
       
   986     //      index:   0   [1] 
       
   987     //               <A  A> 
       
   988     //
       
   989     // in order to make sure that above case is handled, decrement i and
       
   990     // re-evaluate from index 0
       
   991     //
       
   992     TInt i = 0;
       
   993     while ( i < iPlan.Count() - 2 )  // no need to go beyond the last item
       
   994         {
       
   995         if ( iPlan[i]->Type() == CDiagExecPlanEntryImpl::ETypeSuitePrepare &&
       
   996                 iPlan[i+1]->Type() == CDiagExecPlanEntryImpl::ETypeSuiteFinalize )
       
   997             {
       
   998             // if these two do not match, then there may have been
       
   999             // a problem during plan creation.
       
  1000             __ASSERT_DEBUG( iPlan[i]->Plugin().Uid() == iPlan[i+1]->Plugin().Uid(),
       
  1001                             Panic( EDiagFrameworkCorruptPlugin ) );
       
  1002 
       
  1003 
       
  1004             CDiagExecPlanEntryImpl* entry = iPlan[ i + 1 ];
       
  1005             iPlan.Remove( i+1 );
       
  1006             delete entry;
       
  1007             entry = NULL;
       
  1008 
       
  1009             entry = iPlan[i];
       
  1010             iPlan.Remove( i );
       
  1011             delete entry;
       
  1012             entry = NULL;
       
  1013             
       
  1014             // Wondering why step back by one? See NOTE_4
       
  1015             if ( i > 0 )
       
  1016                 {
       
  1017                 i--;
       
  1018                 }
       
  1019             }
       
  1020         else
       
  1021             {
       
  1022             // it's not empty. Examine next item.
       
  1023             i++;
       
  1024             }
       
  1025         }
       
  1026     }
       
  1027 
       
  1028 // ---------------------------------------------------------------------------
       
  1029 // CDiagPluginExecPlanImpl::InsertSuiteTransitionsL
       
  1030 // ---------------------------------------------------------------------------
       
  1031 //
       
  1032 void CDiagPluginExecPlanImpl::InsertSuiteTransitionsL()
       
  1033     {
       
  1034     // STEP_5. Add pre/post suite execution based on test parent change.
       
  1035     // Before modifying this function, please see STEP_1 comments in CreatePlanL()
       
  1036     
       
  1037     // if plan is empty, nothing to do.
       
  1038     if ( iPlan.Count() == 0 )
       
  1039         {
       
  1040         return;
       
  1041         }
       
  1042     
       
  1043     // Create a new CStack. Second template parameter ETrue means that
       
  1044     // CStack owns the stack entries.
       
  1045     CStack<TTransitionStackEntry, ETrue>* stack = 
       
  1046         new( ELeave )CStack<TTransitionStackEntry, ETrue>;
       
  1047     
       
  1048     CleanupStack::PushL( stack );
       
  1049 
       
  1050     // create a root entry
       
  1051     AddRootSuiteIfMissingL();
       
  1052     
       
  1053     // In this loop, iPlan.Count() cannot be cached because new item may be
       
  1054     // added within the loop
       
  1055     TInt i = 0;
       
  1056     while ( i < iPlan.Count() )
       
  1057         {
       
  1058         #ifdef _DEBUG_EXEC_PLAN
       
  1059         LOGSTRING2( "CDiagPluginExecPlanImpl::InsertSuiteTransitionsL: ------ %d", i )
       
  1060         LogPlanL();
       
  1061         #endif // _DEBUG_EXEC_PLAN
       
  1062             
       
  1063         // Case 1
       
  1064         // If current item is a suite prepare, push a new level into stack.
       
  1065         if ( iPlan[i]->Type() == CDiagExecPlanEntryImpl::ETypeSuitePrepare )
       
  1066             {
       
  1067             // we are entering a new suite. Push current plan item into stack.
       
  1068             PushNewLevelL( *stack, i );
       
  1069             i++;
       
  1070             continue; //lint !e960  continue OK. examine next item.
       
  1071             }
       
  1072 
       
  1073         // Case 2
       
  1074         // If current item is a suite finalize, pop a level from stack.
       
  1075         if ( iPlan[i]->Type() == CDiagExecPlanEntryImpl::ETypeSuiteFinalize && 
       
  1076                 stack->Head() != NULL &&
       
  1077                 stack->Head()->iLevelUid == iPlan[i]->Plugin().Uid() )
       
  1078             {
       
  1079             // we are leaving a suite. Pop top item from suite.
       
  1080             PopLevel( *stack );
       
  1081             i++;
       
  1082             continue; //lint !e960 : continue OK. examine next item.
       
  1083             }
       
  1084 
       
  1085         // it was neither prepare or finalize. Examine item as current level.
       
  1086         const TTransitionStackEntry& level = *(stack->Head()); // Peek
       
  1087 
       
  1088         TUid newLevelUid = iPlan[i]->Plugin().ParentUid();
       
  1089 
       
  1090         // Case 3
       
  1091         if ( newLevelUid == level.iLevelUid )
       
  1092             {
       
  1093             // still in the same suite level.  No need to add new items.
       
  1094 
       
  1095             // check if current item is non-dependent.
       
  1096             // If so, update the iAsDependent to reflect that it includes
       
  1097             // a non-dependent item.
       
  1098             if ( !(iPlan[i]->AsDependency()) )
       
  1099                 {
       
  1100                 // update the prepare item, indicating that it has
       
  1101                 // an non-dependent item
       
  1102                 iPlan[level.iPrepareIndex]->SetAsDependency( EFalse );
       
  1103                 }
       
  1104             i++;
       
  1105             continue;   //lint !e960 : continue OK. examine next item.
       
  1106             }
       
  1107 
       
  1108         // If parent UID is differnt from current level uid, 
       
  1109         // it can mean one of the following:
       
  1110         //  A ) We are entering a new suite.
       
  1111         //  B ) We leaving a suite.
       
  1112         // Case B ) can be deteced by checking whether the new parent is 
       
  1113         // already in the stack somewhere (stack will be popped until we are
       
  1114         // in the same level), or if there is no more item of the same
       
  1115         // level is in the plan, which means it is not needed.
       
  1116         // If case B ) fails, assume case A.
       
  1117         if ( IsLevelInStack( *stack, newLevelUid ) ||
       
  1118              !IsThisSuiteNeededAfterThisIndex( stack->Head()->iLevelUid, i ) )
       
  1119             {
       
  1120             // Case B) Insert a new Finalize item.
       
  1121             AddSuiteFinalizeL( level.iPrepareIndex, i );
       
  1122             }
       
  1123         else
       
  1124             {
       
  1125             // Case A) Insert a new prepare item.
       
  1126             AddSuitePrepareL( newLevelUid, i );
       
  1127             }
       
  1128         }
       
  1129 
       
  1130     // When all done, stack must be empty.
       
  1131     __ASSERT_DEBUG( stack->IsEmpty(), Panic( EDiagFrameworkInternal ) );
       
  1132 
       
  1133     CleanupStack::PopAndDestroy( stack );
       
  1134     stack = NULL;
       
  1135     }
       
  1136 
       
  1137 // ---------------------------------------------------------------------------
       
  1138 // CDiagPluginExecPlanImpl::AddRootSuiteIfMissingL
       
  1139 // ---------------------------------------------------------------------------
       
  1140 //
       
  1141 void CDiagPluginExecPlanImpl::AddRootSuiteIfMissingL()
       
  1142     {
       
  1143     // Check to see if root element is already in the plan.
       
  1144     if ( iPlan[0]->Plugin().Uid() != KDiagRootSuiteUid )
       
  1145         {
       
  1146         // root( uid 0 ) does not exist in the plan.
       
  1147         // Add prepare and finalize root into the plan.
       
  1148         MDiagPlugin& rootPlugin = iEngine.PluginPool().FindPluginL( KDiagRootSuiteUid );
       
  1149 
       
  1150         CDiagExecPlanEntryImplSuite* rootEntry = 
       
  1151             CDiagExecPlanEntryImplSuite::NewLC(
       
  1152                 iEngine,
       
  1153                 iEngineConfig,
       
  1154                 iPlanEntryObserver,
       
  1155                 static_cast< MDiagSuitePlugin& >( rootPlugin ),
       
  1156                 ETrue,              // iAsDependent == ETrue. Updated as later.
       
  1157                 CDiagExecPlanEntryImpl::ETypeSuitePrepare );
       
  1158 
       
  1159         iPlan.InsertL( static_cast< CDiagExecPlanEntryImpl* >( rootEntry ), 0 );  
       
  1160         CleanupStack::Pop( rootEntry ); // ownership transferred above.
       
  1161         rootEntry = NULL;
       
  1162 
       
  1163         rootEntry = CDiagExecPlanEntryImplSuite::NewLC(
       
  1164             iEngine,
       
  1165             iEngineConfig,
       
  1166             iPlanEntryObserver,
       
  1167             static_cast< MDiagSuitePlugin& >( rootPlugin ),
       
  1168             ETrue,              // iAsDependent == ETrue. Updated as later.
       
  1169             CDiagExecPlanEntryImpl::ETypeSuiteFinalize );
       
  1170 
       
  1171         // insert same entry with finalize as type
       
  1172         iPlan.AppendL( static_cast< CDiagExecPlanEntryImpl* >( rootEntry ) );
       
  1173         CleanupStack::Pop( rootEntry ); // ownership transferred above
       
  1174         rootEntry = NULL;
       
  1175         }
       
  1176     }
       
  1177 
       
  1178 // ---------------------------------------------------------------------------
       
  1179 // CDiagPluginExecPlanImpl::PushNewLevelL
       
  1180 // ---------------------------------------------------------------------------
       
  1181 //
       
  1182 void CDiagPluginExecPlanImpl::PushNewLevelL( 
       
  1183         CStack<TTransitionStackEntry, ETrue>& aStack, 
       
  1184         TInt aHeadIndex )
       
  1185     {
       
  1186     TTransitionStackEntry* level = new( ELeave )TTransitionStackEntry;
       
  1187 
       
  1188     __ASSERT_ALWAYS( aHeadIndex >= 0 && aHeadIndex < iPlan.Count(),
       
  1189                      Panic( EDiagFrameworkInternal ) );
       
  1190 
       
  1191     level->iLevelUid = iPlan[aHeadIndex]->Plugin().Uid();
       
  1192     level->iPrepareIndex = aHeadIndex;
       
  1193 
       
  1194     #ifdef _DEBUG_EXEC_PLAN
       
  1195     LOGSTRING2( "CDiagPluginExecPlanImpl:: Push 0x%08x", level->iLevelUid.iUid )
       
  1196     #endif // _DEBUG_EXEC_PLAN
       
  1197 
       
  1198     aStack.PushL( level ); // owership transferred.
       
  1199     level = NULL; //lint !e423 Ownership transferred. No leak here.
       
  1200     }
       
  1201 
       
  1202 // ---------------------------------------------------------------------------
       
  1203 // CDiagPluginExecPlanImpl::PopLevel
       
  1204 // ---------------------------------------------------------------------------
       
  1205 //
       
  1206 void CDiagPluginExecPlanImpl::PopLevel( CStack<TTransitionStackEntry, ETrue>& aStack )
       
  1207     {
       
  1208     TTransitionStackEntry* level = aStack.Pop();
       
  1209     #ifdef _DEBUG_EXEC_PLAN
       
  1210     LOGSTRING2( "CDiagPluginExecPlanImpl:: Pop 0x%08x", level->iLevelUid.iUid )
       
  1211     #endif // _DEBUG_EXEC_PLAN
       
  1212     delete level;
       
  1213     level = NULL;
       
  1214     }
       
  1215 
       
  1216 // ---------------------------------------------------------------------------
       
  1217 // CDiagPluginExecPlanImpl::IsLevelInStack
       
  1218 // ---------------------------------------------------------------------------
       
  1219 //
       
  1220 TBool CDiagPluginExecPlanImpl::IsLevelInStack( 
       
  1221         CStack<TTransitionStackEntry, ETrue>& aStack,
       
  1222         TUid aLevelUid ) const
       
  1223     {
       
  1224     for ( TInt i = 0; i < aStack.Count(); i++ )
       
  1225         {
       
  1226         const TTransitionStackEntry& currEntry = *aStack[i];
       
  1227         if ( currEntry.iLevelUid == aLevelUid )
       
  1228             {
       
  1229             return ETrue;
       
  1230             }
       
  1231         }
       
  1232 
       
  1233     return EFalse;
       
  1234     }
       
  1235 
       
  1236 // ---------------------------------------------------------------------------
       
  1237 // CDiagPluginExecPlanImpl::IsThisSuiteNeededAfterThisIndex
       
  1238 // ---------------------------------------------------------------------------
       
  1239 //
       
  1240 TBool CDiagPluginExecPlanImpl::IsThisSuiteNeededAfterThisIndex(
       
  1241         TUid aSuiteUid,
       
  1242         TInt aIndex ) const
       
  1243     {
       
  1244     for ( TInt i = aIndex; i < iPlan.Count(); i++ )
       
  1245         {
       
  1246         if ( iPlan[i]->Plugin().Uid() == aSuiteUid ||  // finalize already exists
       
  1247              iPlan[i]->Plugin().ParentUid() == aSuiteUid )
       
  1248             {
       
  1249             return ETrue;
       
  1250             }
       
  1251         }
       
  1252 
       
  1253     return EFalse;
       
  1254     }
       
  1255 
       
  1256 // ---------------------------------------------------------------------------
       
  1257 // CDiagPluginExecPlanImpl::AddSuitePrepareL
       
  1258 // ---------------------------------------------------------------------------
       
  1259 //
       
  1260 void CDiagPluginExecPlanImpl::AddSuitePrepareL( TUid aLevelUid, TInt aAt )
       
  1261     {
       
  1262     MDiagPlugin& suitePlugin = iEngine.PluginPool().FindPluginL( aLevelUid );
       
  1263 
       
  1264     CDiagExecPlanEntryImplSuite* prepareEntry =
       
  1265         CDiagExecPlanEntryImplSuite::NewLC( 
       
  1266             iEngine,
       
  1267             iEngineConfig,
       
  1268             iPlanEntryObserver,
       
  1269             static_cast< MDiagSuitePlugin& >( suitePlugin ),
       
  1270             ETrue, // iAsDependent. Updated as later if not true.
       
  1271             CDiagExecPlanEntryImpl::ETypeSuitePrepare );
       
  1272 
       
  1273     iPlan.InsertL( static_cast< CDiagExecPlanEntryImpl* >( prepareEntry ), aAt );
       
  1274     CleanupStack::Pop( prepareEntry ); // ownership transfer
       
  1275     prepareEntry = NULL;
       
  1276 
       
  1277     #ifdef _DEBUG_EXEC_PLAN
       
  1278     LOGSTRING2( "CDiagPluginExecPlanImpl:: InsertPrepare 0x%08x", aLevelUid )
       
  1279     #endif // _DEBUG_EXEC_PLAN
       
  1280     }
       
  1281 
       
  1282 // ---------------------------------------------------------------------------
       
  1283 // CDiagPluginExecPlanImpl::AddSuiteFinalizeL
       
  1284 // ---------------------------------------------------------------------------
       
  1285 //
       
  1286 void CDiagPluginExecPlanImpl::AddSuiteFinalizeL( TInt aPrepareIndex, TInt aAt )
       
  1287     {
       
  1288     // It is identical to the prepare entry, except that type is ETypeSuiteFinalize
       
  1289     __ASSERT_ALWAYS( aPrepareIndex >= 0 && aPrepareIndex < iPlan.Count(),
       
  1290                      Panic( EDiagFrameworkInternal ) );
       
  1291 
       
  1292     CDiagExecPlanEntryImplSuite& prepareEntry = 
       
  1293         static_cast< CDiagExecPlanEntryImplSuite& > ( *(iPlan[aPrepareIndex]) );
       
  1294 
       
  1295     CDiagExecPlanEntryImplSuite* finalizeEntry = 
       
  1296         CDiagExecPlanEntryImplSuite::NewLC( 
       
  1297             iEngine,
       
  1298             iEngineConfig,
       
  1299             iPlanEntryObserver,
       
  1300             prepareEntry.SuitePlugin(),
       
  1301             prepareEntry.AsDependency(),
       
  1302             CDiagExecPlanEntryImpl::ETypeSuiteFinalize );
       
  1303 
       
  1304     iPlan.InsertL( static_cast< CDiagExecPlanEntryImpl* >( finalizeEntry ), aAt );
       
  1305     CleanupStack::Pop( finalizeEntry );  // ownership transmitted above
       
  1306     finalizeEntry = NULL;
       
  1307 
       
  1308     #ifdef _DEBUG_EXEC_PLAN
       
  1309     LOGSTRING2( "CDiagPluginExecPlanImpl:: InsertFinalize 0x%08x", prepareEntry.Plugin().Uid().iUid );
       
  1310     #endif // _DEBUG_EXEC_PLAN
       
  1311     }
       
  1312 
       
  1313 // ---------------------------------------------------------------------------
       
  1314 // CDiagPluginExecPlanImpl::StoreNextTestPluginToDbL
       
  1315 // ---------------------------------------------------------------------------
       
  1316 //
       
  1317 void CDiagPluginExecPlanImpl::StoreNextTestPluginToDbL()
       
  1318     {
       
  1319     // STEP_6. Store plan to DB. 
       
  1320     // In this step, all test entries must be stored in db with EQueuedToRun
       
  1321     // status. Since DbRecord().LogTestResult() is an async call, only one
       
  1322     // item can be written at a time. 
       
  1323     //
       
  1324     // To do this, this function will search for the next "TEST" plug-in that
       
  1325     // needs to be logged to DB. Once it is found, it will call async function
       
  1326     // LogTestResult() and wait for RunL() to execute again.
       
  1327     // In RunL(), StoreNextTestPluginToDbL() is called again, and it will look for the
       
  1328     // next test plugin to store until it loops through all items in plan.
       
  1329     while ( MoveCursorToNext() )
       
  1330         {
       
  1331         if ( CurrentExecutionItem().Plugin().Type() == MDiagPlugin::ETypeTestPlugin )
       
  1332             {
       
  1333             LOGSTRING2( "CDiagPluginExecPlanImpl::RunL: STEP_6 - storing item 0x%08x",
       
  1334                 CurrentExecutionItem().Plugin().Uid().iUid )
       
  1335 
       
  1336             CDiagResultsDatabaseItem* resultItem = 
       
  1337                 CDiagResultsDbItemBuilder::CreateSimpleDbItemL( 
       
  1338                     CurrentExecutionItem().Plugin().Uid(),
       
  1339                     CurrentExecutionItem().AsDependency(),
       
  1340                     CDiagResultsDatabaseItem::EQueuedToRun );
       
  1341 
       
  1342             // Record initial test result to db.
       
  1343             // StoreNextTestPluginToDbL() will be called again later from RunL()
       
  1344             iEngine.DbRecord().LogTestResult( iStatus, *resultItem );
       
  1345             SetActive();
       
  1346 
       
  1347             delete resultItem;
       
  1348             resultItem = NULL;
       
  1349 
       
  1350             // Exit here since we must wait for LogTestResult() to complete
       
  1351             // before moving on to the next item.
       
  1352             return;
       
  1353             }
       
  1354         }
       
  1355 
       
  1356     // All items are stored now.
       
  1357     ChangeState( EStatePlanCreated );
       
  1358     }
       
  1359 
       
  1360 // ---------------------------------------------------------------------------
       
  1361 // CDiagPluginExecPlanImpl::PrependExecutedItemsL
       
  1362 // ---------------------------------------------------------------------------
       
  1363 //
       
  1364 void CDiagPluginExecPlanImpl::PrependExecutedItemsL()
       
  1365     {
       
  1366     #ifdef _DEBUG_EXEC_PLAN
       
  1367     LOGSTRING( "CDiagExecPlanEntryImpl::PrependExecutedItemsL(). "
       
  1368         L" Before prepending executed entries" );
       
  1369     LogPlanL();
       
  1370     #endif // _DEBUG_EXEC_PLAN
       
  1371 
       
  1372     for ( TInt lastIndex = iExecutedEntries.Count() - 1;
       
  1373           lastIndex >= 0 ;
       
  1374           lastIndex-- )
       
  1375         {
       
  1376         // Insert last entry from the executed list to the beginning.
       
  1377         iPlan.InsertL( iExecutedEntries[ lastIndex ], 0 );
       
  1378         iExecutedEntries.Remove( lastIndex );
       
  1379         }
       
  1380     }
       
  1381 
       
  1382 // ---------------------------------------------------------------------------
       
  1383 // CDiagPluginExecPlanImpl::ReportResult
       
  1384 // ---------------------------------------------------------------------------
       
  1385 //
       
  1386 void CDiagPluginExecPlanImpl::ReportResult( TInt aError )
       
  1387     {
       
  1388     User::RequestComplete( iClientStatus, aError );
       
  1389     iClientStatus = NULL;
       
  1390     }
       
  1391 
       
  1392 // ---------------------------------------------------------------------------
       
  1393 // CDiagPluginExecPlanImpl::InsertPluginL
       
  1394 // ---------------------------------------------------------------------------
       
  1395 //
       
  1396 TBool CDiagPluginExecPlanImpl::InsertPluginL( MDiagPlugin& aPlugin,
       
  1397                                               TBool aAsDependency,
       
  1398                                               TInt aAt )
       
  1399     {
       
  1400     #ifdef _DEBUG_EXEC_PLAN
       
  1401     LOGSTRING4( "CDiagPluginExecPlanImpl::InsertPluginL:"
       
  1402             L"Id = 0x%x, Type = %s, At %d", 
       
  1403             aPlugin.Uid().iUid,  
       
  1404             ( aPlugin.Type() == MDiagPlugin::ETypeTestPlugin ? L"Test" : L"Suite" ),
       
  1405             aAt )
       
  1406     #endif // _DEBUG_EXEC_PLAN
       
  1407 
       
  1408     __ASSERT_ALWAYS( aAt >= 0 && aAt <= iPlan.Count(), Panic( EDiagFrameworkArrayBounds ) );
       
  1409 
       
  1410     // First, examine items before given index.
       
  1411     // If new item has iAsDependent == ETrue, and also found before the given index,
       
  1412     //   --> it is okay to not insert the item, since it will just be duplicates.
       
  1413     // if new item has iAsDependent == EFalse, 
       
  1414     //   --> no need to check for items prior to current position, since
       
  1415     //   explicit
       
  1416     // where it was requested.
       
  1417     TInt idx = 0;
       
  1418     if ( aAsDependency )
       
  1419         {
       
  1420         // check if it was already executed in the previous session.
       
  1421         for ( idx = 0; idx < iExecutedEntries.Count(); idx++ )
       
  1422             {
       
  1423             if ( iExecutedEntries[idx]->Plugin().Uid() == aPlugin.Uid() )
       
  1424                 {
       
  1425                 // matching item found.
       
  1426                 // No need to instert a new item.
       
  1427                 return EFalse;
       
  1428                 }
       
  1429             }
       
  1430 
       
  1431         // check for items in current plan.
       
  1432         for ( idx = 0; idx < aAt && idx < iPlan.Count(); idx++ )
       
  1433             {
       
  1434             if ( iPlan[idx]->Plugin().Uid() == aPlugin.Uid() )
       
  1435                 {
       
  1436                 // Matching item found. 
       
  1437                 // No change to plan made.
       
  1438                 return EFalse;
       
  1439                 }
       
  1440             }
       
  1441         }
       
  1442 
       
  1443     // Duplicate item not found before given index.
       
  1444     // An item will be inserted at the given index. Now, we search for
       
  1445     // duplicates after current index, and see if we can remove them.
       
  1446     idx = aAt;
       
  1447     while ( idx < iPlan.Count() )
       
  1448         {
       
  1449         if ( iPlan[idx]->Plugin().Uid() == aPlugin.Uid() && iPlan[idx]->AsDependency() )
       
  1450             {
       
  1451             // Item is found, and it was for dependency.
       
  1452             // We can move this item to current position. 
       
  1453             // For now, we just need to remove it, since it will be added at
       
  1454             // current position when for loop is done.
       
  1455             CDiagExecPlanEntryImpl* entry = iPlan[idx];
       
  1456             iPlan.Remove( idx );
       
  1457             delete entry;
       
  1458             entry = NULL;
       
  1459 
       
  1460             // no need to increment idx, since current item is removed.
       
  1461             // idx should already be at the next item.
       
  1462             }
       
  1463         else
       
  1464             {
       
  1465             idx++;     // check next item.
       
  1466             }
       
  1467         }
       
  1468 
       
  1469     // Either plug-in is not found, or we found one that we can move.
       
  1470     // Add to current position.
       
  1471     CDiagExecPlanEntryImpl* newEntry = CreateDefaultPlanEntryLC(
       
  1472         aPlugin,
       
  1473         aAsDependency );
       
  1474 
       
  1475     iPlan.InsertL( newEntry, aAt );
       
  1476     CleanupStack::Pop( newEntry );
       
  1477     newEntry = NULL;
       
  1478 
       
  1479     return ETrue;
       
  1480     }
       
  1481 
       
  1482 // ---------------------------------------------------------------------------
       
  1483 // CDiagPluginExecPlanImpl::CreateDefaultPlanEntryL
       
  1484 //
       
  1485 // ---------------------------------------------------------------------------
       
  1486 //
       
  1487 CDiagExecPlanEntryImpl* CDiagPluginExecPlanImpl::CreateDefaultPlanEntryLC(
       
  1488         MDiagPlugin& aPlugin,
       
  1489         TBool aAsDependency ) const
       
  1490     {
       
  1491     CDiagExecPlanEntryImpl* newEntry = NULL;
       
  1492 
       
  1493     if ( aPlugin.Type() == MDiagPlugin::ETypeTestPlugin )
       
  1494         {
       
  1495         newEntry = static_cast< CDiagExecPlanEntryImpl* >(
       
  1496             CDiagExecPlanEntryImplTest::NewLC(
       
  1497                 iEngine,
       
  1498                 iEngineConfig,
       
  1499                 iPlanEntryObserver,
       
  1500                 static_cast< MDiagTestPlugin& >( aPlugin ),
       
  1501                 aAsDependency,
       
  1502                 CDiagResultsDatabaseItem::EQueuedToRun ) );
       
  1503         }
       
  1504     else
       
  1505         {
       
  1506         newEntry = static_cast< CDiagExecPlanEntryImpl* >(
       
  1507             CDiagExecPlanEntryImplSuite::NewLC(
       
  1508                 iEngine,
       
  1509                 iEngineConfig,
       
  1510                 iPlanEntryObserver,
       
  1511                 static_cast< MDiagSuitePlugin& >( aPlugin ),
       
  1512                 aAsDependency,
       
  1513                 CDiagExecPlanEntryImpl::ETypeSuiteUnexpanded ) );
       
  1514         }
       
  1515 
       
  1516     return newEntry;
       
  1517     }
       
  1518 
       
  1519 // ---------------------------------------------------------------------------
       
  1520 // CDiagPluginExecPlanImpl::LogPlan
       
  1521 // ---------------------------------------------------------------------------
       
  1522 //
       
  1523 void CDiagPluginExecPlanImpl::LogPlanL() const
       
  1524     {
       
  1525     #ifdef _DEBUG
       
  1526     LOGSTRING( "CDiagPluginExecPlanImpl::LogPlan(): Plan Dump." )
       
  1527     for ( TInt i = 0; i < iPlan.Count(); i++ )
       
  1528         {            
       
  1529         HBufC* pluginName = iPlan[i]->Plugin().GetPluginNameL( 
       
  1530             MDiagPlugin::ENameLayoutListSingle );
       
  1531 
       
  1532         LOGSTRING5( "Plan Entry: Id = 0x%08x, %s, Dep=[%s], Name = %S",
       
  1533             iPlan[i]->Plugin().Uid().iUid,  
       
  1534             ( iPlan[i]->Type() == CDiagExecPlanEntryImpl::ETypeSuitePrepare ? L"<" : 
       
  1535                 ( iPlan[i]->Type() == CDiagExecPlanEntryImpl::ETypeSuiteFinalize ? L">" : L" " ) ),
       
  1536             ( iPlan[i]->AsDependency() ? L"*" : L" " ),
       
  1537             pluginName )
       
  1538 
       
  1539         delete pluginName;
       
  1540         }
       
  1541     #endif // _DEBUG
       
  1542     }
       
  1543 
       
  1544 // ---------------------------------------------------------------------------
       
  1545 // CDiagPluginExecPlanImpl::LogPlanInRecordL
       
  1546 // ---------------------------------------------------------------------------
       
  1547 //
       
  1548 void CDiagPluginExecPlanImpl::LogPlanInRecordL() const
       
  1549     {
       
  1550     #ifdef _DEBUG
       
  1551 
       
  1552     LOGSTRING( "CDiagPluginExecPlanImpl::LogPlanInRecord()" )
       
  1553 
       
  1554     RPointerArray< CDiagResultsDatabaseItem > results;
       
  1555     DiagFwInternal::CleanupRPointerArrayPushL< CDiagResultsDatabaseItem >( &results );
       
  1556     User::LeaveIfError(
       
  1557         iEngine.DbRecord().GetTestResults( results ) );
       
  1558 
       
  1559     TInt resultCount = results.Count();
       
  1560 
       
  1561     LOGSTRING2( "  Result Count = %d", resultCount )
       
  1562 
       
  1563     for ( TInt i = 0; i < resultCount; i++ )
       
  1564         {
       
  1565         LOGSTRING4( "   Test UID = 0x%08x, Result = %d, Dep = %d", 
       
  1566             results[i]->TestUid().iUid,
       
  1567             results[i]->TestResult(),
       
  1568             results[i]->WasDependency() )
       
  1569         }
       
  1570 
       
  1571     CleanupStack::PopAndDestroy( &results );
       
  1572 
       
  1573     #endif // _DEBUG
       
  1574     }
       
  1575 
       
  1576 // End of File
       
  1577