devicediagnosticsfw/diagframework/src/diagpluginpoolimpl.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:27:42 +0100
branchRCL_3
changeset 26 19bba8228ff0
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* 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:  Implementation of Diagnostics Plug-in Pool
*
*/


// CLASS DECLARATION
#include "diagpluginpoolimpl.h"

// SYSTEM INCLUDE FILES
#include <ecom.h>
#include <DiagPlugin.h>
#include <DiagPluginPoolObserver.h>
#include <DiagPluginConstructionParam.h>
#include <DiagPluginPoolObserver.h>
#include <DiagFrameworkDebug.h>
#include <mmf/common/mmfcontrollerpluginresolver.h> // CleanupResetAndDestroyPushL

// USER INCLUDE FILES
#include "diagpluginloaderdependencyparser.h"
#include "diagrootsuite.h"

using namespace DiagPluginPool;
using namespace DiagFwInternal;

_LIT( KPanicCode, "PluginPool" );

// ===========================================================================
// PUBLIC MEMBER FUNCTIONS
// ===========================================================================    

// ---------------------------------------------------------------------------
// NewL
// ---------------------------------------------------------------------------
//
CDiagPluginPoolImpl* CDiagPluginPoolImpl::NewL( MDiagPluginPoolObserver& aObserver )
    {
    LOGSTRING("");
    CDiagPluginPoolImpl* self = CDiagPluginPoolImpl::NewLC( aObserver );
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// NewLC
// ---------------------------------------------------------------------------
//
CDiagPluginPoolImpl* CDiagPluginPoolImpl::NewLC( MDiagPluginPoolObserver& aObserver )
    {
    CDiagPluginPoolImpl* self = new( ELeave )CDiagPluginPoolImpl( aObserver );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }        

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CDiagPluginPoolImpl::~CDiagPluginPoolImpl()
    {
    LOGSTRING("");
    Cancel();
    iPlugins.ResetAndDestroy();
    iPlugins.Close();
    REComSession::FinalClose();
    }
    
// ---------------------------------------------------------------------------
// LoadAsyncL
// ---------------------------------------------------------------------------
//
void CDiagPluginPoolImpl::LoadAsyncL()
    {
    LOGSTRING( "CDiagPluginPoolImpl::LoadAsyncL" )

    ASSERT ( !iPluginsLoaded );
    ASSERT ( !iPluginsLoading );

    iPluginsLoading = ETrue;       
       
    iConstructionParamArray = GeneratePluginListL();
    
    iTotalPluginsFound = iConstructionParamArray->Count();

    // No plug-ins found
    if ( ! iTotalPluginsFound )
        {
        DestroyConstructionParams();
        User::Leave( KErrNotFound );
        }                
            
    // Create root suite to define the hierarchy
    MDiagSuitePlugin* rootSuite = CDiagRootSuite::NewL();    
    CleanupStack::PushL( rootSuite );
    iPlugins.AppendL( rootSuite ); // ownership transfered        
    CleanupStack::Pop( rootSuite );

    SetNextIteration();
    }
    
// ---------------------------------------------------------------------------
// CreatePluginL
// ---------------------------------------------------------------------------
//
MDiagPlugin* CDiagPluginPoolImpl::CreatePluginL( const TUid aUid )
    {
    TInt errorCode = KErrNone;

    LOGSTRING2( "CDiagPluginPoolImpl::CreatePluginL %d\n", aUid.iUid )

    // Create construction parameters list
    RConstructionParamArray* constructionParamsArray = GeneratePluginListL();
    CleanupStack::PushL( constructionParamsArray );
    CleanupResetAndDestroyPushL( *constructionParamsArray );
    
    MDiagPlugin* plugin = NULL;
    
    // Find plug-in with matching UID        
    for ( TInt i=0; i<constructionParamsArray->Count(); i++ )
        {
        if ( ( *constructionParamsArray )[i]->Uid() == aUid )
            {            
            plugin = CreatePluginFromConstructionParamsL( ( *constructionParamsArray )[i] );
            
            // Construction params owned by plug-in so remove from list
            constructionParamsArray->Remove(i);
            break;  //lint !e960 ok to break from for loop     
            }
        }
        
    if ( ! plugin )
        {                
        errorCode = KErrNotFound;                
        }
       
    CleanupStack::PopAndDestroy();        // *implInfoArray
    CleanupStack::PopAndDestroy( constructionParamsArray );
    
    User::LeaveIfError( errorCode );
        
    return plugin;    
    }

// ---------------------------------------------------------------------------
// FindPlugin
// ---------------------------------------------------------------------------
//
TInt CDiagPluginPoolImpl::FindPlugin( TUid aUid, MDiagPlugin*& aPlugin ) const
    {
    LOGSTRING2( "CDiagPluginPoolImpl::FindPlugin 0x%x\n", aUid.iUid )

    aPlugin = NULL;

    // Find plug-in with matching UID in pool
    for ( TInt i=0; i<iPlugins.Count(); i++ )
        {           
        if ( iPlugins[i]->Uid() == aUid )           
            {
            aPlugin = iPlugins[i];            
            return KErrNone;
            }
        }
        
    return KErrNotFound;        
    }

// ---------------------------------------------------------------------------
// FindPlugin
// ---------------------------------------------------------------------------
//
TInt CDiagPluginPoolImpl::FindPlugin( const TDesC& aServiceName,
                                        MDiagPlugin *& aPlugin ) const
    {    
    LOGSTRING2( "CDiagPluginPoolImpl::FindPlugin \"%S\"\n", &aServiceName )

    aPlugin = NULL;
    
    // Find plug-in with matching service name in pool
    for ( TInt i=0; i<iPlugins.Count(); i++ )
        {           
        if ( iPlugins[i]->ServiceLogicalName() == aServiceName )           
            {
            aPlugin = iPlugins[i];            
            return KErrNone;
            }
        }
        
    return KErrNotFound;
    }


// ===========================================================================
// PRIVATE CONSTRUCTORS
// ===========================================================================

// ---------------------------------------------------------------------------
// CDiagPluginPool
// ---------------------------------------------------------------------------
//
CDiagPluginPoolImpl::CDiagPluginPoolImpl( MDiagPluginPoolObserver& aObserver )
        // Priority is idle to allow plug-ins to load in background regardless of
        // what UI priority is set to.
    :   CActive( EPriorityIdle ),
        iObserver( aObserver ),
        iErrorCode( KErrNone )
    {
    }


// ---------------------------------------------------------------------------
// ConstructL
// ---------------------------------------------------------------------------
//
void CDiagPluginPoolImpl::ConstructL()
    {
    CActiveScheduler::Add( this );
    }        
    

// ===========================================================================
// PRIVATE STATIC FUNCTIONS
// ===========================================================================

// ---------------------------------------------------------------------------
// ObtainImplementationInfoL
// ---------------------------------------------------------------------------
//
CDiagPluginPoolImpl::RConstructionParamArray* CDiagPluginPoolImpl::GeneratePluginListL()
    {     

    // Get list of plug-in implementation implementationInfo
    RImplInfoPtrArray* implInfoArray = new( ELeave )RImplInfoPtrArray;
    
    REComSession::ListImplementationsL( KDiagPluginInterfaceUid, *implInfoArray );
        
    // Leave if no matching plug-ins found        
    if ( ! implInfoArray->Count() )
        {
        delete implInfoArray;
        User::Leave( KErrNotFound );
        }
        
    CleanupStack::PushL( implInfoArray );
    CleanupResetAndDestroyPushL( *implInfoArray );         
        
    RConstructionParamArray* constructionParamsArray = new(ELeave)RConstructionParamArray;
    CleanupStack::PushL( constructionParamsArray );
    CleanupResetAndDestroyPushL( *constructionParamsArray );
    CDependencyParser* parser = CDependencyParser::NewLC();
    
    // Iterate through implementation information array and create construction data for each
    // plug-in.  Insert into array by order number.
    for ( TInt pluginIndex=0; pluginIndex < implInfoArray->Count(); pluginIndex++ )
        {
        CImplementationInformation* pluginImplementationInfo = ( *implInfoArray )[pluginIndex];

        if ( !pluginImplementationInfo->RomBased() )
            {
#ifdef _DEBUG
            LOGSTRING2( "CDiagPluginPoolImpl::GeneratePluginListL() "
                L" Loading non-rom plug-in 0x%08x", 
                pluginImplementationInfo->ImplementationUid() );
#else   // #ifdef _DEBUG
            // In non _DEBUG build, do not load plug-in that are not in ROM
            // for security reasons. Continue to next plug-in.
            //continue;
#endif  // #else _DEBUG
            }

        // Obtain depenency and other information from opaque data field
        parser->ParseL( pluginImplementationInfo->OpaqueData(), 
                        pluginImplementationInfo->DataType() );
        
        CDiagPluginConstructionParam* constructionParams = 
            GenerateConstructionParamsLC( pluginImplementationInfo );
                
        TInt orderNumber = constructionParams->Order();        
        
        // Find correct index to insert plug-in
        TInt insertIndex;
        for ( insertIndex=0; insertIndex<constructionParamsArray->Count(); insertIndex++ )
            {
            if ( orderNumber < (*constructionParamsArray)[insertIndex]->Order() )
                {                
                break;    //lint !e960 break OK here.
                }
            } 
                        
        // Insert in order by order number
        constructionParamsArray->InsertL(constructionParams,insertIndex);            
        CleanupStack::Pop(constructionParams);
        }
                    
    // Clean up                    
    CleanupStack::PopAndDestroy(parser);              
    CleanupStack::Pop(); // constructionParamsArray
    CleanupStack::Pop(constructionParamsArray);            
    CleanupStack::PopAndDestroy(); // implInfoArray
    CleanupStack::PopAndDestroy(implInfoArray);                  
        
    return constructionParamsArray;
    }
    
// ---------------------------------------------------------------------------
// GenerateConstructionParamsL
// ---------------------------------------------------------------------------
//     
CDiagPluginConstructionParam* CDiagPluginPoolImpl::GenerateConstructionParamsLC(
                                    const CImplementationInformation* aInfo )
    {
    CDependencyParser* parser = CDependencyParser::NewLC();
    
    // Obtain depenency and other information from opaque data field
    parser->ParseL( aInfo->OpaqueData(), aInfo->DataType() );
    
    CDiagPluginConstructionParam* params = CDiagPluginConstructionParam::NewL
                                    (
                                    parser->GetServiceProvided(),
                                    parser->GetServicesRequired(),
                                    parser->GetOrderNumber(),
                                    aInfo->ImplementationUid(),
                                    parser->GetParentUid()
                                    );
        
    CleanupStack::PopAndDestroy( parser );
    CleanupStack::PushL( params );
    
    return params;
    }

// ---------------------------------------------------------------------------
// CreatePluginFromImplementationInfoL
// ---------------------------------------------------------------------------
//    
MDiagPlugin* CDiagPluginPoolImpl::CreatePluginFromConstructionParamsL(
                                    const CDiagPluginConstructionParam* aParams )
    {    
    MDiagPlugin* newPlugin = NULL;
    TUid destructorIdKey;

    // Call ECOM to load next plug-in
    TAny* object = REComSession::CreateImplementationL( aParams->Uid(), 
                                                        destructorIdKey, 
                                                        ( TAny* )aParams );
    if (!object)
    User::Leave(KErrNotFound);
    
    newPlugin = static_cast<MDiagPlugin*>( object );
    newPlugin->SetDtorIdKey( destructorIdKey );
    return newPlugin;
    }           
    
// ===========================================================================
// PRIVATE MEMBER FUNCTIONS
// ===========================================================================

// ---------------------------------------------------------------------------
// AddNewPluginToSuiteL
// ---------------------------------------------------------------------------
//
void CDiagPluginPoolImpl::AddNewPluginToSuiteL(MDiagPlugin* aPlugin)
    {
    // Search the plug-in list for a matching suite plug-in and add this newly
    // loaded plug-in to that corresponding suite.  If a suite is not found,
    // this plug-in will have no parent unless the parent suite is loaded
    // at some later point.
    for ( TInt pluginIndex = 0; pluginIndex < iPlugins.Count(); pluginIndex++ )
        {
        
        // Find matching parent suite
        if ( aPlugin->ParentUid() == iPlugins[pluginIndex]->Uid() )
            {               
            if ( iPlugins[pluginIndex]->Type() == MDiagPlugin::ETypeSuitePlugin )
                {
                // If parent is a suite, add child         
                MDiagSuitePlugin* parent = static_cast<MDiagSuitePlugin*>( iPlugins[pluginIndex] );
                
                parent->AddChildL( aPlugin );
                return;
                }
            else
                {
                // if parent is not a suite, leave
                User::Leave( KErrCorrupt );
                }
            }            
        }   
    }
    
// ---------------------------------------------------------------------------
// AddPluginsToNewSuiteL
// ---------------------------------------------------------------------------
//    
void CDiagPluginPoolImpl::AddPluginsToNewSuiteL(MDiagSuitePlugin* aPluginSuite)
    {        
    // Search the plug-in list for plug-ins with matching parent suite.
    for ( TInt pluginIndex = 0; pluginIndex < iPlugins.Count(); pluginIndex++ )
        {        
        // Add any "orphan" plug-ins
        if ( aPluginSuite->Uid() == iPlugins[pluginIndex]->ParentUid() )
            {                                      
            aPluginSuite->AddChildL( iPlugins[pluginIndex] );                      
            }            
        }   
    }    

// ---------------------------------------------------------------------------
// SetNextIteration
// ---------------------------------------------------------------------------
//
void CDiagPluginPoolImpl::SetNextIteration()
    {
    TRequestStatus* status = &iStatus;
    
    // Complete own request
    User::RequestComplete( status, KErrNone );    
    SetActive();
    }
    
// ---------------------------------------------------------------------------
// LoadNextPlugin
// ---------------------------------------------------------------------------
//    
void CDiagPluginPoolImpl::LoadNextPluginL()
    {
    // Get parameters to generate plug-in
    CDiagPluginConstructionParam* constructionParams = ( *iConstructionParamArray )[ 0 ];
    iCurrentPluginIndex++;
    MDiagPlugin* newPlugin = NULL;
    
    // Uid to report to application, defaults to NULL.
    TUid reportedUid = TUid::Null();

    // Create plug-in from ECOM structure
    // Any parsing or ECOM error will be caught here
    TRAPD( error, newPlugin = CreatePluginFromConstructionParamsL( constructionParams ) )
        
    // Construction params are now owned by plug-in so remove from array
    iConstructionParamArray->Remove( 0 );        

    LOGSTRING4( "CDiagPluginPoolImpl::LoadNextPluginL Plugin( %d/%d ): Error=%d\n",
                iCurrentPluginIndex, iTotalPluginsFound, error )
                                                          
    // Check for error in plug-in creation                
    if ( error != KErrNone )
        {        
        if ( iErrorCode == KErrNone )
            {
            // Sets error code to whatever was the first error encountered        
            iErrorCode = error;
            }                     
        }
    else
        {
        
        CleanupDeletePushL( newPlugin );
        
        // Add to plug-in pool
        reportedUid = AddPluginToPoolLD( newPlugin );
        newPlugin = NULL;
        }

    // Load is not complete
    if ( iConstructionParamArray->Count() )
        {        
        
        // Set next plug-in to load in next active scheduler cycle
        SetNextIteration();
        
        // Report progress to client
        iObserver.LoadProgressL( iCurrentPluginIndex, iTotalPluginsFound, reportedUid );
        }
        
    // Load is complete        
    else
        {
        // Report load completed to client
        iPluginsLoading = EFalse;
        iPluginsLoaded = ETrue;

        iObserver.LoadCompletedL( iErrorCode );

        // Don't need implementation implementationInfo list anymore
        DestroyConstructionParams();
        }
    }

// ---------------------------------------------------------------------------
// DestroyConstructionParams
// ---------------------------------------------------------------------------
//    
TUid CDiagPluginPoolImpl::AddPluginToPoolLD( MDiagPlugin* aPlugin )
    {
    
    TUid reportedUid = TUid::Null();
    
    // Add plug-in to list
    if ( aPlugin->IsSupported() )
        {
        iPlugins.AppendL( aPlugin );
        
        // Indicate to client that a plug-in was loaded with this UID
        reportedUid = aPlugin->Uid();
        
        // Update suite tree.  If this is a plug-in, try to find parent
        // suite and add.  If this is a suite, try to find child plug-ins
        // and add them.            
        AddNewPluginToSuiteL(aPlugin);
        
        if ( aPlugin->Type() == MDiagPlugin::ETypeSuitePlugin )
            {
            MDiagSuitePlugin* pluginSuite = 
                    static_cast<MDiagSuitePlugin*>(aPlugin);
            AddPluginsToNewSuiteL( pluginSuite );
            }            
        
        CleanupStack::Pop();    // aPlugin        
        }
    else
        {
        LOGSTRING2( " Plugin UID 0x%x NOT SUPPORTED. Skipped", aPlugin->Uid().iUid )
        CleanupStack::PopAndDestroy(); // aPlugin        
        }
        
    return reportedUid;        
    }
    
// ---------------------------------------------------------------------------
// DestroyConstructionParams
// ---------------------------------------------------------------------------
// 
void CDiagPluginPoolImpl::DestroyConstructionParams( )
    {
    if ( iConstructionParamArray )
        {
        iConstructionParamArray->ResetAndDestroy();
        delete iConstructionParamArray;
        iConstructionParamArray = NULL;
        }
    }
    
// ---------------------------------------------------------------------------
// ResetAndNotify
// ---------------------------------------------------------------------------
//
TInt CDiagPluginPoolImpl::ResetAndNotify(TInt aErrorCode)
    {
    // Reset load data
    iCurrentPluginIndex = 0;
    iPlugins.ResetAndDestroy();

    iPluginsLoading = EFalse;

    // Reset and delete implementation implementationInfo array
    DestroyConstructionParams();

    TRAPD( error, iObserver.LoadCompletedL( aErrorCode ) )
    
    return error;
    }

    

// ===========================================================================
// From CActive
// ===========================================================================

// ---------------------------------------------------------------------------
// RunL
// ---------------------------------------------------------------------------
//
void CDiagPluginPoolImpl::RunL()
    {
    // Load a plug-in in active scheduler cycle
    LoadNextPluginL();
    }

// ---------------------------------------------------------------------------
// DoCancel
// ---------------------------------------------------------------------------
//
void CDiagPluginPoolImpl::DoCancel()
    {   
    LOGSTRING( "CDiagPluginPoolImpl::DoCancel" )
    
    TInt error = ResetAndNotify(KErrCancel);

    // Reset load data
    if ( error )
        {
        User::Panic( KPanicCode(), error );
        }
    }

// ---------------------------------------------------------------------------
// RunError
// ---------------------------------------------------------------------------
//
TInt CDiagPluginPoolImpl::RunError( TInt aError )
    {
    // An unhandled exception occurs while running.  Destroy all currently
    // loaded plug-ins.

    LOGSTRING2( "CDiagPluginPoolImpl::RunError %d", aError )

    TInt err = ResetAndNotify( aError );
    LOGSTRING2( "CDiagPluginPoolImpl::RunError %d", err )
    
    return KErrNone;
    }
    
// End of File