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