diff -r 000000000000 -r e4d67989cc36 lowlevellibsandfws/pluginfw/Framework/frame/Discoverer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lowlevellibsandfws/pluginfw/Framework/frame/Discoverer.cpp Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,1007 @@ +// Copyright (c) 1997-2009 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: +// Contains the implementation of the CDiscoverer class. +// +// + +/** + @file + @internalComponent +*/ + +#include +#include // for EStartupStateNonCritical and EStartupStateCritical +#include + +#include + +#include "EComDebug.h" +#include "TestUtilities.h" // For __FILE__LINE__ +#include "Discoverer.h" +#include "DiscovererObserver.h" +#include "EComUidCodes.h" +#include "baspi.h" +#include "bautils.h" +#include "DriveInfo.h" +#include +#include + + +#define UNUSED_VAR(a) a = a + + +/** Interface Implementation Collection resource file search path */ +_LIT(KEComResourceFileSearch, "\\resource\\plugins\\*"); + +_LIT(KEComResourceFilePathAny, "\\resource\\plugins\\"); +_LIT(KEComResourceFolderPath, "?:\\resource\\plugins\\"); + +// Relative to the Drive with a fixed path +_LIT(KEComSPIFilePath, "\\private\\10009D8F\\"); + +/** + Begin directory scanning after a delay of 1 Second + Allowing multiple directory changes to be applied before + beginning a scan. + */ +static const TInt32 KEComDefaultBeginScanPeriod = 1000000; + +// __________________________________________________________________________ +// +CDiscoverer::CSwiChangeNotifier* CDiscoverer::CSwiChangeNotifier::NewL(CDiscoverer& aDiscoverer) + { + CSwiChangeNotifier* self = new(ELeave) CSwiChangeNotifier(aDiscoverer); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CDiscoverer::CSwiChangeNotifier::CSwiChangeNotifier(CDiscoverer& aDiscoverer) +: CActive(CActive::EPriorityHigh), iDiscoverer(aDiscoverer) + { + // Safe because it cannot fail + CActiveScheduler::Add(this); + } + +void CDiscoverer::CSwiChangeNotifier::ConstructL() + { + // Attach to SWI property + User::LeaveIfError( + iProperty.Attach(KUidSystemCategory, KSAUidSoftwareInstallKeyValue)); + } + +CDiscoverer::CSwiChangeNotifier::~CSwiChangeNotifier() + { + Cancel(); + iProperty.Close(); + } + +void CDiscoverer::CSwiChangeNotifier::DoCancel() + { + iProperty.Cancel(); // Cancel SWI change notifications + } + +void CDiscoverer::CSwiChangeNotifier::Subscribe() + { + if(!IsActive()) + { + iProperty.Subscribe(iStatus); + SetActive(); + } + } + +void CDiscoverer::CSwiChangeNotifier::RunL() + { + Subscribe(); + + TInt swiProperty; + User::LeaveIfError( + iProperty.Get(KUidSystemCategory, KSAUidSoftwareInstallKeyValue, swiProperty)); + + // Do a discovery each time an install, uninstall or restore is completed. + iDiscoverer.SwiChangeNotificationL(swiProperty); + } + +TInt CDiscoverer::CSwiChangeNotifier::RunError(TInt /*aError*/) + { + //If unable to read the SWI P&S variable set the + //discoverers SWI state to ESASwiNone as this will return + //EComs back to its default behaviour + TRAP_IGNORE(iDiscoverer.SwiChangeNotificationL(ESASwisNone)); + return KErrNone; //avoid CActiveScheduler panic + } + +// __________________________________________________________________________ +// +/* + The notification object which watches the Interface Implementation + Collection directories for any changes on specific drive. + When its RunL method is called, it notifies its owning CDiscoverer class + object to re-scan of the Interface Implementation Collection directories. +*/ +CDiscoverer::CDirChangeNotifier::CDirChangeNotifier(CDiscoverer& aDiscoverer, RFs& aFs, const TDriveUnit& aDriveUnit) +: CActive(CActive::EPriorityHigh), iDiscoverer(aDiscoverer), iFs(aFs),iDriveUnit(aDriveUnit) + { + + iNotificationFilePath.Append(iDriveUnit.Name()); + iNotificationFilePath.Append(KEComResourceFilePathAny); + // Safe because it cannot fail + CActiveScheduler::Add(this); + } + +CDiscoverer::CDirChangeNotifier::~CDirChangeNotifier() + { + Cancel(); + } + +void CDiscoverer::CDirChangeNotifier::DoCancel() + { + iFs.NotifyChangeCancel(iStatus); // Cancel change notifications + } + +void CDiscoverer::CDirChangeNotifier::Activate() + { + if(!IsActive()) + { + iStatus = KRequestPending; + SetActive(); + iFs.NotifyChange(ENotifyEntry, iStatus, iNotificationFilePath); + } + } + +void CDiscoverer::CDirChangeNotifier::RunL() + { + RECORD_START_NOTIFIER_RUNL_TIMER_RESULT(iDriveUnit) + // Signal the notification + // If iStatus.Int() is not KErrNone + // then reactivation will not occur + if(iDiscoverer.NotificationL(iStatus.Int(), iDriveUnit)) + Activate(); + RECORD_END_NOTIFIER_RUNL_TIMER_RESULT(iDriveUnit) + } + +TInt CDiscoverer::CDirChangeNotifier::RunError(TInt aError) + { + // Entered most likely because of an error condition during file system + // rescanning and plugin registration that could not be handled locally. + // As indexes in the registry are updated after each registration and the + // tree of registrations is updated at the end for some scan use-cases there + // is a chance that the registration tree and the indexes can get out of + // sync when a leave occurs. + // The code is not present to handle a recovery so the best policy + // is to panic the server and have it restart on next use. + // We can't trap leaves in RunL() and continue as we can not be sure the + // registry is in sync. The registry and discovery code would need to be + // totally reviewed and reworked if panic's were not acceptable. So far they + // have allowed error conditions found in the field to be reported as + // incidents allowing us to idenitify and resovle the underlying causes. + __ECOM_LOG1("ECOM: PANIC in CDiscoverer::CDirChangeNotifier::RunError(), error= %d", aError); + User::Panic(KEComServerPanicCategory, EEComPanic_CDiscoverer_CDirChangeNotifier_RunError); + return KErrNone; // dummy return to stop warnings on missing return + } + +// __________________________________________________________________________ +// +/* + The timer Active object for providing plugin directory scanning on rediscovery events. + The processing of notification will be performed only on drive(s) that has notification event(s) + triggered on it. + It uses data member iPendingDriveList to hold all pending drive nums, and executes only once. + It is activated by the CDirChangeNotifier's notification call. + The default priority is idle time execution only. +*/ +CDiscoverer::CIdleScanningTimer* CDiscoverer::CIdleScanningTimer::NewL(CDiscoverer& aDiscoverer) + { + CIdleScanningTimer* self = new(ELeave) CIdleScanningTimer(aDiscoverer); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } +CDiscoverer::CIdleScanningTimer::CIdleScanningTimer(CDiscoverer& aDiscoverer) +: CTimer(CActive::EPriorityIdle), iDiscoverer(aDiscoverer), iPendingDriveList(2) + { + // Safe because it cannot fail + CActiveScheduler::Add(this); + } + +void CDiscoverer::CIdleScanningTimer::ConstructL() + { + CTimer::ConstructL(); + } + +CDiscoverer::CIdleScanningTimer::~CIdleScanningTimer() + { + Cancel(); + iPendingDriveList.Close(); + } + +void CDiscoverer::CIdleScanningTimer::DoCancel() + { + // Call the base class to ensure the timer is cancelled + CTimer::DoCancel(); + + iDiscoverer.ScanDirectoryCancel(); + } + +void CDiscoverer::CIdleScanningTimer::RunL() +// When the object activates on a specfic drive, this is method is called +// and delegates to the CDiscoverer to scan the Interface Implementation +// Collection directories +// + { + // Only carry out a rediscovery if SWI is not in progress + if(!iDiscoverer.SwiOperationInProgress()) + { + RECORD_START_TIMER_RUNL_TIMER_RESULT + // Do scan on all pending drives stored in iPendingDriveList array + TInt length = iPendingDriveList.Count(); + for(TInt count = 0; count < length; ++count) + { + iDiscoverer.RediscoveryScanDirectoryL(TDriveUnit(iPendingDriveList[count])); + } + + // Signal the observer that the scans have been completed successfully. + iDiscoverer.iDiscovererObserver.DiscoveriesComplete(ETrue, EPluginProcessingTypeAll); + // Reset pending drive list when finishes scan. + iPendingDriveList.Reset(); + // Reset the state of discoverer as all notifications processed. + iDiscoverer.CompleteNotificationProcessing(); + RECORD_END_TIMER_RUNL_TIMER_RESULT + } + } + +TInt CDiscoverer::CIdleScanningTimer::RunError(TInt aError) + { + // Entered most likely because of an error condition during file system + // rescanning and plugin registration that could not be handled locally. + // As indexes in the registry are updated after each registration and the + // tree of registrations is updated at the end for some scan use-cases there + // is a chance that the registration tree and the indexes can get out of + // sync when a leave occurs. + // The code is not present to handle a recovery so the best policy + // is to panic the server and have it restart on next use. + // We can't trap leaves in RunL() and continue as we can not be sure the + // registry is in sync. The registry and discovery code would need to be + // totally reviewed and reworked if panic's were not acceptable. So far they + // have allowed error conditions found in the field to be reported as + // incidents allowing us to idenitify and resovle the underlying causes. + __ECOM_LOG1("ECOM: PANIC in CDiscoverer::CIdleScanningTimer::RunError(), error = %d", aError); + User::Panic(KEComServerPanicCategory, EEComPanic_CDiscoverer_CIdleScanningTimer_RunError); + return KErrNone; // dummy return to stop warnings on mising return + } + +void CDiscoverer::CIdleScanningTimer::RestartScanPeriod() + { + if (!iSuspended) + { + Cancel(); + After(KEComDefaultBeginScanPeriod); + } + } + +void CDiscoverer::CIdleScanningTimer::Suspend() + { + Cancel(); + iSuspended = ETrue; + } + +void CDiscoverer::CIdleScanningTimer::Resume() + { + iSuspended = EFalse; + if(IsAnyNotificationProcessingPending()) + { + RestartScanPeriod(); + } + } +// __________________________________________________________________________ +// +/* + CDirScanner implements incremental scanning of the Interface Implementation + Collection directory + on behalf of the CDiscoverer. + It's methods are called in response to the timer task execution, + thereby requiring the incremental scheduling. +*/ +CDiscoverer::CDirScanner* CDiscoverer::CDirScanner::NewL(CDiscoverer& aDiscoverer, RFs& aFs) + { + CDirScanner* self = new(ELeave)CDirScanner(aDiscoverer,aFs); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CDiscoverer::CDirScanner::ConstructL() + { + } + +CDiscoverer::CDirScanner::CDirScanner(CDiscoverer& aDiscoverer, RFs& aFs) +: CBase(), iDiscoverer(aDiscoverer), iFs(aFs) + { + } + +CDiscoverer::CDirScanner::~CDirScanner() +// D'tor + { + } + + +void CDiscoverer::CDirScanner::ScanDriveL(const TDriveUnit& aDrive, TBool aIsRO) + { + RECORD_START_REDISCOVERYSCANDIRECTORY_RESULT(aDrive) + TDriveName driveName(aDrive.Name()); + TBool scanDirectoryForPlugins = ETrue; + TBool found = EFalse; + + + // If RO then attempt to discover plugins from SPI file + if(aIsRO) + { + TFileName spiFilePath; + spiFilePath.Append(driveName); + spiFilePath.Append(KEComSPIFilePath); + + TEntry entry; + //check if the path exists + if (iFs.Entry(spiFilePath,entry)==KErrNone) + { + TParse spiPath; + spiPath.Set(spiFilePath, NULL, NULL); + // Discover plugins from SPI + found = DoScanSpiFileL(spiPath); + } + scanDirectoryForPlugins = !found; + } + + // scan directory for plugins if not already discovered from SPI file. SPI applies to RO. + if(scanDirectoryForPlugins) + { + + // Find plugins via resoure files + TUidType rscUidType(KNullUid,KUidInterfaceImplementationCollectionInfo,KNullUid); + TBool foundRsc = DoScanDriveL(aDrive, rscUidType, aIsRO); + found = found || foundRsc; + } + + if (!found) + { + iDiscoverer.DriveUnmountedL(aDrive); + } + RECORD_END_REDISCOVERYSCANDIRECTORY_RESULT(aDrive) + } + +TBool CDiscoverer::CDirScanner::DoScanSpiFileL(const TParse& aSpiPath) +{ + iDiscoverer.DriveMountedL(aSpiPath.Drive()); + + RResourceArchive resourceArchive; + //ECom server should continue if OpenL leaves because no spi exists + TRAPD(err,resourceArchive.OpenL(iFs, aSpiPath.DriveAndPath(),_L("ecom"))); + if(err==KErrNotFound || err==KErrPathNotFound) + return EFalse; + User::LeaveIfError(err); + CleanupClosePushL(resourceArchive); + // check SPI file type. On failure do not scan archives + if(resourceArchive.Type() != KEcomSpiFileTypeUid) + { + CleanupStack::PopAndDestroy(&resourceArchive); + return EFalse; + } + + CPluginBase* entryBase=NULL; + TBool resourceExistsIndicator = EFalse; + while(!resourceArchive.End()) + { + TRAPD(error,iDiscoverer.ValidateEntryL(resourceArchive,entryBase)); + CleanupStack::PushL(entryBase); + if (error==KErrNoMemory) + User::LeaveNoMemory(); + if (error==KErrNone) + { + // When SPI is on no DAT file exists,and also RO Internal drive is not rediscovered. + //Therefore this RO Internal drive is always at its initial discovery. No Dll + // is ever discovered before. Always pass EFalse to ProcessEntryL method. + iDiscoverer.ProcessEntryL(aSpiPath.Drive(),entryBase, EFalse); + // set to indicate at least 1 resource exists + resourceExistsIndicator = ETrue; + } + else + { + __ECOM_TRACE1("ECOM: CDiscoverer::DoScanSpiFileL(). Fail Validate: %S\n.",&aSpiPath.FullName()); + } + CleanupStack::PopAndDestroy(entryBase); + entryBase=NULL; + } + CleanupStack::PopAndDestroy(&resourceArchive); + return resourceExistsIndicator; +} + +TBool CDiscoverer::CDirScanner::DoScanDriveL(const TDriveUnit& aDrive, const TUidType& aUidType, TBool aIsRO) + { + RDir dir; + + TDriveName driveName(aDrive.Name()); + TParse searchDir; + User::LeaveIfError(searchDir.Set(KEComResourceFileSearch,NULL,&driveName)); + + // Match the directory list UID's to a Polymorphic DLL UID and Interface + // Implementation Collection UID. + // Resource files are sorted by UID. However, since these files have same UID, + // they are actually sorted by their names (alphanumerically). + + TInt error = dir.Open(iFs, searchDir.FullName(), aUidType); + + if(error == KErrNone) + { + // Have found the plugin directory + CleanupClosePushL(dir); + + TFileName* lastRscNameBuf = new TFileName; + + if (!lastRscNameBuf) + { + CleanupStack::PopAndDestroy(&dir); + return EFalse; + } + CleanupStack::PushL(lastRscNameBuf); + + TEntryArray *dirEntriesArray = new TEntryArray; + + if (!dirEntriesArray) + { + CleanupStack::PopAndDestroy(lastRscNameBuf); + CleanupStack::PopAndDestroy(&dir); + return EFalse; + } + CleanupStack::PushL(dirEntriesArray); + + + TPtrC lastRscName(KNullDesC); + + // Iterate through the directory reading multiple entries at a + // time + TInt count = 0; + TInt readError = KErrNone; + CPluginBase* entryBase=NULL; + + iDiscoverer.DriveMountedL(aDrive); + TBool anyDllRegistered = iDiscoverer.IsAnyDllRegisteredWithDriveL(aDrive); + + + + while (readError != KErrEof) + { + + // Read the next set of entries + readError = dir.Read(*dirEntriesArray); + + if ((readError != KErrNone) && (readError != KErrEof)) + { + User::Leave(readError); + } + else + { + // for KErrEof, dirEntriesArray still has items to process + count = dirEntriesArray->Count(); + // Ok use the entries to populate the file list + for(TInt i = 0; i < count; ++i) + { + + // Compare current file name against previous one ignoring extension. If it is same + // then there is no need to process it. + TPtrC currName = (*dirEntriesArray)[i].iName.Left((*dirEntriesArray)[i].iName.Length()-KExtensionLength); + if (lastRscName.Compare(currName) == 0) + { + continue; + } + else if (i < (count - 1)) + { + lastRscName.Set(currName); + } + else + { + lastRscNameBuf->Copy(currName); + lastRscName.Set(*lastRscNameBuf); + } + + + // Obtain a copy of the current directory entry + TRAP(error,iDiscoverer.ValidateEntryL((*dirEntriesArray)[i], driveName, entryBase, aIsRO)); + CleanupStack::PushL(entryBase); + + if (error==KErrNoMemory) + User::LeaveNoMemory(); + + if (error==KErrNone) + { + iDiscoverer.ProcessEntryL(driveName,entryBase,anyDllRegistered); + } + else + { + __ECOM_TRACE1("ECOM: CDiscoverer::DoScanDriveL(). Fail Validate entry: %S\n.",&(*dirEntriesArray)[i].iName); + } + CleanupStack::PopAndDestroy(entryBase); + entryBase=NULL; + } + } + } + CleanupStack::PopAndDestroy(dirEntriesArray); + CleanupStack::PopAndDestroy(lastRscNameBuf); + CleanupStack::PopAndDestroy(&dir); + return ETrue; + } + + return EFalse; + } + +void CDiscoverer::CDirScanner::DiscoverPluginsL(TBool aDiscoverReadOnlyDrives) + { + // iterator which returns only the drives need to be scanned. + TEComCachedDriveInfoIterator iter(*iDiscoverer.iCachedDriveInfo); + + // Iterate from highest drive letter (Z:) towards lowest drive letter (A:). + for (iter.Last(); iter.InRange(); iter.Prev()) + { + if (iter.DriveIsReadOnlyInternal() == aDiscoverReadOnlyDrives) + { + ScanDriveL(iter.DriveUnit(), aDiscoverReadOnlyDrives); + } + } + } + + +// __________________________________________________________________________ +// +/* + Responsible for identifying new Interface Implementation Collections, + installed in the Interface Implementation Collection directories. +*/ + +CDiscoverer* CDiscoverer::NewL(MDiscovererObserver& aDiscovererObserver, RFs& aFs) + { + CDiscoverer* self = new(ELeave) CDiscoverer(aDiscovererObserver, aFs); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +// Default d'tor + +CDiscoverer::~CDiscoverer() + { + // Cancel any scanning behaviour or notifications + if(iDirScanner != NULL) + { + // Left in the middle of a scan + // So clear up + delete iDirScanner; + iDirScanner = NULL; + // Signal the observer that the scan has + // not been completed successfully. + iDiscovererObserver.DiscoveriesComplete(EFalse, EPluginProcessingTypeAll); + } + Suspend(); + iDrivesDiscovered.Reset(); + delete iSwiChangeNotifier; + delete iScanningTimer; + delete iLanguageChangeNotifier; + delete iCachedDriveInfo; + iRscDirNotifierList.ResetAndDestroy(); + + } + +// Default c'tor +CDiscoverer::CDiscoverer(MDiscovererObserver& aDiscovererObserver, RFs& aFs) +: CBase(), iSwiChangeDiscoveryPending(EFalse), iLanguageChangeDiscoveryPending(EFalse), + iState(EDisc_Undefined), iDiscovererObserver(aDiscovererObserver), iFs(aFs) + { + // Do nothing here + } + +void CDiscoverer::ConstructL() + { + iCachedDriveInfo = CEComCachedDriveInfo::NewL(iFs); + + // Construct the Interface Implementation Collection + // directory change notifier list + // and the scan step control object. + + CDirChangeNotifier *dirChangeNotifierPtr; + + // iterator which returns only the drives need to be scanned. + TEComCachedDriveInfoIterator iter(*iCachedDriveInfo); + + for (iter.First(); iter.InRange(); iter.Next()) + { + //Don't need to monitor read-only drives. They don't change. + if ( !iter.DriveIsReadOnlyInternal() ) + { + dirChangeNotifierPtr = new(ELeave)CDirChangeNotifier(*this,iFs,iter.DriveUnit()); + + CleanupStack::PushL(dirChangeNotifierPtr); + iRscDirNotifierList.AppendL(dirChangeNotifierPtr); + CleanupStack::Pop(); + } + } + iSwiChangeNotifier = CSwiChangeNotifier::NewL(*this); + + iScanningTimer = CIdleScanningTimer::NewL(*this); + + //Create the language change notifier and install the callback function + const TCallBack myCallBackFunction(&CDiscoverer::LocaleChangedL, this); + iLanguageChangeNotifier = CEnvironmentChangeNotifier::NewL(CActive::EPriorityStandard, myCallBackFunction); + + iDirScanner = CDirScanner::NewL(*this,iFs); + + InitialiseEvent(); + } + + +TInt CDiscoverer::Resume() + { + // Reactivate the scanning timer if not NULL + if (iScanningTimer != NULL) + { + iScanningTimer->Resume(); + } + + TCallBackState cbData = ECallBackState_EventEnd; + iBurChangeCallBack.CallBack(ECallBackId_BurEvent, &cbData); + + /* + iLanguageChangeNotifier is not activated because it is not cancelled during CDiscoverer::Suspend(). + It is not suspended because a language change should not occur whilst a backup/restore operation + is taking place. + */ + + return KErrNone; + } + + +TInt CDiscoverer::Suspend() + { + // Suspend the scanning timer if not NULL + if (iScanningTimer != NULL) + { + iScanningTimer->Suspend(); + } + + TCallBackState cbData = ECallBackState_EventStart; + iBurChangeCallBack.CallBack(ECallBackId_BurEvent, &cbData); + + /* + iLanguageChangeNotifier is not cancelled because a language change should not occur + whilst a backup/restore operation is taking place. + */ + + return KErrNone; + } + + +TBool CDiscoverer::NotificationL(TInt aStatus, const TDriveUnit& aDriveUnit) + { + + TBool okToContinue = ETrue; + if(aStatus != KErrNone) + { + // Big trouble with the notification + // Tell our observer + // Notifications will cease if EFalse is returned!!!! + okToContinue = iDiscovererObserver.NotifiedWithErrorCode(aStatus); + } + else + { + //call ProcessDNEventL() to indicate Plugins have been added or removed on a specfic drive, + // then do the state transition and to start a re-discovery . + ProcessDNEventL(EPluginsModified,aDriveUnit ); + ProcessDNEventL(EPluginsRediscover, aDriveUnit); + } + return okToContinue; + } + +void CDiscoverer::SwiChangeNotificationL(TInt aSwiOperation) + { + // Store the current SWI operation, ignore operation status + iSwiOperation = aSwiOperation & KSASwisOperationMask; + + TCallBackState cbData = SwiOperationInProgress() ? ECallBackState_EventStart : ECallBackState_EventEnd; + iSwiChangeCallBack.CallBack(ECallBackId_SwiEvent, &cbData); + + // Test no SWI operation in progress + if(!SwiOperationInProgress()) + { + TBool rediscoveryPending = EFalse; + if(!iSwiChangeDiscoveryPending) + { + // for each removable drive call ProcessDNEventL() to do the state transition and to start + // a re-discovery for that drive. + TInt count = iDrivesDiscovered.Count(); + for(TInt i=0; i < count; i++) + { + TDriveUnit drvUnit(iDrivesDiscovered[i]); + if(iCachedDriveInfo->DriveIsRemovableL(drvUnit)) + { + rediscoveryPending = ETrue; + ProcessDNEventL(EPluginsModified, drvUnit ); + ProcessDNEventL(EPluginsRediscover, drvUnit); + iSwiChangeDiscoveryPending = ETrue; + } + } + } + + //If there are no removable drives to be scanned check if there are any + //pending notifications that couldn't be processed during SWI + if(!rediscoveryPending && iScanningTimer->IsAnyNotificationProcessingPending()) + { + // Activate timer if there is any notification processing pending + iScanningTimer->RestartScanPeriod(); + } + } + } + +TBool CDiscoverer::SwiOperationInProgress() + { + return (iSwiOperation != ESASwisNone); + } + +void CDiscoverer::LanguageChangeNotificationL() + { + if (!iLanguageChangeDiscoveryPending) + { + // for each drive call ProcessDNEventL() to do the state transition and to start + // a re-discovery for that drive. + TInt count = iDrivesDiscovered.Count(); + for(TInt i=0; i < count; i++) + { + ProcessDNEventL(EPluginsModified, iDrivesDiscovered[i] ); + ProcessDNEventL(EPluginsRediscover, iDrivesDiscovered[i]); + } + iLanguageChangeDiscoveryPending = ETrue; + } + } +void CDiscoverer::RediscoveryScanDirectoryL(const TDriveUnit& aDriveUnit) + { + TBool doScan = EFalse; + if(iDrivesDiscovered.Find(aDriveUnit) != KErrNotFound) + { + // If the drive has plugins on it previously, do ScanDriveL on any notifications. + doScan = ETrue; + } + else // Otherwise the drive doesn't contain any plugin before, do further check. + { + TBuf pluginsDirPath(KEComResourceFolderPath); + pluginsDirPath[0] = ('A' + TInt(aDriveUnit)); + TEntry entry; + if(iFs.Entry(pluginsDirPath,entry) == KErrNone) + { + // Now it has plugins folder on it, do ScanDriveL. + doScan = ETrue; + } + // If it still doesn't have plugins folder on it, skip unnecessary scanning. + // NOTE: other returned error code could be KErrPathNotFound, KErrNotReady etc. + // As long as no plugin has been found, always skip scanning on this drive. + } + + // Performs scanning according to above checks. + if(doScan) + { + // Signal the observer that a scan has commenced. + iDiscovererObserver.DiscoveriesBegin(); + + iDirScanner->ScanDriveL(aDriveUnit, iCachedDriveInfo->DriveIsReadOnlyInternalL(aDriveUnit)); + + // Signal the observer that the scan has + // been completed successfully. + iDiscovererObserver.SetDiscoveryFlagL(aDriveUnit); + } + } + +void CDiscoverer::ScanDirectoryCancel() + { + if(iDirScanner != NULL) + { + // Signal the observer that the scan has + // been completed un-successfully. + iDiscovererObserver.DiscoveriesComplete(EFalse, EPluginProcessingTypeAll); + } + } + + +void CDiscoverer::CompleteNotificationProcessing() + { + iState = EDisc_AllPluginsDisc; + iSwiChangeDiscoveryPending = EFalse; + iLanguageChangeDiscoveryPending = EFalse; + } + + +void CDiscoverer::ValidateEntryL(const TEntry& aEntry, const TDriveName& aDriveName, CPluginBase*& aEntryToFill, TBool aIsRO) + { + aEntryToFill=CSecurePlugin::NewL(iFs,aEntry,aDriveName, aIsRO); + } + +void CDiscoverer::ValidateEntryL(RResourceArchive& aRscArchive,CPluginBase*& aEntryToFill) + { + aEntryToFill = CSpiPlugin::NewL(aRscArchive); + } + + +void CDiscoverer::ProcessEntryL(const TDriveName& aDrive,CPluginBase*& aEntry, TBool aAnyDllDiscovered) + { + iDiscovererObserver.RegisterDiscoveryL(aDrive,aEntry,aAnyDllDiscovered); + } + +void CDiscoverer::DriveMountedL(TDriveUnit aDrive) + { + TInt index = iDrivesDiscovered.Find(aDrive); + if(index == KErrNotFound) + { + User::LeaveIfError(iDrivesDiscovered.Append(aDrive)); + iDiscovererObserver.DriveReinstatedL(aDrive); // Wasn't there before + } + } + +TBool CDiscoverer::IsAnyDllRegisteredWithDriveL(const TDriveUnit aDrive)const + { + return iDiscovererObserver.IsAnyDllRegisteredWithDriveL(aDrive); + } + +void CDiscoverer::DriveUnmountedL(TDriveUnit aDrive) + { + TInt index = iDrivesDiscovered.Find(aDrive); + if(index != KErrNotFound) + { + iDrivesDiscovered.Remove(index); + iDiscovererObserver.DriveRemovedL(aDrive); // Was there before + } + } + +CDiscoverer::TDiscovererState CDiscoverer::State() const + { + return iState; + } + + +void CDiscoverer::ProcessSSAEventL(TStartupStateIdentifier aKnownState) + { + + if(iState == EDisc_NoPluginsDisc && aKnownState == EStartupStateCriticalStatic) + { + __ECOM_TRACE("ECOM: CDiscoverer::ProcessSSAEventL():EStartupStateCriticalStatic is reached,discover the RO Internal drives only."); + + // Signal the observer that the scanning is started + iDiscovererObserver.DiscoveriesBegin(); + + //scan the RO drives + iDirScanner->DiscoverPluginsL(ETrue); + + //change the state + iState = EDisc_CriticalPluginsDisc; + + // Signal the observer that the scan has + // been completed successfully. + iDiscovererObserver.DiscoveriesComplete(ETrue, EPluginProcessingTypeCriticalOnly); + } + else if(iState == EDisc_CriticalPluginsDisc && aKnownState == EStartupStateNonCritical) + { + __ECOM_TRACE("ECOM: CDiscoverer::ProcessSSAEventL():EStartupStateNonCritical is reached,discover the Non RO Internal drives."); + + // Signal the observer that the scanning is started + iDiscovererObserver.DiscoveriesBegin(); + + //scan the non-ro drives + iDirScanner->DiscoverPluginsL(EFalse); + + //change the state + iState = EDisc_AllPluginsDisc; + + // Signal the observer that the scan has + // been completed successfully. + iDiscovererObserver.DiscoveriesComplete(ETrue, EPluginProcessingTypeNonCriticalOnly); + + + StartNotifiers(); + } + else if(iState == EDisc_NoPluginsDisc && aKnownState == EStartupStateNonCritical) + { + __ECOM_TRACE("ECOM: CDiscoverer::ProcessSSAEventL():EStartupStateNonCritical is reached all at once,discover all the drives."); + + // Signal the observer that the scanning is started + iDiscovererObserver.DiscoveriesBegin(); + + //scan a specified the drives + iDirScanner->DiscoverPluginsL(ETrue); + iDirScanner->DiscoverPluginsL(EFalse); + + //change the state + iState = EDisc_AllPluginsDisc; + + // Signal the observer that the scan has + // been completed successfully. + iDiscovererObserver.DiscoveriesComplete(ETrue, EPluginProcessingTypeAll); + + StartNotifiers(); + } + } + +void CDiscoverer::StartNotifiers() + { + + for(TInt i = 0; iActivate(); + } + iSwiChangeNotifier->Subscribe(); + iLanguageChangeNotifier->Start(); + } + +void CDiscoverer::ProcessDNEventL(TNotificationFlag aFlag, const TDriveUnit& aDriveUnit) + { + if(iState == EDisc_AllPluginsDisc && aFlag == EPluginsModified) + { + iState = EDisc_PluginsDirty; + return; + } + if(iState == EDisc_PluginsDirty && aFlag == EPluginsRediscover) + { + // Add drive number to the pending drive list and activate timer. + iScanningTimer->AddDriveL(aDriveUnit); + iScanningTimer->RestartScanPeriod(); + } + } + +void CDiscoverer::SetSwiChangeCallBack(const TCallBackWithArg& aCallBack) + { + iSwiChangeCallBack = aCallBack; + } + +void CDiscoverer::SetBurChangeCallBack(const TCallBackWithArg& aCallBack) + { + iBurChangeCallBack = aCallBack; + } + +void CDiscoverer::InitialiseEvent() + { + iState = EDisc_NoPluginsDisc; + } +TInt CDiscoverer::LocaleChangedL(TAny* aPtr) + { + CDiscoverer* thisLocaleManager = (CDiscoverer *) aPtr ; + + if(!thisLocaleManager->iLanguageChangeNotifier) + { + __ECOM_TRACE("ECOM: LocaleChangedL: Bad Change Notification"); + return KErrGeneral; + } + + TInt stat = thisLocaleManager->iLanguageChangeNotifier->Change(); + if((stat & EChangesLocale) && (!thisLocaleManager->iLanguageChangeDiscoveryPending)) + { + // + // System Locale data has been updated + // if the downgrade path has changed we + // re-scan resource files for all drives and get the right language. + TBool isLanguageChanged; + thisLocaleManager->iDiscovererObserver.LanguageChangedL(isLanguageChanged); + if(isLanguageChanged) + { + thisLocaleManager->LanguageChangeNotificationL(); + } + } + return KErrNone; + }