|
1 /* |
|
2 * Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "daemonbehaviour.h" |
|
20 #include "swispubsubdefs.h" |
|
21 #include "recsisx.h" |
|
22 #include "sisregistrywritablesession.h" |
|
23 #include "sisregistryentry.h" |
|
24 #include "filesisdataprovider.h" |
|
25 #include "swi/sisparser.h" |
|
26 #include "swi/siscontents.h" |
|
27 #include "swi/siscontroller.h" |
|
28 #include "sisinfo.h" |
|
29 #include "cleanuputils.h" |
|
30 #include "sisregistrypackage.h" |
|
31 #include "log.h" |
|
32 |
|
33 void ScanDirectoryL(TInt aDrive); |
|
34 |
|
35 using namespace Swi; |
|
36 |
|
37 CDaemonBehaviour* CDaemonBehaviour::NewL() |
|
38 { |
|
39 CDaemonBehaviour* self = NewLC(); |
|
40 CleanupStack::Pop(self); |
|
41 return self; |
|
42 } |
|
43 |
|
44 CDaemonBehaviour* CDaemonBehaviour::NewLC() |
|
45 { |
|
46 CDaemonBehaviour* self = new (ELeave) CDaemonBehaviour; |
|
47 CleanupStack::PushL(self); |
|
48 self->ConstructL(); |
|
49 return self; |
|
50 } |
|
51 |
|
52 void CDaemonBehaviour::ConstructL() |
|
53 { |
|
54 User::LeaveIfError(iFs.Connect()); |
|
55 User::LeaveIfError(iFs.ShareProtected()); |
|
56 User::LeaveIfError(iApaSession.Connect()); |
|
57 iSisInstaller = CSisInstaller::NewL(this); |
|
58 TRAP_IGNORE(iSwiDaemonPlugin = CSwiDaemonPlugin::NewL()); |
|
59 } |
|
60 |
|
61 CDaemonBehaviour::~CDaemonBehaviour() |
|
62 { |
|
63 if(iSwiDaemonPlugin) |
|
64 { |
|
65 delete iSwiDaemonPlugin; |
|
66 REComSession::FinalClose(); |
|
67 } |
|
68 delete iSisInstaller; |
|
69 iFs.Close(); |
|
70 iApaSession.Close(); |
|
71 } |
|
72 |
|
73 // from MDaemonBehaviour |
|
74 TBool CDaemonBehaviour::StartupL() |
|
75 { |
|
76 // Return state of Startup |
|
77 return ETrue; |
|
78 } |
|
79 |
|
80 void CDaemonBehaviour::MediaChangeL(TInt aDrive, TChangeType aChangeType) |
|
81 { |
|
82 DEBUG_PRINTF3(_L8("SWI Daemon - Media change detected. Drive: %d, Change Type: %d."), |
|
83 aDrive, aChangeType); |
|
84 |
|
85 RSisRegistryWritableSession registrySession; |
|
86 |
|
87 User::LeaveIfError(registrySession.Connect()); |
|
88 CleanupClosePushL(registrySession); |
|
89 |
|
90 if (aChangeType==EMediaInserted) |
|
91 { |
|
92 // notify IAR |
|
93 registrySession.AddDriveL(aDrive); |
|
94 |
|
95 // Scan directory on the card and run pre-installed through SWIS |
|
96 // nb. will leave if no SIS files to install. |
|
97 ProcessPreinstalledFilesL(aDrive); |
|
98 } |
|
99 else if (aChangeType==EMediaRemoved) |
|
100 { |
|
101 // Cancel all requests for install |
|
102 iSisInstaller->Reset(); |
|
103 |
|
104 // Notify plugin |
|
105 if(iSwiDaemonPlugin) |
|
106 { |
|
107 iSwiDaemonPlugin->MediaRemoved(aDrive); |
|
108 } |
|
109 |
|
110 #ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK |
|
111 // notify IAR |
|
112 registrySession.RemoveDriveL(aDrive); |
|
113 #endif |
|
114 } |
|
115 CleanupStack::PopAndDestroy(®istrySession); |
|
116 } |
|
117 |
|
118 void CDaemonBehaviour::ProcessPreinstalledFilesL(TInt aDrive) |
|
119 { |
|
120 _LIT(KDaemonPrivatePath,":\\private\\10202dce\\"); |
|
121 |
|
122 iSisInstaller->Reset(); |
|
123 ProcessPreinstalledFilesL(aDrive, KDaemonPrivatePath); |
|
124 iStartNotified = EFalse; |
|
125 iDrive = aDrive; |
|
126 iSisInstaller->StartInstallingL(); |
|
127 } |
|
128 |
|
129 void CDaemonBehaviour::ProcessPreinstalledFilesL(TInt aDrive, const TDesC& aDirectory) |
|
130 { |
|
131 TPath preInstalledPath; |
|
132 TChar drive; |
|
133 RFs::DriveToChar(aDrive, drive); |
|
134 preInstalledPath.Append(drive); |
|
135 preInstalledPath.Append(aDirectory); |
|
136 |
|
137 CDir* dir = NULL; |
|
138 TInt err = iFs.GetDir(preInstalledPath, KEntryAttNormal, ESortByName, dir); |
|
139 if (err != KErrNone && err != KErrPathNotFound) |
|
140 { |
|
141 User::Leave(err); |
|
142 } |
|
143 if(dir) |
|
144 { |
|
145 // dir will only exist if GetDir succeeded |
|
146 CleanupStack::PushL(dir); |
|
147 for(TInt i = 0; i < dir->Count(); i++) |
|
148 { |
|
149 const TEntry &entry = (*dir)[i]; |
|
150 if(!entry.IsDir()) |
|
151 { |
|
152 TFileName fileName(preInstalledPath); |
|
153 fileName.Append(entry.iName); |
|
154 iSisInstaller->AddFileToInstallL(fileName); |
|
155 } |
|
156 } |
|
157 CleanupStack::PopAndDestroy(dir); |
|
158 } |
|
159 } |
|
160 |
|
161 |
|
162 // From MDaemonInstallBehaviour |
|
163 |
|
164 MDaemonInstallBehaviour::TSisInstallState CDaemonBehaviour::VerifyAppCacheListL() |
|
165 { |
|
166 MDaemonInstallBehaviour::TSisInstallState returnState = MDaemonInstallBehaviour::EStateVerifyAppCacheList; |
|
167 |
|
168 // What is really desired is notification that the Application Architecture cached List |
|
169 // is valid, but as this cannot be done simply. |
|
170 // Is is simulated by a call to two member functions. |
|
171 |
|
172 TApaAppInfo appInfo; |
|
173 User::LeaveIfError(iApaSession.GetAllApps()); |
|
174 TInt err(iApaSession.GetNextApp(appInfo)); // Call member function that can report an EAppListInvalid |
|
175 |
|
176 if (err == RApaLsSession::EAppListInvalid) |
|
177 { |
|
178 returnState = MDaemonInstallBehaviour::EStateVerifyAppCacheList; |
|
179 } |
|
180 else if (err == KErrNone) // cached list of apps is ready |
|
181 { |
|
182 returnState = MDaemonInstallBehaviour::EStateVerifySwisProperty; |
|
183 } |
|
184 else |
|
185 { |
|
186 User::Leave(err); |
|
187 } |
|
188 return returnState; |
|
189 } |
|
190 |
|
191 MDaemonInstallBehaviour::TSisInstallState CDaemonBehaviour::VerifySwisPropertyL() |
|
192 { |
|
193 MDaemonInstallBehaviour::TSisInstallState returnState = MDaemonInstallBehaviour::EStateVerifySwisProperty; |
|
194 TInt swisState; |
|
195 TInt err(RProperty::Get(KUidSystemCategory,KUidSoftwareInstallKey,swisState)); |
|
196 |
|
197 if (err == KErrNotFound) |
|
198 { |
|
199 returnState = (MDaemonInstallBehaviour::EStateInstall); |
|
200 } |
|
201 else if (err == KErrNone) |
|
202 { |
|
203 if (swisState == ESwisNone) |
|
204 { |
|
205 // SWIS is idle |
|
206 returnState = (MDaemonInstallBehaviour::EStateInstall); |
|
207 } |
|
208 else |
|
209 { |
|
210 // SWIS is performing an operation |
|
211 returnState = (MDaemonInstallBehaviour::EStateVerifySwisIdle); |
|
212 } |
|
213 } |
|
214 else |
|
215 { |
|
216 User::Leave(err); |
|
217 } |
|
218 return returnState; |
|
219 } |
|
220 |
|
221 MDaemonInstallBehaviour::TSisInstallState CDaemonBehaviour::VerifySwisIdleL() |
|
222 { |
|
223 MDaemonInstallBehaviour::TSisInstallState returnState = MDaemonInstallBehaviour::EStateVerifySwisIdle; |
|
224 TInt swisState; |
|
225 |
|
226 // Obtain the state of the software installer |
|
227 User::LeaveIfError(RProperty::Get(KUidSystemCategory,KUidSoftwareInstallKey,swisState)); |
|
228 |
|
229 if (swisState == ESwisNone) // Swis is idle |
|
230 { |
|
231 returnState = (MDaemonInstallBehaviour::EStateInstall); |
|
232 } |
|
233 else // Software installer is currently installing/uinstalling |
|
234 { |
|
235 returnState = (MDaemonInstallBehaviour::EStateVerifySwisIdle); |
|
236 } |
|
237 return returnState; |
|
238 } |
|
239 |
|
240 void CDaemonBehaviour::ReadSymbianHeaderL(RFile& aFile, TUid& aUid1, TUid& aUid2, TUid& aUid3) |
|
241 { |
|
242 |
|
243 TInt uidLen = sizeof(TInt32); |
|
244 |
|
245 TPckg<TInt32> uid1(aUid1.iUid); |
|
246 User::LeaveIfError(aFile.Read(uid1, uidLen)); |
|
247 if (uid1.Length() != uidLen) |
|
248 { |
|
249 User::Leave(KErrUnderflow); |
|
250 } |
|
251 |
|
252 TPckg<TInt32> uid2(aUid2.iUid); |
|
253 User::LeaveIfError(aFile.Read(uid2, uidLen)); |
|
254 if (uid1.Length() != uidLen) |
|
255 { |
|
256 User::Leave(KErrUnderflow); |
|
257 } |
|
258 |
|
259 TPckg<TInt32> uid3(aUid3.iUid); |
|
260 User::LeaveIfError(aFile.Read(uid3, uidLen)); |
|
261 if (uid1.Length() != uidLen) |
|
262 { |
|
263 User::Leave(KErrUnderflow); |
|
264 } |
|
265 |
|
266 } |
|
267 |
|
268 void CDaemonBehaviour::DoInstallRequestL(const TDesC& aFileName) |
|
269 { |
|
270 DEBUG_PRINTF2(_L("SWI Daemon - Processing presinstalled SIS file '%S'"), |
|
271 &aFileName); |
|
272 |
|
273 TUid appUid; |
|
274 TDataType dataType; |
|
275 |
|
276 User::LeaveIfError(iFs.ShareProtected()); |
|
277 |
|
278 // have to pass the file using the file handle |
|
279 // otherwise SisHelper won't be able to read the |
|
280 // daemon private directory |
|
281 RFile file; |
|
282 User::LeaveIfError(file.Open(iFs, aFileName, EFileRead | EFileStream | EFileShareReadersOnly)); |
|
283 CleanupClosePushL(file); |
|
284 User::LeaveIfError(iApaSession.AppForDocument(file,appUid,dataType)); |
|
285 |
|
286 // Start installing the file only if it is a sisx file |
|
287 if (dataType.Des8() == KDataTypeSisx) |
|
288 { |
|
289 |
|
290 // Check if this is already installed, by extracting the package UID and |
|
291 // asking the registry. |
|
292 |
|
293 TUid uid1, uid2, uid3; |
|
294 ReadSymbianHeaderL(file, uid1, uid2, uid3); |
|
295 |
|
296 |
|
297 // UID 3 will be the package UID, query the registry about it. |
|
298 RSisRegistrySession session; |
|
299 User::LeaveIfError(session.Connect()); |
|
300 CleanupClosePushL(session); |
|
301 |
|
302 // temporary work around while we decide what IsInstalled should be policed by. |
|
303 |
|
304 RSisRegistryEntry entry; |
|
305 TInt entryOpenResult = entry.Open(session, uid3); |
|
306 CleanupClosePushL(entry); |
|
307 |
|
308 // Get the types and other details from the stub |
|
309 CFileSisDataProvider* fileProvider = CFileSisDataProvider::NewLC(iFs, aFileName, EFileRead | EFileShareReadersOnly); |
|
310 TInt64 pos( 0 ); |
|
311 fileProvider->Seek( ESeekStart, pos ); |
|
312 Swi::Sis::CContents* content = Swi::Sis::Parser::ContentsL(*fileProvider); |
|
313 CleanupStack::PushL( content ); |
|
314 HBufC8* controllerdata = content->ReadControllerL(); |
|
315 CleanupStack::PushL( controllerdata ); |
|
316 TPtrProvider provider(controllerdata->Des()); |
|
317 Sis::CController *siscontroller = Swi::Sis::CController::NewLC(provider); |
|
318 |
|
319 switch(siscontroller->Info().InstallType()) |
|
320 { |
|
321 /* For SA/PA, If UID is found in registry, Don't install otherwise Install */ |
|
322 case EInstInstallation: |
|
323 case EInstPreInstalledApp: |
|
324 { |
|
325 if(entryOpenResult != KErrNone) |
|
326 { |
|
327 DoInstallL(file,appUid); |
|
328 } |
|
329 |
|
330 break; |
|
331 } |
|
332 /* |
|
333 For PP/SP, If patch name is found already in registry, Don't install |
|
334 otherwise Install |
|
335 */ |
|
336 case EInstPreInstalledPatch: |
|
337 case EInstAugmentation: |
|
338 { |
|
339 TBool shouldInstall = ETrue; |
|
340 const RPointerArray<CString>& names = siscontroller->Info().Names(); |
|
341 RPointerArray<CSisRegistryPackage> augmentations; |
|
342 |
|
343 // If Base package is not available then don't do anything and break the case. |
|
344 if (entryOpenResult != KErrNone) |
|
345 { |
|
346 break; |
|
347 } |
|
348 |
|
349 //Get the Augmentation and Install if augmentation doesn't match |
|
350 CleanupResetAndDestroy<RPointerArray<CSisRegistryPackage> >::PushL(augmentations); |
|
351 entry.AugmentationsL(augmentations); |
|
352 for (TInt i = 0; i < augmentations.Count(); ++i) |
|
353 { |
|
354 for (TInt j =0; j < names.Count(); ++j) |
|
355 { |
|
356 if ((uid3 == augmentations[i]->Uid()) && |
|
357 (augmentations[i]->Name() == names[j]->Data())) |
|
358 { |
|
359 shouldInstall=EFalse; |
|
360 break; |
|
361 } |
|
362 } |
|
363 } |
|
364 |
|
365 if(shouldInstall) |
|
366 { |
|
367 DoInstallL(file,appUid); |
|
368 } |
|
369 |
|
370 CleanupStack::PopAndDestroy(&augmentations); |
|
371 break; |
|
372 } |
|
373 |
|
374 default: |
|
375 /* |
|
376 If SA/PA/SP/PP is not the case we can't handle because |
|
377 PU has never been supported for SwiDaemon according to FS. |
|
378 */ |
|
379 ASSERT(EFalse); |
|
380 |
|
381 } |
|
382 |
|
383 CleanupStack::PopAndDestroy(6, &session); |
|
384 |
|
385 } // End of SISX file condition |
|
386 |
|
387 CleanupStack::PopAndDestroy(&file); // close |
|
388 } |
|
389 |
|
390 void CDaemonBehaviour::DoNotifyMediaProcessingComplete() |
|
391 { |
|
392 if(iSwiDaemonPlugin && iStartNotified) |
|
393 { |
|
394 iSwiDaemonPlugin->MediaProcessingComplete(); |
|
395 } |
|
396 } |
|
397 |
|
398 void CDaemonBehaviour::DoInstallL(RFile &file, const TUid &appUid) |
|
399 { |
|
400 |
|
401 // Rewind file |
|
402 TInt pos = 0; |
|
403 file.Seek(ESeekStart, pos); |
|
404 |
|
405 if(iSwiDaemonPlugin) |
|
406 { |
|
407 DEBUG_PRINTF(_L8("SWI Daemon - Using external plugin to process install")); |
|
408 |
|
409 if(!iStartNotified) |
|
410 { |
|
411 iSwiDaemonPlugin->MediaProcessingStart(iDrive); |
|
412 iStartNotified = ETrue; |
|
413 } |
|
414 iSwiDaemonPlugin->RequestInstall(file); |
|
415 } |
|
416 |
|
417 else |
|
418 { |
|
419 DEBUG_PRINTF(_L8("SWI Daemon - Using internal logic to process install")); |
|
420 |
|
421 TThreadId threadId; |
|
422 User::LeaveIfError(iApaSession.StartDocument(file,appUid,threadId)); |
|
423 |
|
424 RThread thread; |
|
425 User::LeaveIfError(thread.Open(threadId)); |
|
426 CleanupClosePushL(thread); |
|
427 |
|
428 // Wait for the installer to terminate before launching another install. |
|
429 |
|
430 TRequestStatus status; |
|
431 thread.Logon(status); |
|
432 User::WaitForRequest(status); |
|
433 CleanupStack::PopAndDestroy(&thread); |
|
434 } |
|
435 } |