|
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 } |