diff -r 000000000000 -r b497e44ab2fc devicediagnosticsfw/diagframework/src/diagpluginpoolimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devicediagnosticsfw/diagframework/src/diagpluginpoolimpl.cpp Thu Dec 17 09:07:52 2009 +0200 @@ -0,0 +1,623 @@ +/* +* 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 +#include +#include +#include +#include +#include +#include // 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; iCount(); 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; iUid() == 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; iServiceLogicalName() == 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; insertIndexCount(); 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( 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( 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(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 ) + + return ResetAndNotify( aError ); + } + +// End of File +