lowlevellibsandfws/pluginfw/Framework/frame/Discoverer.cpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Contains the implementation of the CDiscoverer class.
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21 */
       
    22 
       
    23 #include <e32uid.h>
       
    24 #include <startup.hrh> // for EStartupStateNonCritical and EStartupStateCritical
       
    25 #include <bacntf.h>
       
    26 
       
    27 #include <sacls.h>
       
    28 
       
    29 #include "EComDebug.h"
       
    30 #include "TestUtilities.h"	// For __FILE__LINE__
       
    31 #include "Discoverer.h"
       
    32 #include "DiscovererObserver.h"
       
    33 #include "EComUidCodes.h"
       
    34 #include "baspi.h"
       
    35 #include "bautils.h"
       
    36 #include "DriveInfo.h"
       
    37 #include <ecom/ecomerrorcodes.h>
       
    38 #include <saclscommon.h>
       
    39 
       
    40 
       
    41 #define UNUSED_VAR(a) a = a
       
    42 
       
    43 
       
    44 /** Interface Implementation Collection resource file search path */
       
    45 _LIT(KEComResourceFileSearch,	"\\resource\\plugins\\*");
       
    46 
       
    47 _LIT(KEComResourceFilePathAny,	"\\resource\\plugins\\");
       
    48 _LIT(KEComResourceFolderPath,	"?:\\resource\\plugins\\"); 
       
    49 
       
    50 // Relative to the Drive with a fixed path
       
    51 _LIT(KEComSPIFilePath, "\\private\\10009D8F\\");
       
    52 
       
    53 /** 
       
    54 	Begin directory scanning after a delay of 1 Second
       
    55 	Allowing multiple directory changes to be applied before
       
    56 	beginning a scan.
       
    57  */
       
    58 static const TInt32 KEComDefaultBeginScanPeriod	=	1000000;
       
    59 
       
    60 // __________________________________________________________________________
       
    61 //
       
    62 CDiscoverer::CSwiChangeNotifier* CDiscoverer::CSwiChangeNotifier::NewL(CDiscoverer& aDiscoverer)
       
    63 	{
       
    64 	CSwiChangeNotifier* self = new(ELeave) CSwiChangeNotifier(aDiscoverer);
       
    65 	CleanupStack::PushL(self);
       
    66 	self->ConstructL();
       
    67 	CleanupStack::Pop(self);
       
    68 	return self;
       
    69 	}
       
    70 
       
    71 CDiscoverer::CSwiChangeNotifier::CSwiChangeNotifier(CDiscoverer& aDiscoverer)
       
    72 : CActive(CActive::EPriorityHigh), iDiscoverer(aDiscoverer)
       
    73 	{
       
    74 	// Safe because it cannot fail
       
    75 	CActiveScheduler::Add(this);
       
    76 	}
       
    77 
       
    78 void CDiscoverer::CSwiChangeNotifier::ConstructL()
       
    79 	{
       
    80 	// Attach to SWI property
       
    81 	User::LeaveIfError(
       
    82         iProperty.Attach(KUidSystemCategory, KSAUidSoftwareInstallKeyValue));
       
    83 	}
       
    84 
       
    85 CDiscoverer::CSwiChangeNotifier::~CSwiChangeNotifier()
       
    86 	{
       
    87 	Cancel();
       
    88 	iProperty.Close();
       
    89 	}
       
    90 
       
    91 void CDiscoverer::CSwiChangeNotifier::DoCancel()
       
    92 	{
       
    93 	iProperty.Cancel();	// Cancel SWI change notifications
       
    94 	}
       
    95 
       
    96 void CDiscoverer::CSwiChangeNotifier::Subscribe()
       
    97 	{
       
    98 	if(!IsActive())
       
    99 		{
       
   100 		iProperty.Subscribe(iStatus);
       
   101 		SetActive();
       
   102 		}
       
   103 	}
       
   104 
       
   105 void CDiscoverer::CSwiChangeNotifier::RunL()
       
   106 	{
       
   107 	Subscribe();
       
   108 	
       
   109 	TInt swiProperty;
       
   110 	User::LeaveIfError(
       
   111         iProperty.Get(KUidSystemCategory, KSAUidSoftwareInstallKeyValue, swiProperty));
       
   112 
       
   113 	// Do a discovery each time an install, uninstall or restore is completed.
       
   114 	iDiscoverer.SwiChangeNotificationL(swiProperty);	
       
   115 	}
       
   116 
       
   117 TInt CDiscoverer::CSwiChangeNotifier::RunError(TInt /*aError*/)
       
   118 	{
       
   119 	//If unable to read the SWI P&S variable set the 
       
   120 	//discoverers SWI state to ESASwiNone as this will return
       
   121 	//EComs back to its default behaviour
       
   122 	TRAP_IGNORE(iDiscoverer.SwiChangeNotificationL(ESASwisNone));	
       
   123 	return KErrNone; //avoid CActiveScheduler panic
       
   124 	}
       
   125 
       
   126 // __________________________________________________________________________
       
   127 //
       
   128 /*
       
   129 	The notification object which watches the Interface Implementation 
       
   130 	Collection directories for any changes on specific drive.
       
   131 	When its RunL method is called, it notifies its owning CDiscoverer class
       
   132 	object to re-scan of the Interface Implementation Collection directories.
       
   133 */
       
   134 CDiscoverer::CDirChangeNotifier::CDirChangeNotifier(CDiscoverer& aDiscoverer, RFs& aFs, const TDriveUnit& aDriveUnit)
       
   135 : CActive(CActive::EPriorityHigh), iDiscoverer(aDiscoverer), iFs(aFs),iDriveUnit(aDriveUnit)
       
   136 	{
       
   137 	
       
   138 	iNotificationFilePath.Append(iDriveUnit.Name());
       
   139 	iNotificationFilePath.Append(KEComResourceFilePathAny);
       
   140 	// Safe because it cannot fail
       
   141 	CActiveScheduler::Add(this);
       
   142 	}
       
   143 
       
   144 CDiscoverer::CDirChangeNotifier::~CDirChangeNotifier()
       
   145 	{
       
   146 	Cancel();
       
   147 	}
       
   148 
       
   149 void CDiscoverer::CDirChangeNotifier::DoCancel()
       
   150 	{
       
   151 	iFs.NotifyChangeCancel(iStatus);	// Cancel change notifications
       
   152 	}
       
   153 
       
   154 void CDiscoverer::CDirChangeNotifier::Activate()
       
   155 	{
       
   156 	if(!IsActive())
       
   157 		{
       
   158 		iStatus = KRequestPending;
       
   159 		SetActive();
       
   160 		iFs.NotifyChange(ENotifyEntry, iStatus, iNotificationFilePath); 
       
   161 		}
       
   162 	}
       
   163 
       
   164 void CDiscoverer::CDirChangeNotifier::RunL()
       
   165 	{
       
   166 	RECORD_START_NOTIFIER_RUNL_TIMER_RESULT(iDriveUnit)
       
   167 	// Signal the notification
       
   168 	// If iStatus.Int() is not KErrNone
       
   169 	// then reactivation will not occur
       
   170 	if(iDiscoverer.NotificationL(iStatus.Int(), iDriveUnit))
       
   171 		Activate();
       
   172 	RECORD_END_NOTIFIER_RUNL_TIMER_RESULT(iDriveUnit)
       
   173 	}
       
   174 
       
   175 TInt CDiscoverer::CDirChangeNotifier::RunError(TInt aError)
       
   176 	{
       
   177 	// Entered most likely because of an error condition during file system
       
   178     // rescanning and plugin registration that could not be handled locally. 
       
   179     // As indexes in the registry are updated after each registration and the
       
   180 	// tree of registrations is updated at the end for some scan use-cases there
       
   181 	// is a chance that the registration tree and the indexes can get out of 
       
   182     // sync when a leave occurs. 
       
   183     // The code is not present to handle a recovery so the best policy 
       
   184     // is to panic the server and have it restart on next use.
       
   185     // We can't trap leaves in RunL() and continue as we can not be sure the 
       
   186     // registry is in sync. The registry and discovery code would need to be 
       
   187     // totally reviewed and reworked if panic's were not acceptable. So far they 
       
   188     // have allowed error conditions found in the field to be reported as 
       
   189     // incidents allowing us to idenitify and resovle the underlying causes.
       
   190 	__ECOM_LOG1("ECOM: PANIC in CDiscoverer::CDirChangeNotifier::RunError(), error= %d", aError);
       
   191 	User::Panic(KEComServerPanicCategory, EEComPanic_CDiscoverer_CDirChangeNotifier_RunError);
       
   192 	return KErrNone;   // dummy return to stop warnings on missing return
       
   193 	}
       
   194 
       
   195 // __________________________________________________________________________
       
   196 //
       
   197 /*
       
   198 	The timer Active object for providing plugin directory scanning on rediscovery events. 
       
   199 	The processing of notification will be performed only on drive(s) that has notification event(s)
       
   200 	triggered on it.
       
   201 	It uses data member iPendingDriveList to hold all pending drive nums, and executes only once. 
       
   202 	It is activated by the CDirChangeNotifier's notification call. 
       
   203 	The default priority is idle time execution only.
       
   204 */
       
   205 CDiscoverer::CIdleScanningTimer* CDiscoverer::CIdleScanningTimer::NewL(CDiscoverer& aDiscoverer)
       
   206 	{
       
   207 	CIdleScanningTimer* self = new(ELeave) CIdleScanningTimer(aDiscoverer);
       
   208 	CleanupStack::PushL(self);
       
   209 	self->ConstructL();
       
   210 	CleanupStack::Pop(self);
       
   211 	return self;
       
   212 	}
       
   213 CDiscoverer::CIdleScanningTimer::CIdleScanningTimer(CDiscoverer& aDiscoverer)
       
   214 : CTimer(CActive::EPriorityIdle), iDiscoverer(aDiscoverer), iPendingDriveList(2)
       
   215 	{
       
   216 	// Safe because it cannot fail
       
   217 	CActiveScheduler::Add(this);
       
   218 	}
       
   219 
       
   220 void CDiscoverer::CIdleScanningTimer::ConstructL()
       
   221 	{
       
   222 	CTimer::ConstructL();
       
   223 	}
       
   224 
       
   225 CDiscoverer::CIdleScanningTimer::~CIdleScanningTimer()
       
   226 	{
       
   227 	Cancel();
       
   228 	iPendingDriveList.Close();
       
   229 	}
       
   230 
       
   231 void CDiscoverer::CIdleScanningTimer::DoCancel()
       
   232 	{
       
   233 	// Call the base class to ensure the timer is cancelled
       
   234 	CTimer::DoCancel();
       
   235 
       
   236 	iDiscoverer.ScanDirectoryCancel();
       
   237 	}
       
   238 
       
   239 void CDiscoverer::CIdleScanningTimer::RunL()
       
   240 //	When the object activates on a specfic drive, this is method is called
       
   241 //  and delegates to the CDiscoverer to scan the Interface Implementation 
       
   242 //	Collection directories
       
   243 //
       
   244 	{
       
   245 	// Only carry out a rediscovery if SWI is not in progress
       
   246 	if(!iDiscoverer.SwiOperationInProgress()) 
       
   247 		{
       
   248 		RECORD_START_TIMER_RUNL_TIMER_RESULT
       
   249 		// Do scan on all pending drives stored in iPendingDriveList array
       
   250 		TInt length = iPendingDriveList.Count();
       
   251 		for(TInt count = 0; count < length; ++count)
       
   252 			{
       
   253 			iDiscoverer.RediscoveryScanDirectoryL(TDriveUnit(iPendingDriveList[count]));
       
   254 			}
       
   255 	
       
   256 		// Signal the observer that the scans have been completed successfully.
       
   257 		iDiscoverer.iDiscovererObserver.DiscoveriesComplete(ETrue, EPluginProcessingTypeAll);
       
   258 		// Reset pending drive list when finishes scan.
       
   259 		iPendingDriveList.Reset();
       
   260 		// Reset the state of discoverer as all notifications processed.
       
   261 		iDiscoverer.CompleteNotificationProcessing();
       
   262 		RECORD_END_TIMER_RUNL_TIMER_RESULT
       
   263 		}
       
   264 	}
       
   265 
       
   266 TInt CDiscoverer::CIdleScanningTimer::RunError(TInt aError)
       
   267 	{
       
   268 	// Entered most likely because of an error condition during file system
       
   269     // rescanning and plugin registration that could not be handled locally. 
       
   270     // As indexes in the registry are updated after each registration and the
       
   271 	// tree of registrations is updated at the end for some scan use-cases there
       
   272 	// is a chance that the registration tree and the indexes can get out of 
       
   273     // sync when a leave occurs. 
       
   274     // The code is not present to handle a recovery so the best policy 
       
   275     // is to panic the server and have it restart on next use.
       
   276     // We can't trap leaves in RunL() and continue as we can not be sure the 
       
   277     // registry is in sync. The registry and discovery code would need to be 
       
   278     // totally reviewed and reworked if panic's were not acceptable. So far they 
       
   279     // have allowed error conditions found in the field to be reported as 
       
   280     // incidents allowing us to idenitify and resovle the underlying causes.
       
   281 	__ECOM_LOG1("ECOM: PANIC in CDiscoverer::CIdleScanningTimer::RunError(), error = %d", aError);
       
   282 	User::Panic(KEComServerPanicCategory, EEComPanic_CDiscoverer_CIdleScanningTimer_RunError);
       
   283 	return KErrNone;	// dummy return to stop warnings on mising return
       
   284 	}
       
   285 	
       
   286 void CDiscoverer::CIdleScanningTimer::RestartScanPeriod()
       
   287 	{
       
   288 	if (!iSuspended)
       
   289 		{
       
   290 		Cancel();
       
   291 		After(KEComDefaultBeginScanPeriod);
       
   292 		}
       
   293 	}
       
   294 	
       
   295 void CDiscoverer::CIdleScanningTimer::Suspend()
       
   296 	{
       
   297 	Cancel();
       
   298 	iSuspended = ETrue;
       
   299 	}
       
   300 	
       
   301 void CDiscoverer::CIdleScanningTimer::Resume()
       
   302 	{
       
   303 	iSuspended = EFalse;
       
   304 	if(IsAnyNotificationProcessingPending())
       
   305 		{
       
   306 		RestartScanPeriod();
       
   307 		}
       
   308 	}
       
   309 // __________________________________________________________________________
       
   310 //
       
   311 /*
       
   312 		CDirScanner implements incremental scanning of the Interface Implementation 
       
   313 		Collection directory 
       
   314 		on behalf of the CDiscoverer.
       
   315 		It's methods are called in response to the timer task execution,
       
   316 		thereby requiring the incremental scheduling.
       
   317 */
       
   318 CDiscoverer::CDirScanner* CDiscoverer::CDirScanner::NewL(CDiscoverer& aDiscoverer, RFs& aFs)
       
   319 	{
       
   320 	CDirScanner* self = new(ELeave)CDirScanner(aDiscoverer,aFs);
       
   321 	CleanupStack::PushL(self);
       
   322 	self->ConstructL();
       
   323 	CleanupStack::Pop(self);
       
   324 	return self;
       
   325 	}
       
   326 
       
   327 void CDiscoverer::CDirScanner::ConstructL()
       
   328 	{
       
   329 	}
       
   330 
       
   331 CDiscoverer::CDirScanner::CDirScanner(CDiscoverer& aDiscoverer, RFs& aFs)
       
   332 : CBase(), iDiscoverer(aDiscoverer), iFs(aFs)
       
   333 	{
       
   334 	}
       
   335 
       
   336 CDiscoverer::CDirScanner::~CDirScanner()
       
   337 // D'tor
       
   338 	{
       
   339 	}
       
   340 	
       
   341 
       
   342 void CDiscoverer::CDirScanner::ScanDriveL(const TDriveUnit& aDrive,  TBool aIsRO)
       
   343 	{
       
   344 	RECORD_START_REDISCOVERYSCANDIRECTORY_RESULT(aDrive)
       
   345 	TDriveName driveName(aDrive.Name());
       
   346 	TBool scanDirectoryForPlugins = ETrue;
       
   347 	TBool found = EFalse;
       
   348 
       
   349 	
       
   350 	// If RO then attempt to discover plugins from SPI file
       
   351 	if(aIsRO)
       
   352 		{
       
   353 		TFileName spiFilePath;
       
   354 		spiFilePath.Append(driveName);
       
   355 		spiFilePath.Append(KEComSPIFilePath);
       
   356 		
       
   357 		TEntry entry;
       
   358 		//check if the path exists
       
   359 		if (iFs.Entry(spiFilePath,entry)==KErrNone)
       
   360 			{
       
   361 			TParse spiPath;
       
   362 			spiPath.Set(spiFilePath, NULL, NULL);
       
   363 			// Discover plugins from SPI
       
   364 			found = DoScanSpiFileL(spiPath);
       
   365 			}
       
   366 		scanDirectoryForPlugins = !found;
       
   367 		}
       
   368  
       
   369  	// scan directory for plugins if not already discovered from SPI file. SPI applies to RO.
       
   370  	if(scanDirectoryForPlugins)
       
   371  		{
       
   372  	
       
   373 		// Find plugins via resoure files
       
   374 		TUidType rscUidType(KNullUid,KUidInterfaceImplementationCollectionInfo,KNullUid);
       
   375 		TBool foundRsc = DoScanDriveL(aDrive, rscUidType, aIsRO);
       
   376 		found = found || foundRsc; 
       
   377  		}
       
   378 
       
   379 	if (!found)
       
   380 		{
       
   381 		iDiscoverer.DriveUnmountedL(aDrive);
       
   382 		}
       
   383 	RECORD_END_REDISCOVERYSCANDIRECTORY_RESULT(aDrive)
       
   384 	}
       
   385 
       
   386 TBool CDiscoverer::CDirScanner::DoScanSpiFileL(const TParse& aSpiPath)
       
   387 {
       
   388 	iDiscoverer.DriveMountedL(aSpiPath.Drive());
       
   389 
       
   390 	RResourceArchive resourceArchive;
       
   391 	//ECom server should continue if OpenL leaves because no spi exists 
       
   392 	TRAPD(err,resourceArchive.OpenL(iFs, aSpiPath.DriveAndPath(),_L("ecom")));
       
   393 	if(err==KErrNotFound || err==KErrPathNotFound)
       
   394 		return EFalse;
       
   395 	User::LeaveIfError(err);
       
   396 	CleanupClosePushL(resourceArchive);
       
   397 	// check SPI file type. On failure do not scan archives
       
   398 	if(resourceArchive.Type() != KEcomSpiFileTypeUid)
       
   399 		{
       
   400 		CleanupStack::PopAndDestroy(&resourceArchive);
       
   401 		return EFalse;
       
   402 		}
       
   403 	
       
   404 	CPluginBase* entryBase=NULL;
       
   405 	TBool resourceExistsIndicator = EFalse;
       
   406 	while(!resourceArchive.End())
       
   407 		{
       
   408 		TRAPD(error,iDiscoverer.ValidateEntryL(resourceArchive,entryBase));
       
   409 		CleanupStack::PushL(entryBase);
       
   410 		if (error==KErrNoMemory)
       
   411 			User::LeaveNoMemory();
       
   412 		if (error==KErrNone)
       
   413 			{
       
   414 			// When SPI is on no DAT file exists,and also RO Internal drive is not rediscovered. 
       
   415 			//Therefore this RO Internal drive is always at its initial discovery. No Dll
       
   416 			// is ever discovered before. Always pass EFalse to ProcessEntryL method.
       
   417 			iDiscoverer.ProcessEntryL(aSpiPath.Drive(),entryBase, EFalse);
       
   418 			// set to indicate at least 1 resource exists
       
   419 			resourceExistsIndicator = ETrue;	
       
   420 			}
       
   421 		else
       
   422 			{
       
   423 			__ECOM_TRACE1("ECOM: CDiscoverer::DoScanSpiFileL(). Fail Validate: %S\n.",&aSpiPath.FullName());
       
   424 			}	
       
   425 		CleanupStack::PopAndDestroy(entryBase);
       
   426 		entryBase=NULL;
       
   427 		}
       
   428 	CleanupStack::PopAndDestroy(&resourceArchive);
       
   429 	return resourceExistsIndicator;
       
   430 }
       
   431 
       
   432 TBool CDiscoverer::CDirScanner::DoScanDriveL(const TDriveUnit& aDrive, const TUidType& aUidType, TBool aIsRO)
       
   433 	{	
       
   434 	RDir dir;
       
   435 	
       
   436 	TDriveName driveName(aDrive.Name());
       
   437 	TParse searchDir;
       
   438 	User::LeaveIfError(searchDir.Set(KEComResourceFileSearch,NULL,&driveName));
       
   439 
       
   440 	// Match the directory list UID's to a Polymorphic DLL UID and Interface
       
   441 	// Implementation Collection UID.
       
   442 	// Resource files are sorted by UID. However, since these files have same UID,
       
   443 	// they are actually sorted by their names (alphanumerically).
       
   444 
       
   445   	TInt error = dir.Open(iFs, searchDir.FullName(), aUidType);
       
   446  
       
   447 	if(error == KErrNone)
       
   448 		{
       
   449 		// Have found the plugin directory
       
   450 		CleanupClosePushL(dir);
       
   451 		
       
   452 		TFileName* lastRscNameBuf = new TFileName;
       
   453 		
       
   454 		if (!lastRscNameBuf) 
       
   455 		{
       
   456 			CleanupStack::PopAndDestroy(&dir); 
       
   457 			return EFalse;
       
   458 		}
       
   459 		CleanupStack::PushL(lastRscNameBuf);
       
   460 		
       
   461 		TEntryArray *dirEntriesArray = new TEntryArray;
       
   462 	 
       
   463 		if (!dirEntriesArray) 
       
   464 		{
       
   465 			CleanupStack::PopAndDestroy(lastRscNameBuf); 
       
   466 			CleanupStack::PopAndDestroy(&dir); 
       
   467 			return EFalse;
       
   468 		}
       
   469 		CleanupStack::PushL(dirEntriesArray);
       
   470 				
       
   471 		
       
   472 		TPtrC lastRscName(KNullDesC);
       
   473 		
       
   474 		// Iterate through the directory reading multiple entries at a 
       
   475 		// time
       
   476 		TInt count = 0;
       
   477 		TInt readError = KErrNone;
       
   478 		CPluginBase* entryBase=NULL;
       
   479 
       
   480  		iDiscoverer.DriveMountedL(aDrive);
       
   481 		TBool anyDllRegistered = iDiscoverer.IsAnyDllRegisteredWithDriveL(aDrive);
       
   482  
       
   483 	 
       
   484 
       
   485 		while (readError != KErrEof)  
       
   486 			{
       
   487 		
       
   488  			// Read the next set of entries
       
   489  			readError =	dir.Read(*dirEntriesArray);
       
   490  				
       
   491 			if ((readError != KErrNone) &&  (readError != KErrEof))
       
   492 				{
       
   493 				User::Leave(readError);	
       
   494 				}
       
   495 			else 
       
   496 				{
       
   497  				// for KErrEof, dirEntriesArray still has items to process 
       
   498 				count = dirEntriesArray->Count();
       
   499  				// Ok use the entries to populate the file list
       
   500 				for(TInt i = 0; i < count; ++i)
       
   501 					{
       
   502  
       
   503  					// Compare current file name against previous one ignoring extension. If it is same
       
   504 					// then there is no need to process it.
       
   505 					TPtrC currName = (*dirEntriesArray)[i].iName.Left((*dirEntriesArray)[i].iName.Length()-KExtensionLength);
       
   506 					if (lastRscName.Compare(currName) == 0)
       
   507 						{
       
   508 						continue;
       
   509 						}
       
   510 					else if (i < (count - 1))
       
   511 						{
       
   512 						lastRscName.Set(currName);
       
   513 						}
       
   514 					else
       
   515 						{
       
   516 						lastRscNameBuf->Copy(currName);
       
   517 						lastRscName.Set(*lastRscNameBuf);
       
   518 						}
       
   519 						
       
   520  
       
   521 					// Obtain a copy of the current directory entry
       
   522 					TRAP(error,iDiscoverer.ValidateEntryL((*dirEntriesArray)[i], driveName, entryBase, aIsRO));			
       
   523 					CleanupStack::PushL(entryBase);		
       
   524  
       
   525 					if (error==KErrNoMemory) 
       
   526 						User::LeaveNoMemory();
       
   527 				
       
   528 					if (error==KErrNone)
       
   529 						{
       
   530 						iDiscoverer.ProcessEntryL(driveName,entryBase,anyDllRegistered);
       
   531  						}
       
   532 					else
       
   533 						{
       
   534 						__ECOM_TRACE1("ECOM: CDiscoverer::DoScanDriveL(). Fail Validate entry: %S\n.",&(*dirEntriesArray)[i].iName);
       
   535 						}		
       
   536 				    CleanupStack::PopAndDestroy(entryBase);
       
   537 					entryBase=NULL;
       
   538 					}
       
   539 				}
       
   540 			}
       
   541  		CleanupStack::PopAndDestroy(dirEntriesArray); 
       
   542 		CleanupStack::PopAndDestroy(lastRscNameBuf); 
       
   543 		CleanupStack::PopAndDestroy(&dir); 
       
   544 		return ETrue; 
       
   545 		}
       
   546 
       
   547 	return EFalse;
       
   548 	}
       
   549 
       
   550 void CDiscoverer::CDirScanner::DiscoverPluginsL(TBool aDiscoverReadOnlyDrives)
       
   551 	{
       
   552 	// iterator which returns only the drives need to be scanned.
       
   553 	TEComCachedDriveInfoIterator iter(*iDiscoverer.iCachedDriveInfo);
       
   554 
       
   555 	// Iterate from highest drive letter (Z:) towards lowest drive letter (A:).
       
   556 	for (iter.Last(); iter.InRange(); iter.Prev())
       
   557 		{
       
   558 		if (iter.DriveIsReadOnlyInternal() == aDiscoverReadOnlyDrives)
       
   559 			{
       
   560 			ScanDriveL(iter.DriveUnit(), aDiscoverReadOnlyDrives);
       
   561 			}
       
   562 		}
       
   563 	}
       
   564 	
       
   565 
       
   566 // __________________________________________________________________________
       
   567 //
       
   568 /*
       
   569 	Responsible for identifying new Interface Implementation Collections,
       
   570 	installed in the Interface Implementation Collection directories.
       
   571 */
       
   572 
       
   573 CDiscoverer* CDiscoverer::NewL(MDiscovererObserver& aDiscovererObserver, RFs& aFs)
       
   574 	{
       
   575 	CDiscoverer* self = new(ELeave) CDiscoverer(aDiscovererObserver, aFs);
       
   576 	CleanupStack::PushL(self);
       
   577 	self->ConstructL();
       
   578 	CleanupStack::Pop(self);
       
   579 	return self;
       
   580 	}
       
   581 
       
   582 // Default d'tor
       
   583 
       
   584 CDiscoverer::~CDiscoverer()
       
   585 	{
       
   586 	// Cancel any scanning behaviour or notifications
       
   587 	if(iDirScanner != NULL)
       
   588 		{
       
   589 		// Left in the middle of a scan
       
   590 		// So clear up
       
   591 		delete iDirScanner;
       
   592 		iDirScanner = NULL;
       
   593 		// Signal the observer that the scan has 
       
   594 		// not been completed successfully.
       
   595 		iDiscovererObserver.DiscoveriesComplete(EFalse, EPluginProcessingTypeAll);
       
   596 		}
       
   597 	Suspend();
       
   598 	iDrivesDiscovered.Reset();
       
   599 	delete iSwiChangeNotifier;
       
   600 	delete iScanningTimer;
       
   601 	delete iLanguageChangeNotifier;
       
   602 	delete iCachedDriveInfo;
       
   603 	iRscDirNotifierList.ResetAndDestroy();
       
   604 
       
   605 	}
       
   606 
       
   607 // Default c'tor
       
   608 CDiscoverer::CDiscoverer(MDiscovererObserver& aDiscovererObserver, RFs& aFs)
       
   609 : CBase(),   iSwiChangeDiscoveryPending(EFalse), iLanguageChangeDiscoveryPending(EFalse),
       
   610   iState(EDisc_Undefined), iDiscovererObserver(aDiscovererObserver), iFs(aFs)
       
   611 	{
       
   612 	// Do nothing here
       
   613 	}
       
   614 
       
   615 void CDiscoverer::ConstructL()
       
   616 	{
       
   617 	iCachedDriveInfo = CEComCachedDriveInfo::NewL(iFs);
       
   618 	
       
   619 	// Construct the Interface Implementation Collection
       
   620 	// directory change notifier list
       
   621 	// and the scan step control object.
       
   622 
       
   623 	CDirChangeNotifier *dirChangeNotifierPtr;
       
   624 
       
   625 	// iterator which returns only the drives need to be scanned.
       
   626 	TEComCachedDriveInfoIterator iter(*iCachedDriveInfo);
       
   627 
       
   628 	for (iter.First(); iter.InRange(); iter.Next())
       
   629 		{
       
   630 		//Don't need to monitor read-only drives. They don't change.
       
   631 		if ( !iter.DriveIsReadOnlyInternal() )
       
   632 			{				
       
   633 			dirChangeNotifierPtr = new(ELeave)CDirChangeNotifier(*this,iFs,iter.DriveUnit());
       
   634 		
       
   635 			CleanupStack::PushL(dirChangeNotifierPtr);				
       
   636 			iRscDirNotifierList.AppendL(dirChangeNotifierPtr);
       
   637 			CleanupStack::Pop();
       
   638 			}
       
   639 		}
       
   640 	iSwiChangeNotifier = CSwiChangeNotifier::NewL(*this);
       
   641 
       
   642 	iScanningTimer = CIdleScanningTimer::NewL(*this);
       
   643 
       
   644 	//Create the language change notifier and install the callback function
       
   645 	const TCallBack myCallBackFunction(&CDiscoverer::LocaleChangedL, this);
       
   646 	iLanguageChangeNotifier = CEnvironmentChangeNotifier::NewL(CActive::EPriorityStandard, myCallBackFunction);
       
   647 	
       
   648 	iDirScanner = CDirScanner::NewL(*this,iFs);	
       
   649 
       
   650 	InitialiseEvent();	
       
   651 	}
       
   652 
       
   653 
       
   654 TInt CDiscoverer::Resume()
       
   655 	{
       
   656 	// Reactivate the scanning timer if not NULL
       
   657 	if (iScanningTimer != NULL)
       
   658 		{
       
   659 		iScanningTimer->Resume();
       
   660 		}
       
   661 	
       
   662 	TCallBackState cbData = ECallBackState_EventEnd;
       
   663 	iBurChangeCallBack.CallBack(ECallBackId_BurEvent, &cbData);
       
   664 
       
   665 	/*
       
   666 	iLanguageChangeNotifier is not activated because it is not cancelled during CDiscoverer::Suspend().
       
   667 	It is not suspended because a language change should not occur whilst a backup/restore operation
       
   668 	is taking place.
       
   669 	*/
       
   670 
       
   671 	return KErrNone;
       
   672 	}
       
   673 
       
   674 
       
   675 TInt CDiscoverer::Suspend()
       
   676 	{
       
   677 	// Suspend the scanning timer if not NULL
       
   678 	if (iScanningTimer != NULL)
       
   679 		{
       
   680 		iScanningTimer->Suspend();
       
   681 		}
       
   682 
       
   683 	TCallBackState cbData = ECallBackState_EventStart;
       
   684 	iBurChangeCallBack.CallBack(ECallBackId_BurEvent, &cbData);
       
   685 
       
   686 	/*
       
   687 	iLanguageChangeNotifier is not cancelled because a language change should not occur
       
   688 	whilst a backup/restore operation is taking place.
       
   689 	*/
       
   690 
       
   691 	return KErrNone;
       
   692 	}
       
   693 
       
   694 
       
   695 TBool CDiscoverer::NotificationL(TInt aStatus, const TDriveUnit& aDriveUnit)
       
   696 	{
       
   697 
       
   698 	TBool okToContinue = ETrue;
       
   699 	if(aStatus != KErrNone)
       
   700 		{
       
   701 		// Big trouble with the notification
       
   702 		// Tell our observer
       
   703 		// Notifications will cease if EFalse is returned!!!!
       
   704 		okToContinue = iDiscovererObserver.NotifiedWithErrorCode(aStatus);	
       
   705 		}
       
   706 	else
       
   707 		{
       
   708 		//call ProcessDNEventL() to indicate Plugins have been added or removed on a specfic drive,
       
   709 		// then do the state transition and to start a re-discovery .
       
   710 		ProcessDNEventL(EPluginsModified,aDriveUnit );
       
   711 		ProcessDNEventL(EPluginsRediscover, aDriveUnit);
       
   712 		}
       
   713 	return okToContinue;
       
   714 	}
       
   715 
       
   716 void CDiscoverer::SwiChangeNotificationL(TInt aSwiOperation)
       
   717 	{
       
   718 	// Store the current SWI operation, ignore operation status
       
   719 	iSwiOperation = aSwiOperation & KSASwisOperationMask;
       
   720 	
       
   721 	TCallBackState cbData = SwiOperationInProgress() ? ECallBackState_EventStart : ECallBackState_EventEnd;
       
   722 	iSwiChangeCallBack.CallBack(ECallBackId_SwiEvent, &cbData);
       
   723 
       
   724 	// Test no SWI operation in progress
       
   725 	if(!SwiOperationInProgress())
       
   726 		{
       
   727 		TBool rediscoveryPending = EFalse;
       
   728 		if(!iSwiChangeDiscoveryPending)
       
   729 			{		 
       
   730 			// for each removable drive call ProcessDNEventL() to do the state transition and to start
       
   731 			// a re-discovery for that drive.
       
   732 			TInt count = iDrivesDiscovered.Count();		
       
   733 			for(TInt i=0; i < count; i++)
       
   734 				{
       
   735 				TDriveUnit drvUnit(iDrivesDiscovered[i]);
       
   736 				if(iCachedDriveInfo->DriveIsRemovableL(drvUnit))
       
   737 					{
       
   738 					rediscoveryPending = ETrue;
       
   739 					ProcessDNEventL(EPluginsModified, drvUnit );
       
   740 					ProcessDNEventL(EPluginsRediscover, drvUnit);
       
   741 					iSwiChangeDiscoveryPending = ETrue;
       
   742 					}
       
   743 				}
       
   744 			}
       
   745 		
       
   746 		//If there are no removable drives to be scanned check if there are any
       
   747 		//pending notifications that couldn't be processed during SWI
       
   748 		if(!rediscoveryPending && iScanningTimer->IsAnyNotificationProcessingPending())
       
   749 			{
       
   750 			// Activate timer if there is any notification processing pending
       
   751 			iScanningTimer->RestartScanPeriod();
       
   752 			}
       
   753 		}
       
   754 	}
       
   755 
       
   756 TBool CDiscoverer::SwiOperationInProgress()
       
   757 	{
       
   758 	return (iSwiOperation != ESASwisNone);
       
   759 	}
       
   760 
       
   761 void CDiscoverer::LanguageChangeNotificationL()
       
   762 	{
       
   763 	if (!iLanguageChangeDiscoveryPending)
       
   764 		{
       
   765 		// for each drive call ProcessDNEventL() to do the state transition and to start
       
   766 		// a re-discovery for that drive.
       
   767 		TInt count = iDrivesDiscovered.Count();
       
   768 		for(TInt i=0; i < count; i++)
       
   769 			{
       
   770 			ProcessDNEventL(EPluginsModified, iDrivesDiscovered[i] );
       
   771 			ProcessDNEventL(EPluginsRediscover, iDrivesDiscovered[i]);
       
   772 			}
       
   773 		iLanguageChangeDiscoveryPending = ETrue;
       
   774 		}
       
   775 	}
       
   776 void CDiscoverer::RediscoveryScanDirectoryL(const TDriveUnit& aDriveUnit) 
       
   777 	{
       
   778 	TBool doScan = EFalse;
       
   779 	if(iDrivesDiscovered.Find(aDriveUnit) != KErrNotFound)
       
   780 		{
       
   781 		// If the drive has plugins on it previously, do ScanDriveL on any notifications.
       
   782 		doScan = ETrue;
       
   783 		}
       
   784 	else // Otherwise the drive doesn't contain any plugin before, do further check.
       
   785 		{
       
   786 		TBuf<KEComPlugRSCPathMaxLen> pluginsDirPath(KEComResourceFolderPath);
       
   787 		pluginsDirPath[0] = ('A' + TInt(aDriveUnit));
       
   788 		TEntry entry;
       
   789 		if(iFs.Entry(pluginsDirPath,entry) == KErrNone)
       
   790 			{
       
   791 			// Now it has plugins folder on it, do ScanDriveL.
       
   792 			doScan = ETrue;
       
   793 			}
       
   794 		// If it still doesn't have plugins folder on it, skip unnecessary scanning.
       
   795 		// NOTE: other returned error code could be KErrPathNotFound, KErrNotReady etc.
       
   796 		//  As long as no plugin has been found, always skip scanning on this drive.
       
   797 		}
       
   798 	
       
   799 	// Performs scanning according to above checks.
       
   800 	if(doScan)
       
   801 		{
       
   802 		// Signal the observer that a scan has commenced.
       
   803 		iDiscovererObserver.DiscoveriesBegin();	
       
   804 		
       
   805 		iDirScanner->ScanDriveL(aDriveUnit, iCachedDriveInfo->DriveIsReadOnlyInternalL(aDriveUnit));
       
   806 		
       
   807 		// Signal the observer that the scan has 
       
   808 		// been completed successfully.
       
   809 		iDiscovererObserver.SetDiscoveryFlagL(aDriveUnit);
       
   810 		}
       
   811 	}
       
   812 
       
   813 void CDiscoverer::ScanDirectoryCancel()
       
   814 	{
       
   815 	if(iDirScanner != NULL)
       
   816 		{
       
   817 		// Signal the observer that the scan has 
       
   818 		// been completed un-successfully.
       
   819 		iDiscovererObserver.DiscoveriesComplete(EFalse, EPluginProcessingTypeAll);
       
   820 		}
       
   821 	}
       
   822 
       
   823 
       
   824 void CDiscoverer::CompleteNotificationProcessing()
       
   825 	{
       
   826 	iState = EDisc_AllPluginsDisc;
       
   827 	iSwiChangeDiscoveryPending = EFalse;
       
   828 	iLanguageChangeDiscoveryPending = EFalse;
       
   829 	}
       
   830 
       
   831 
       
   832 void CDiscoverer::ValidateEntryL(const TEntry& aEntry, const TDriveName& aDriveName, CPluginBase*& aEntryToFill, TBool aIsRO)
       
   833    	{
       
   834 	aEntryToFill=CSecurePlugin::NewL(iFs,aEntry,aDriveName, aIsRO);
       
   835   	}
       
   836 
       
   837 void CDiscoverer::ValidateEntryL(RResourceArchive& aRscArchive,CPluginBase*& aEntryToFill)
       
   838    	{
       
   839     aEntryToFill = CSpiPlugin::NewL(aRscArchive);
       
   840 	}
       
   841   	
       
   842 
       
   843 void CDiscoverer::ProcessEntryL(const TDriveName& aDrive,CPluginBase*& aEntry, TBool aAnyDllDiscovered)
       
   844 	{
       
   845 	iDiscovererObserver.RegisterDiscoveryL(aDrive,aEntry,aAnyDllDiscovered);
       
   846 	}
       
   847 	
       
   848 void CDiscoverer::DriveMountedL(TDriveUnit aDrive)
       
   849 	{
       
   850 	TInt index = iDrivesDiscovered.Find(aDrive);
       
   851 	if(index == KErrNotFound)
       
   852 		{
       
   853 		User::LeaveIfError(iDrivesDiscovered.Append(aDrive));
       
   854 		iDiscovererObserver.DriveReinstatedL(aDrive);	// Wasn't there before
       
   855 		}
       
   856 	}
       
   857 	
       
   858 TBool CDiscoverer::IsAnyDllRegisteredWithDriveL(const TDriveUnit aDrive)const
       
   859 	{
       
   860 	return 	iDiscovererObserver.IsAnyDllRegisteredWithDriveL(aDrive);
       
   861 	}
       
   862 
       
   863 void CDiscoverer::DriveUnmountedL(TDriveUnit aDrive)
       
   864 	{
       
   865 	TInt index = iDrivesDiscovered.Find(aDrive);
       
   866 	if(index != KErrNotFound)
       
   867 		{
       
   868 		iDrivesDiscovered.Remove(index);
       
   869 		iDiscovererObserver.DriveRemovedL(aDrive);		// Was there before
       
   870 		}
       
   871 	}
       
   872 	
       
   873 CDiscoverer::TDiscovererState CDiscoverer::State() const
       
   874 	{
       
   875 	return iState;
       
   876 	}
       
   877 
       
   878 	
       
   879 void CDiscoverer::ProcessSSAEventL(TStartupStateIdentifier aKnownState)
       
   880 	{
       
   881 
       
   882 	if(iState == EDisc_NoPluginsDisc && aKnownState == EStartupStateCriticalStatic)
       
   883 		{
       
   884 		__ECOM_TRACE("ECOM: CDiscoverer::ProcessSSAEventL():EStartupStateCriticalStatic is reached,discover the RO Internal drives only.");
       
   885 
       
   886 		// Signal the observer that the scanning is started
       
   887 		iDiscovererObserver.DiscoveriesBegin();
       
   888 		
       
   889 		//scan the RO drives
       
   890 	    iDirScanner->DiscoverPluginsL(ETrue);
       
   891 
       
   892 		//change the state
       
   893 		iState = EDisc_CriticalPluginsDisc;
       
   894 
       
   895 		// Signal the observer that the scan has 
       
   896 		// been completed successfully.
       
   897 		iDiscovererObserver.DiscoveriesComplete(ETrue, EPluginProcessingTypeCriticalOnly);
       
   898 		}
       
   899 	else if(iState == EDisc_CriticalPluginsDisc && aKnownState == EStartupStateNonCritical)
       
   900 		{
       
   901 		__ECOM_TRACE("ECOM: CDiscoverer::ProcessSSAEventL():EStartupStateNonCritical is reached,discover the Non RO Internal drives.");
       
   902 
       
   903 		// Signal the observer that the scanning is started
       
   904 		iDiscovererObserver.DiscoveriesBegin();
       
   905 		
       
   906 		//scan the non-ro drives
       
   907 		iDirScanner->DiscoverPluginsL(EFalse);
       
   908 	
       
   909 		//change the state
       
   910 		iState = EDisc_AllPluginsDisc;
       
   911 		
       
   912 		// Signal the observer that the scan has 
       
   913 		// been completed successfully.
       
   914 		iDiscovererObserver.DiscoveriesComplete(ETrue, EPluginProcessingTypeNonCriticalOnly);
       
   915 
       
   916 	
       
   917 		StartNotifiers();		
       
   918 		}
       
   919 	else if(iState == EDisc_NoPluginsDisc && aKnownState == EStartupStateNonCritical)
       
   920 		{
       
   921 		__ECOM_TRACE("ECOM: CDiscoverer::ProcessSSAEventL():EStartupStateNonCritical is reached all at once,discover all the drives.");
       
   922 
       
   923 		// Signal the observer that the scanning is started
       
   924 		iDiscovererObserver.DiscoveriesBegin();
       
   925 		
       
   926 		//scan a specified the drives
       
   927 		iDirScanner->DiscoverPluginsL(ETrue);
       
   928 		iDirScanner->DiscoverPluginsL(EFalse);
       
   929 
       
   930 		//change the state
       
   931 		iState = EDisc_AllPluginsDisc;
       
   932 		
       
   933 		// Signal the observer that the scan has 
       
   934 		// been completed successfully.
       
   935 		iDiscovererObserver.DiscoveriesComplete(ETrue, EPluginProcessingTypeAll);
       
   936 
       
   937 		StartNotifiers();
       
   938 		}
       
   939 	}
       
   940 	
       
   941 void CDiscoverer::StartNotifiers()
       
   942 	{
       
   943 		
       
   944 	for(TInt i = 0; i<iRscDirNotifierList.Count(); i++)
       
   945 		{
       
   946 		if (iRscDirNotifierList[i] != NULL)
       
   947 		iRscDirNotifierList[i]->Activate();
       
   948 		}
       
   949 	iSwiChangeNotifier->Subscribe();
       
   950 	iLanguageChangeNotifier->Start();
       
   951 	}
       
   952 	
       
   953 void CDiscoverer::ProcessDNEventL(TNotificationFlag aFlag, const TDriveUnit& aDriveUnit)
       
   954 	{
       
   955 	if(iState == EDisc_AllPluginsDisc && aFlag == EPluginsModified)
       
   956 		{
       
   957 		iState = EDisc_PluginsDirty;
       
   958 		return;	
       
   959 		}
       
   960 	if(iState == EDisc_PluginsDirty && aFlag == EPluginsRediscover)
       
   961 		{
       
   962 		// Add drive number to the pending drive list and activate timer.
       
   963 		iScanningTimer->AddDriveL(aDriveUnit);
       
   964 		iScanningTimer->RestartScanPeriod();
       
   965 		}
       
   966 	}
       
   967 	
       
   968 void CDiscoverer::SetSwiChangeCallBack(const TCallBackWithArg& aCallBack)
       
   969 	{
       
   970 	iSwiChangeCallBack = aCallBack;
       
   971 	}
       
   972 
       
   973 void CDiscoverer::SetBurChangeCallBack(const TCallBackWithArg& aCallBack)
       
   974 	{
       
   975 	iBurChangeCallBack = aCallBack;
       
   976 	}
       
   977 
       
   978 void CDiscoverer::InitialiseEvent()
       
   979 	{
       
   980 	iState = EDisc_NoPluginsDisc;
       
   981 	}
       
   982 TInt CDiscoverer::LocaleChangedL(TAny* aPtr)
       
   983 	{
       
   984 	CDiscoverer* thisLocaleManager = (CDiscoverer *) aPtr ;
       
   985 	
       
   986 	if(!thisLocaleManager->iLanguageChangeNotifier)	
       
   987 		{
       
   988 	    __ECOM_TRACE("ECOM: LocaleChangedL: Bad Change Notification");
       
   989 		return KErrGeneral;
       
   990 		}
       
   991 
       
   992  	TInt stat = thisLocaleManager->iLanguageChangeNotifier->Change();
       
   993 	if((stat & EChangesLocale) && (!thisLocaleManager->iLanguageChangeDiscoveryPending))
       
   994 	   	{
       
   995 	   	//
       
   996 	   	// System Locale data has been updated 
       
   997 	   	// if the downgrade path has changed we 
       
   998 		// re-scan resource files for all drives and get the right language.
       
   999 		TBool isLanguageChanged;
       
  1000 		thisLocaleManager->iDiscovererObserver.LanguageChangedL(isLanguageChanged);
       
  1001 		if(isLanguageChanged)
       
  1002 			{
       
  1003 			thisLocaleManager->LanguageChangeNotificationL();
       
  1004 			}
       
  1005 	   	}
       
  1006 	 return KErrNone;
       
  1007 	}