|
1 /* |
|
2 * Copyright (c) 2008 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 "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: OMJ S60 preinstaller process |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32base.h> |
|
20 #include <pathinfo.h> |
|
21 #include <driveinfo.h> |
|
22 #include <javastorageentry.h> |
|
23 #include <javastorage.h> |
|
24 #include <javastoragenames.h> |
|
25 #include <utf.h> |
|
26 |
|
27 #include "silentmidletinstall.h" |
|
28 #include "javacommonutils.h" |
|
29 #include "logger.h" |
|
30 #include "javaprocessconstants.h" |
|
31 #include "javasymbianoslayer.h" |
|
32 |
|
33 using namespace java::storage; |
|
34 using namespace java::util; |
|
35 |
|
36 |
|
37 // MIDlet name and vendor max size is 255, |
|
38 // +1 added for terminating zero needed for logging |
|
39 const TInt KMaxBufferSize = 256; |
|
40 |
|
41 // character constants needed when parsing java attributes |
|
42 const TUint32 HT = 9; // horizontal tab |
|
43 const TUint32 LF = 10; // line feed |
|
44 const TUint32 CR = 13; // carriage return |
|
45 const TUint32 SP = 32; // space |
|
46 const TUint32 COLON = 58; // ':' |
|
47 |
|
48 const int INSTALLED = 0; |
|
49 const int NO_PREINSTALL = 2; |
|
50 |
|
51 _LIT(KMidletName, "MIDlet-Name"); |
|
52 _LIT(KMidletVendor, "MIDlet-Vendor"); |
|
53 _LIT(KMidletVersion, "MIDlet-Version"); |
|
54 |
|
55 _LIT(KJadExtension, "*.jad"); |
|
56 |
|
57 // Java Installer Integrity Service journal file name |
|
58 _LIT(KISJournalFile, "\\private\\102033E6\\installer\\is\\isjournal.dat"); |
|
59 |
|
60 // The directory where the java applications to be preinstalled are searched |
|
61 // from |
|
62 _LIT(KPreinstallDir, ":\\resource\\java\\preinstall\\"); |
|
63 |
|
64 |
|
65 /** |
|
66 * To create new instance of this class. |
|
67 * |
|
68 * @param aFs - A reference to the file server. |
|
69 * @return Reference to the object of this class. |
|
70 * @exception If construction fails. |
|
71 */ |
|
72 CSilentMIDletInstall* CSilentMIDletInstall::NewLC(RFs& aFs) |
|
73 { |
|
74 CSilentMIDletInstall* self = new(ELeave) CSilentMIDletInstall(aFs); |
|
75 CleanupStack::PushL(self); |
|
76 self->ConstructL(); |
|
77 return self; |
|
78 } |
|
79 |
|
80 /** |
|
81 * To do 1st phase construction for this object. |
|
82 * Adds this active object to the scheduler. |
|
83 * |
|
84 * @param aFs - A reference to the file server. |
|
85 */ |
|
86 CSilentMIDletInstall::CSilentMIDletInstall(RFs& aFs) : |
|
87 CActive(EPriorityStandard), iFs(aFs) |
|
88 { |
|
89 CActiveScheduler::Add(this); |
|
90 } |
|
91 |
|
92 /** |
|
93 * To do 2nd phase construction for this object. |
|
94 * |
|
95 * @exception If the method is not able to allocate necessary buffers. |
|
96 */ |
|
97 void CSilentMIDletInstall::ConstructL() |
|
98 { |
|
99 JELOG2(EJavaPreinstaller); |
|
100 iMIDletName = HBufC::NewL(KMaxBufferSize); |
|
101 iMIDletVendor = HBufC::NewL(KMaxBufferSize); |
|
102 iPreinstallServer = new(ELeave) PreinstallCommsServer(); |
|
103 |
|
104 iNumberOfAppsToInstall = 0; |
|
105 iISRollbackNeeded = EFalse; |
|
106 } |
|
107 |
|
108 /** |
|
109 * Deletes this object. |
|
110 * All allocated resources are released. |
|
111 */ |
|
112 CSilentMIDletInstall::~CSilentMIDletInstall() |
|
113 { |
|
114 JELOG2(EJavaPreinstaller); |
|
115 iJadFiles.ResetAndDestroy(); |
|
116 iJadFiles.Close(); |
|
117 |
|
118 iDirs.ResetAndDestroy(); |
|
119 iDirs.Close(); |
|
120 |
|
121 delete iMIDletName; |
|
122 iMIDletName = NULL; |
|
123 |
|
124 delete iMIDletVendor; |
|
125 iMIDletVendor = NULL; |
|
126 |
|
127 delete iPreinstallServer; |
|
128 iPreinstallServer = NULL; |
|
129 } |
|
130 |
|
131 /** |
|
132 * To start silent preinstallations. |
|
133 */ |
|
134 void CSilentMIDletInstall::Start() |
|
135 { |
|
136 JELOG2(EJavaPreinstaller); |
|
137 iState = EFindOutDeviceDrives; |
|
138 |
|
139 // Check if an explicit roll-back of a previous installation is needed |
|
140 // in the case there is nothing to pre-install (if there is something |
|
141 // to pre-install, the potential roll-back is done automatically) |
|
142 TUint attrs; |
|
143 TInt err = iFs.Att(KISJournalFile, attrs); |
|
144 LOG1(EJavaPreinstaller, EInfo, |
|
145 "Checking IS journal file \\private\\102033E6\\installer\\is\\isjournal.dat, status %d", err); |
|
146 if ((KErrNotFound == err) || (KErrPathNotFound == err)) |
|
147 { |
|
148 iISRollbackNeeded = EFalse; |
|
149 } |
|
150 else |
|
151 { |
|
152 iISRollbackNeeded = ETrue; |
|
153 // If JavaInstaller is running, then existence of the Java Installer |
|
154 // integrity service directory is ok and rollback is not needed |
|
155 TFullName processName; |
|
156 _LIT(KJavaInstallerProcess, "*Installer*"); |
|
157 TFindProcess finder(KJavaInstallerProcess); |
|
158 err = finder.Next(processName); |
|
159 if (err == KErrNone) |
|
160 { |
|
161 iISRollbackNeeded = EFalse; |
|
162 WLOG(EJavaPreinstaller, |
|
163 "Java Installer is running while checking need to rollback"); |
|
164 } |
|
165 } |
|
166 |
|
167 CompleteRequest(); |
|
168 } |
|
169 |
|
170 /** |
|
171 * To stop whole preinstaller. |
|
172 * Stops the active scheduler. |
|
173 */ |
|
174 void CSilentMIDletInstall::Exit() |
|
175 { |
|
176 CActiveScheduler::Stop(); |
|
177 } |
|
178 |
|
179 /** |
|
180 * Completes the current request for this object and |
|
181 * sets this active object to active state. |
|
182 * |
|
183 * @Postconditions The following conditions are true immediately after |
|
184 * returning from this method. |
|
185 * - iStatus == KErrNone |
|
186 * - IsActive() == ETrue |
|
187 */ |
|
188 void CSilentMIDletInstall::CompleteRequest() |
|
189 { |
|
190 JELOG2(EJavaPreinstaller); |
|
191 |
|
192 TRequestStatus *status = &iStatus; |
|
193 User::RequestComplete(status, KErrNone); |
|
194 if (!IsActive()) |
|
195 { |
|
196 SetActive(); |
|
197 } |
|
198 } |
|
199 |
|
200 /** |
|
201 * To run this active object. |
|
202 * |
|
203 * This object goes through the following states in the order the states |
|
204 * are listed below: |
|
205 * |
|
206 * EFindOutDeviceDrives: find out all non-remote drives in the device |
|
207 * - mark externally mountable drives (removable drives) |
|
208 * - mark read only drives (ROM) |
|
209 * |
|
210 * EFindOutDrivesToBeScannedNow: make list of drives to be scanned |
|
211 * - start with all mounted drives |
|
212 * |
|
213 * EAppsInPreinstallDirectories: go through all drives in the list and |
|
214 * find all java applications in the preinstall directory |
|
215 * - only the .jad file is checked but remember that downloading .jar is not |
|
216 * allowed when preinstalling so the .jar file referred to in the .jad |
|
217 * file must be in the device |
|
218 * |
|
219 * ECheckWhichAppsShouldBeInstalled: for each java application check from |
|
220 * Java Storage whether it should be installed |
|
221 * - if same or newer version already installed, do not install |
|
222 * - if the user has uninstalled same or newer version, do not install |
|
223 * - unsigned java applications can be installed only in debug builds |
|
224 * |
|
225 * EExecutePreinstallServer: |
|
226 * - store list of .jad files to preinstall server object, |
|
227 * - start Java Installer in poll mode, |
|
228 * - start preinstall server in another thread and wait until Java Installer exits |
|
229 * - preinstall server will give the names of the .jad files to |
|
230 * Java Installer when it polls them, |
|
231 * - preinstall server will log whether each installation succeeded. |
|
232 * - After all .jad files have been polled, preinstall server will ask |
|
233 * Java Installer to exit. |
|
234 * - when Java Installer exits, this active object moves to next state. |
|
235 * |
|
236 * EExit: |
|
237 * - stop preinstall server thread |
|
238 * - notify possibly waiting processes that preinstallation has been done |
|
239 * - exit |
|
240 * |
|
241 */ |
|
242 void CSilentMIDletInstall::RunL() |
|
243 { |
|
244 JELOG2(EJavaPreinstaller); |
|
245 |
|
246 switch (iState) |
|
247 { |
|
248 case EFindOutDeviceDrives: |
|
249 { |
|
250 LOG(EJavaPreinstaller, EInfo, |
|
251 "CSilentMIDletInstall:RunL EFindOutDeviceDrives"); |
|
252 GetAllDeviceDrivesL(); |
|
253 iState = EFindOutDirectoriesToBeScannedNow; |
|
254 CompleteRequest(); |
|
255 } |
|
256 break; |
|
257 |
|
258 case EFindOutDirectoriesToBeScannedNow: |
|
259 { |
|
260 LOG(EJavaPreinstaller, EInfo, |
|
261 "CSilentMIDletInstall:RunL EFindOutDirectoriesToBeScannedNow"); |
|
262 |
|
263 GetDirsToBeScannedL(); |
|
264 |
|
265 iState = EAppsInPreinstallDirectories; |
|
266 CompleteRequest(); |
|
267 } |
|
268 break; |
|
269 |
|
270 case EAppsInPreinstallDirectories: |
|
271 { |
|
272 LOG(EJavaPreinstaller, EInfo, |
|
273 "CSilentMIDletInstall:RunL EAppsInPreinstallDirectories"); |
|
274 |
|
275 GetMIDletFilesL(iDirs); |
|
276 |
|
277 iState = ECheckWhichAppsShouldBeInstalled; |
|
278 CompleteRequest(); |
|
279 } |
|
280 break; |
|
281 |
|
282 case ECheckWhichAppsShouldBeInstalled: |
|
283 { |
|
284 LOG(EJavaPreinstaller, EInfo, |
|
285 "CSilentMIDletInstall:RunL ECheckWhichAppsShouldBeInstalled"); |
|
286 |
|
287 CheckWhichAppsShouldBeInstalledL(); |
|
288 |
|
289 iState = EExecutePreinstallServer; |
|
290 CompleteRequest(); |
|
291 } |
|
292 break; |
|
293 |
|
294 case EExecutePreinstallServer: |
|
295 { |
|
296 LOG(EJavaPreinstaller, EInfo, |
|
297 "CSilentMIDletInstall:RunL EExecutePreinstallServer"); |
|
298 |
|
299 // This method advances the state machine to EExit state |
|
300 ExecutePreinstallServerL(); |
|
301 } |
|
302 break; |
|
303 |
|
304 case EExit: |
|
305 { |
|
306 LOG(EJavaPreinstaller, EInfo, |
|
307 "CSilentMIDletInstall:RunL EExit"); |
|
308 |
|
309 // Stop the server if it is running |
|
310 iPreinstallServer->stop(); |
|
311 |
|
312 // Java Captain starts preinstaller each time a mountable drive |
|
313 // is added to the device. There is no need to wait for mount |
|
314 // events in this process. |
|
315 |
|
316 // Stop the whole preinstaller process. |
|
317 Exit(); |
|
318 } |
|
319 break; |
|
320 |
|
321 } // switch |
|
322 } |
|
323 |
|
324 /** |
|
325 * To handle leave from RunL. |
|
326 * This method re-activates this active object. |
|
327 * After calling this method this active object is in stable state and |
|
328 * ready to continue its execution |
|
329 * |
|
330 * @param aError - A reason of error. |
|
331 * @return KErrNone. |
|
332 */ |
|
333 TInt CSilentMIDletInstall::RunError(TInt aError) |
|
334 { |
|
335 ELOG2(EJavaPreinstaller, |
|
336 "CSilentMIDletInstall::RunError(%d) from state %d", aError, iState); |
|
337 |
|
338 Cancel(); |
|
339 |
|
340 // Make preinstaller to exit nicely. |
|
341 iState = EExit; |
|
342 CompleteRequest(); |
|
343 |
|
344 return KErrNone; |
|
345 } |
|
346 |
|
347 /** |
|
348 * Cancel this object. Stops preinstall server if needed. |
|
349 */ |
|
350 void CSilentMIDletInstall::DoCancel() |
|
351 { |
|
352 ELOG1(EJavaPreinstaller, |
|
353 "CSilentMIDletInstall::DoCancel from state %d", iState); |
|
354 |
|
355 // Check whether preinstall server must be stopped |
|
356 if (iState == EExecutePreinstallServer) |
|
357 { |
|
358 // Stops the server if it is running |
|
359 iPreinstallServer->stop(); |
|
360 } |
|
361 } |
|
362 |
|
363 /** |
|
364 * Add .jad files in the directories specified in aDirs to iJadFiles. |
|
365 * |
|
366 * Goes all directories in iDirs one by one and adds the |
|
367 * valid .jad files in alphabetical order to iJadFiles. |
|
368 * |
|
369 * @param aDirs - An array of directories to be scanned. |
|
370 * @exception Unable to alloc memory for the internal buffers. |
|
371 * @exception Unable to get directory's contents. |
|
372 */ |
|
373 void CSilentMIDletInstall::GetMIDletFilesL(RPointerArray<HBufC>& aDirs) |
|
374 { |
|
375 JELOG2(EJavaPreinstaller); |
|
376 |
|
377 const TInt num = aDirs.Count(); |
|
378 |
|
379 // Read JAD files. |
|
380 for (TInt i = 0; i < num; i++) |
|
381 { |
|
382 const TPtrC& dir = ((HBufC *)(aDirs[i]))->Des(); |
|
383 |
|
384 HBufC* mask= NULL; |
|
385 TPtr maskPtr(NULL,0,0); |
|
386 |
|
387 // Create JAD mask, e.g., "z:\resource\java\preinstall\*.jad". |
|
388 // Reserve space also for terminating zero for logging the info |
|
389 mask = HBufC::NewLC(dir.Length() + KJadExtension().Length() + 1); |
|
390 maskPtr.Set(mask->Des()); |
|
391 maskPtr.Append(dir); |
|
392 maskPtr.Append(KJadExtension); |
|
393 LOG1WSTR(EJavaPreinstaller, EInfo, |
|
394 "CSilentMIDletInstall::GetMIDletFilesL Looking for jad files from directory %s", |
|
395 (wchar_t *)(maskPtr.PtrZ())); |
|
396 GetDirEntriesL(dir, *mask, iJadFiles); |
|
397 CleanupStack::PopAndDestroy(mask); |
|
398 } |
|
399 |
|
400 if (iJadFiles.Count() == 0) |
|
401 { |
|
402 ILOG(EJavaPreinstaller, |
|
403 "CSilentMIDletInstall:GetMIDletFilesL No MIDlets to preinstall"); |
|
404 } |
|
405 } |
|
406 |
|
407 /** |
|
408 * Get the entries of the directory in alphabetical order. |
|
409 * |
|
410 * @param aDirectory - A directory to be scanned. |
|
411 * @param aMask - A filter to be used for scanning. |
|
412 * @param aVector - An output vector for contents. |
|
413 * @exception Unable to alloc memory for the internal buffers. |
|
414 */ |
|
415 void CSilentMIDletInstall::GetDirEntriesL(const TDesC& aDirectory, |
|
416 const TDesC& aMask, RPointerArray<HBufC>& aVector) |
|
417 { |
|
418 JELOG2(EJavaPreinstaller); |
|
419 |
|
420 // Get entries in alphabetical order. |
|
421 |
|
422 CDir* entries= NULL; |
|
423 TInt err = iFs.GetDir(aMask, KEntryAttMaskSupported, ESortByName, entries); |
|
424 |
|
425 if (err != KErrNone) |
|
426 { |
|
427 if (err != KErrPathNotFound) |
|
428 { |
|
429 ELOG1(EJavaPreinstaller, |
|
430 "CSilentMIDletInstall::GetDirEntriesL Dir error (%d)", err); |
|
431 } |
|
432 delete entries; |
|
433 return; |
|
434 } |
|
435 |
|
436 CleanupStack::PushL(entries); |
|
437 |
|
438 // Add full file names to the vector. |
|
439 |
|
440 TInt num = entries->Count(); |
|
441 for (TInt i = 0; i < num; i++) |
|
442 { |
|
443 const TDesC& name = (*entries)[i].iName; |
|
444 // Reserve one char for null terminator |
|
445 HBufC* path = HBufC::NewLC(aDirectory.Length() + name.Length() + 1); |
|
446 TPtr pathPtr(path->Des()); |
|
447 pathPtr.Append(aDirectory); |
|
448 pathPtr.Append(name); |
|
449 LOG1WSTR(EJavaPreinstaller, EInfo, |
|
450 "CSilentMIDletInstall::GetDirEntriesL Adding file %s", |
|
451 (wchar_t *)(pathPtr.PtrZ())); |
|
452 aVector.Append(path); |
|
453 CleanupStack::Pop(path); |
|
454 } |
|
455 |
|
456 CleanupStack::PopAndDestroy(entries); |
|
457 } |
|
458 |
|
459 /** |
|
460 * Start Java Installer in poll mode and then wait until it exits. |
|
461 */ |
|
462 void CSilentMIDletInstall::RunJavaInstallerL() |
|
463 { |
|
464 JELOG2(EJavaPreinstaller); |
|
465 |
|
466 LOG(EJavaPreinstaller, EInfo, "CSilentMIDletInstall::RunJavaInstaller"); |
|
467 |
|
468 RProcess rJavaInstaller; |
|
469 TFileName fileName; |
|
470 // Max one path name, user name and password and some options -> |
|
471 // 1536 is enough |
|
472 TBuf<1536> commandLine; |
|
473 |
|
474 // Build command line used to pass all necessary info to Java Installer |
|
475 TInt len = strlen(java::runtime::JAVA_INSTALLER_STARTER_DLL); |
|
476 TPtr8 ptr8InstallerDll((TUint8 *)java::runtime::JAVA_INSTALLER_STARTER_DLL, len, len); |
|
477 commandLine.Copy(ptr8InstallerDll); |
|
478 |
|
479 commandLine.Append(_L(" poll -address=preinstall")); |
|
480 |
|
481 // Upgrading MIDlets is allowed |
|
482 commandLine.Append(_L(" -upgrade=yes")); |
|
483 |
|
484 // No OCSP checks for preinstalled MIDlets |
|
485 commandLine.Append(_L(" -ocsp=no")); |
|
486 |
|
487 #ifdef _DEBUG |
|
488 // Allow installing unsigned apps in debug builds |
|
489 commandLine.Append(_L(" -untrusted=yes")); |
|
490 #else |
|
491 // Deny preinstalling untrusted midlets in release builds |
|
492 commandLine.Append(_L(" -untrusted=no")); |
|
493 #endif |
|
494 |
|
495 // Do upgrade if version number has not increased |
|
496 commandLine.Append(_L(" -overwrite=no")); |
|
497 |
|
498 // Both the JAD and JAR file must be present when preinstalling MIDlets, |
|
499 // downloading is not allowed. |
|
500 commandLine.Append(_L(" -download=no")); |
|
501 |
|
502 // If upgrade install, retain the data (RMS and private files) of the previous version |
|
503 commandLine.Append(_L(" -upgrade_data=yes")); |
|
504 |
|
505 // start JavaInstaller |
|
506 TBuf<64> installerProcess; // Actual len of the process name is 9 |
|
507 len = strlen(java::runtime::JAVA_PROCESS); |
|
508 TPtr8 ptr8Process((TUint8 *)java::runtime::JAVA_PROCESS, len, len); |
|
509 installerProcess.Copy(ptr8Process); |
|
510 |
|
511 TInt err = rJavaInstaller.Create(installerProcess, commandLine); |
|
512 if (KErrNone == err) |
|
513 { |
|
514 LOG(EJavaPreinstaller, EInfo, "CSilentMIDletInstall::RunJavaInstaller calling Logon"); |
|
515 // This call will wait until Java Installer exits (or panics) |
|
516 rJavaInstaller.Logon(iStatus); |
|
517 |
|
518 LOG(EJavaPreinstaller, EInfo, "CSilentMIDletInstall::RunJavaInstaller calling Resume"); |
|
519 rJavaInstaller.Resume(); |
|
520 } |
|
521 else |
|
522 { |
|
523 ELOG1(EJavaPreinstaller, |
|
524 "CSilentMIDletInstall::RunJavaInstaller Cannot start Installer, error %d", err); |
|
525 // CActive will trap the following leave, execution will go to RunError |
|
526 User::Leave(err); |
|
527 } |
|
528 |
|
529 LOG(EJavaPreinstaller, EInfo, "CSilentMIDletInstall::RunJavaInstaller calling RProcess::Close"); |
|
530 // free resources before returning |
|
531 rJavaInstaller.Close(); |
|
532 |
|
533 // now wait until Java Installer exits |
|
534 SetActive(); |
|
535 } |
|
536 |
|
537 /** |
|
538 * Start Java Installer just to do IntegrityService rollback. |
|
539 * Do not wait for the process exit. |
|
540 */ |
|
541 void CSilentMIDletInstall::RollbackJavaInstaller() |
|
542 { |
|
543 JELOG2(EJavaPreinstaller); |
|
544 |
|
545 RProcess rJavaInstaller; |
|
546 TFileName fileName; |
|
547 // Pass just 'rollback' command |
|
548 TBuf<128> commandLine; |
|
549 |
|
550 // Build command line used to pass all necessary info to Java Installer |
|
551 TInt len = strlen(java::runtime::JAVA_INSTALLER_STARTER_DLL); |
|
552 TPtr8 ptr8InstallerDll((TUint8 *)java::runtime::JAVA_INSTALLER_STARTER_DLL, len, len); |
|
553 commandLine.Copy(ptr8InstallerDll); |
|
554 |
|
555 commandLine.Append(_L(" rollback")); |
|
556 |
|
557 WLOG(EJavaPreinstaller, |
|
558 "CSilentMIDletInstall::RollbackJavaInstaller starting Java Installer for rollback"); |
|
559 |
|
560 // start JavaInstaller |
|
561 TBuf<64> installerProcess; // Actual len of the process name is 9 |
|
562 len = strlen(java::runtime::JAVA_PROCESS); |
|
563 TPtr8 ptr8Process((TUint8 *)java::runtime::JAVA_PROCESS, len, len); |
|
564 installerProcess.Copy(ptr8Process); |
|
565 |
|
566 TInt err = rJavaInstaller.Create(installerProcess, commandLine); |
|
567 if (KErrNone == err) |
|
568 { |
|
569 LOG(EJavaPreinstaller, EInfo, |
|
570 "CSilentMIDletInstall::RollbackJavaInstaller calling Resume"); |
|
571 rJavaInstaller.Resume(); |
|
572 } |
|
573 |
|
574 LOG(EJavaPreinstaller, EInfo, |
|
575 "CSilentMIDletInstall::RollbackJavaInstaller calling RProcess::Close"); |
|
576 // free resources before returning |
|
577 rJavaInstaller.Close(); |
|
578 } |
|
579 |
|
580 /** |
|
581 * Parse MIDlet-Name, MIDlet-Vendor and MIDlet-Version parameters from JAD file. |
|
582 * Parameters are used to determine whether to pre-install MIDlet or not. |
|
583 * |
|
584 * @param ETrue if parsing succeeds otherwise EFalse. |
|
585 */ |
|
586 TBool CSilentMIDletInstall::ParseJadL(const TDesC& aJadFileName) |
|
587 { |
|
588 JELOG2(EJavaPreinstaller); |
|
589 |
|
590 HBufC *jadContent = NULL; |
|
591 // Trap leave thrown if reading jad content fails |
|
592 TRAPD(err, jadContent = GetJadContentL(aJadFileName)); |
|
593 if (KErrNone != err) |
|
594 { |
|
595 ELOG1(EJavaPreinstaller, |
|
596 "CSilentMIDletInstall::ParseJadL Reading Jad content failed, error %d", |
|
597 err); |
|
598 return EFalse; |
|
599 } |
|
600 CleanupStack::PushL(jadContent); |
|
601 |
|
602 HBufC *midletName = ParseAttribute(jadContent, KMidletName); |
|
603 if (NULL == midletName) |
|
604 { |
|
605 ELOG(EJavaPreinstaller, |
|
606 "CSilentMIDletInstall::ParseJadL Parsing midlet name failed."); |
|
607 CleanupStack::PopAndDestroy(jadContent); |
|
608 return EFalse; |
|
609 } |
|
610 // store midlet name to member variable and log it |
|
611 TPtr namePtr(iMIDletName->Des()); |
|
612 namePtr.Copy(*midletName); |
|
613 LOG1WSTR(EJavaPreinstaller, EInfo, |
|
614 "CSilentMIDletInstall::ParseJadL MIDlet-Name %s", |
|
615 (wchar_t *)(namePtr.PtrZ())); |
|
616 delete midletName; |
|
617 |
|
618 HBufC *midletVendor = ParseAttribute(jadContent, KMidletVendor); |
|
619 if (NULL == midletVendor) |
|
620 { |
|
621 ELOG(EJavaPreinstaller, |
|
622 "CSilentMIDletInstall::ParseJadL Parsing midlet vendor failed."); |
|
623 CleanupStack::PopAndDestroy(jadContent); |
|
624 return EFalse; |
|
625 } |
|
626 // store midlet vendor to member variable and log it |
|
627 TPtr vendorPtr(iMIDletVendor->Des()); |
|
628 vendorPtr.Copy(*midletVendor); |
|
629 LOG1WSTR(EJavaPreinstaller, EInfo, |
|
630 "CSilentMIDletInstall::ParseJadL MIDlet-Vendor %s", |
|
631 (wchar_t *)(vendorPtr.PtrZ())); |
|
632 delete midletVendor; |
|
633 |
|
634 HBufC *midletVersion = ParseAttribute(jadContent, KMidletVersion); |
|
635 if (NULL == midletVersion) |
|
636 { |
|
637 ELOG(EJavaPreinstaller, |
|
638 "CSilentMIDletInstall::ParseJadL Parsing midlet version failed."); |
|
639 CleanupStack::PopAndDestroy(jadContent); |
|
640 return EFalse; |
|
641 } |
|
642 // Convert version to TAppVersion, store it and log it |
|
643 iMIDletVersion = DesToAppVersion(midletVersion); |
|
644 delete midletVersion; |
|
645 |
|
646 LOG3(EJavaPreinstaller, EInfo, |
|
647 "CSilentMIDletInstall::ParseJadL MIDlet-Version is %d.%d.%d", |
|
648 iMIDletVersion.iMajor, iMIDletVersion.iMinor, iMIDletVersion.iBuild); |
|
649 |
|
650 CleanupStack::PopAndDestroy(jadContent); |
|
651 return ETrue; |
|
652 } |
|
653 |
|
654 /** |
|
655 * If there is something to preinstall start preinstall comms server and |
|
656 * installer in poll mode. |
|
657 * Otherwise start installer with rollback option if installer |
|
658 * integrity service rollback is needed. |
|
659 */ |
|
660 void CSilentMIDletInstall::ExecutePreinstallServerL() |
|
661 { |
|
662 if (iNumberOfAppsToInstall > 0) |
|
663 { |
|
664 // Install all MIDlet Suites still in iJadFiles. |
|
665 |
|
666 // Pass iJadFiles to PreinstallServer |
|
667 iPreinstallServer->setJadFiles(iJadFiles); |
|
668 |
|
669 // Start the comms server |
|
670 int err = iPreinstallServer->start(); |
|
671 if (0 != err) |
|
672 { |
|
673 // server cannot be started |
|
674 ELOG1(EJavaPreinstaller, |
|
675 "Cannot start preinstall server, err %d", err); |
|
676 } |
|
677 else |
|
678 { |
|
679 // Starts Java Installer and waits until it exits |
|
680 RunJavaInstallerL(); |
|
681 } |
|
682 |
|
683 iState = EExit; |
|
684 } |
|
685 else |
|
686 { |
|
687 // Rollback must be done by launching Java Installer |
|
688 // separately with rollback option. |
|
689 // (Normally rollback is done during normal installation.) |
|
690 if (iISRollbackNeeded) |
|
691 { |
|
692 RollbackJavaInstaller(); |
|
693 iISRollbackNeeded = EFalse; |
|
694 } |
|
695 |
|
696 iState = EExit; |
|
697 CompleteRequest(); |
|
698 } |
|
699 } |
|
700 |
|
701 /** |
|
702 * Check all Jad files in iJadFiles and remove those |
|
703 * that need not be preinstalled (already installed[1] or preinstalled[2] |
|
704 * or preinstalled and then uninstalled by user[3]). |
|
705 */ |
|
706 void CSilentMIDletInstall::CheckWhichAppsShouldBeInstalledL() |
|
707 { |
|
708 TBool skipInstall(ETrue); |
|
709 iNumberOfAppsToInstall = 0; |
|
710 |
|
711 // throws STL C++ exception if fails, catched by CActive and |
|
712 // execution goes to RunError |
|
713 std::auto_ptr<JavaStorage> js(JavaStorage::createInstance()); |
|
714 // throws STL C++ exception if fails, catched by CActive and |
|
715 // execution goes to RunError |
|
716 js->open(JAVA_DATABASE_NAME); |
|
717 |
|
718 // In Java Storage there is 'preinstall' table that contains |
|
719 // the name, vendor and version of every java application that is currently |
|
720 // installed to the device or that has been preinstalled to the device |
|
721 // but removed by the user. |
|
722 // The table contains also the installation state of each application. |
|
723 // If the application has been removed the user, the application is in state |
|
724 // NO_PREINSTALL. |
|
725 // Do not preinstall application if it is found from this table with state |
|
726 // NO_PREINSTALL. |
|
727 // Do not preinstall application if it is found from this table |
|
728 // and the version number of the application is the same or less |
|
729 // than the version number in the table. |
|
730 |
|
731 JavaStorageEntry attribute; |
|
732 JavaStorageApplicationEntry_t findPattern; |
|
733 JavaStorageApplicationList_t foundEntries; |
|
734 |
|
735 for (TInt i = 0; i < iJadFiles.Count(); i++) |
|
736 { |
|
737 if (ParseJadL(*iJadFiles[i])) |
|
738 { |
|
739 skipInstall = ETrue; |
|
740 |
|
741 TPtr namePtr(iMIDletName->Des()); |
|
742 TPtr vendorPtr(iMIDletVendor->Des()); |
|
743 int installState = INSTALLED; |
|
744 |
|
745 // Search by NAME and VENDOR |
|
746 attribute.setEntry(NAME, desToWstring(namePtr)); |
|
747 findPattern.insert(attribute); |
|
748 attribute.setEntry(VENDOR, desToWstring(vendorPtr)); |
|
749 findPattern.insert(attribute); |
|
750 |
|
751 // All information in table is returned (whole row) |
|
752 |
|
753 js->search(PREINSTALL_TABLE, findPattern, foundEntries); |
|
754 findPattern.clear(); |
|
755 |
|
756 // Anything found? |
|
757 if (foundEntries.size() > 0) |
|
758 { |
|
759 // We like to know if the application INSTALL_STATE is NO_PREINSTALL |
|
760 attribute.setEntry(INSTALL_STATE, L""); |
|
761 |
|
762 // Check the INSTALL_STATE of the first (there should be only one) |
|
763 // found application |
|
764 JavaStorageApplicationEntry_t::const_iterator findIterator = |
|
765 foundEntries.front().find(attribute); |
|
766 if (findIterator != (foundEntries.front()).end()) |
|
767 { |
|
768 installState = JavaCommonUtils::wstringToInt(findIterator->entryValue()); |
|
769 } |
|
770 else |
|
771 { |
|
772 ELOG1WSTR(EJavaPreinstaller, |
|
773 "CheckWhichAppsShouldBeInstalledL: No INSTALL_STATE info " |
|
774 "in Storage for application %s", desToWstring(namePtr)); |
|
775 } |
|
776 |
|
777 if (installState == NO_PREINSTALL) |
|
778 { |
|
779 // This application must not be preinstalled |
|
780 LOG1WSTR(EJavaPreinstaller, EInfo, |
|
781 "CheckWhichAppsShouldBeInstalledL: User has removed application %s " |
|
782 "It must not be preinstalled again.", desToWstring(namePtr)); |
|
783 } |
|
784 else |
|
785 { |
|
786 // We like to know application VERSION |
|
787 attribute.setEntry(VERSION, L""); |
|
788 |
|
789 // Check the version of the first (there should be only one) |
|
790 // found application |
|
791 findIterator = foundEntries.front().find(attribute); |
|
792 if (findIterator != (foundEntries.front()).end()) |
|
793 { |
|
794 // Application has been installed at sometime |
|
795 // but if we have a newer version of the application |
|
796 // we will install this newer version. |
|
797 if (iMIDletVersion > wstringToAppVersion(findIterator->entryValue())) |
|
798 { |
|
799 skipInstall = EFalse; |
|
800 } |
|
801 else |
|
802 { |
|
803 LOG1WSTR(EJavaPreinstaller, EInfo, |
|
804 "CheckWhichAppsShouldBeInstalledL: Application %s " |
|
805 "has already been installed", desToWstring(namePtr)); |
|
806 } |
|
807 } |
|
808 else |
|
809 { |
|
810 skipInstall = EFalse; |
|
811 ELOG1WSTR(EJavaPreinstaller, |
|
812 "CheckWhichAppsShouldBeInstalledL: No version info " |
|
813 "in Storage for application %s", desToWstring(namePtr)); |
|
814 } |
|
815 } |
|
816 } |
|
817 else |
|
818 { |
|
819 skipInstall = EFalse; |
|
820 LOG(EJavaPreinstaller, EInfo, |
|
821 "CheckWhichAppsShouldBeInstalledL: Application has not " |
|
822 "been installed previously"); |
|
823 } |
|
824 |
|
825 foundEntries.clear(); |
|
826 } |
|
827 else |
|
828 { |
|
829 // If Jad parsing fails don't preinstall this |
|
830 skipInstall = ETrue; |
|
831 TPtr16 ptrJadName = iJadFiles[i]->Des(); |
|
832 ELOG1WSTR(EJavaPreinstaller, |
|
833 "CheckWhichAppsShouldBeInstalledL: Parsing JAD %s failed", |
|
834 desToWstring(ptrJadName)); |
|
835 } |
|
836 |
|
837 if (skipInstall) |
|
838 { |
|
839 delete iJadFiles[i]; |
|
840 iJadFiles[i] = NULL; |
|
841 } |
|
842 else |
|
843 { |
|
844 iNumberOfAppsToInstall++; |
|
845 } |
|
846 } |
|
847 |
|
848 js->close(); |
|
849 } |
|
850 |
|
851 /** |
|
852 * Adds the preinstall directory of every local, non-substed drive to iDirs |
|
853 */ |
|
854 void CSilentMIDletInstall::GetDirsToBeScannedL() |
|
855 { |
|
856 TChar driveChar; |
|
857 |
|
858 for (TInt drive = 0; drive < KMaxDrives; drive++) |
|
859 { |
|
860 // All present local drives are scanned for |
|
861 // java applications to be preinstalled |
|
862 if (iDriveStatuses[drive] & DriveInfo::EDrivePresent) |
|
863 { |
|
864 // The preinstall directory in this drive must be scanned. |
|
865 // Reserve memory also for drive letter and terminating zero |
|
866 // for logging. |
|
867 HBufC *preinstallDir = HBufC::NewLC(KPreinstallDir().Length() + 2); |
|
868 TPtr dirPtr(preinstallDir->Des()); |
|
869 |
|
870 (void)iFs.DriveToChar(drive, driveChar); |
|
871 dirPtr.Append(driveChar); |
|
872 dirPtr.Append(KPreinstallDir()); |
|
873 |
|
874 // Add new search directory |
|
875 iDirs.AppendL(preinstallDir); |
|
876 CleanupStack::Pop(preinstallDir); |
|
877 } |
|
878 } |
|
879 } |
|
880 |
|
881 /** |
|
882 * Checks all local drives in the device and stores the DriveInfo API drive |
|
883 * status information for each drive to iDriveStatuses |
|
884 * @exception Cannot get drive list. |
|
885 */ |
|
886 void CSilentMIDletInstall::GetAllDeviceDrivesL() |
|
887 { |
|
888 JELOG2(EJavaPreinstaller); |
|
889 |
|
890 TDriveList driveList; |
|
891 // get all drives |
|
892 TInt err = iFs.DriveList(driveList); |
|
893 if (KErrNone != err) |
|
894 { |
|
895 ELOG1(EJavaPreinstaller, |
|
896 "GetAllDeviceDrives cannot get drive list, err %d", err); |
|
897 User::Leave(err); |
|
898 } |
|
899 |
|
900 // store status of the non-remote, non-substed drives |
|
901 TUint status = 0; |
|
902 for (TInt drive = 0; drive < KMaxDrives; drive++) |
|
903 { |
|
904 iDriveStatuses[drive] = 0; |
|
905 |
|
906 if (driveList[drive] == 0) |
|
907 { |
|
908 // no such drive in this device |
|
909 continue; |
|
910 } |
|
911 |
|
912 err = DriveInfo::GetDriveStatus(iFs, drive, status); |
|
913 if (KErrNone != err) |
|
914 { |
|
915 ELOG2(EJavaPreinstaller, |
|
916 "GetAllDeviceDrivesL cannot get drive %d status, err %d", |
|
917 drive, err); |
|
918 User::Leave(err); |
|
919 } |
|
920 // D drive is temporary RAM drive, skip it |
|
921 // Drives J to Y are substed or remote drives, skip them |
|
922 if ((drive == EDriveD) || ((drive >= EDriveJ) && (drive <= EDriveY))) |
|
923 { |
|
924 continue; |
|
925 } |
|
926 |
|
927 iDriveStatuses[drive] = status; |
|
928 } |
|
929 } |
|
930 |
|
931 /** |
|
932 * Reads the whole content of the Jad file and returns it in |
|
933 * buffer in Symbian Unicode character set. |
|
934 * @param[in] aJarFile |
|
935 * @return pointer to HBufC that contains the Jad file, |
|
936 * ownership is transferred to caller |
|
937 * @exception If jad file content cannot be read |
|
938 */ |
|
939 HBufC *CSilentMIDletInstall::GetJadContentL(const TDesC& aJadFileName) |
|
940 { |
|
941 JELOG2(EJavaPreinstaller); |
|
942 |
|
943 TInt err; |
|
944 RFile jadFile; |
|
945 |
|
946 err = jadFile.Open(iFs, aJadFileName, EFileRead); |
|
947 User::LeaveIfError(err); |
|
948 CleanupClosePushL(jadFile); |
|
949 |
|
950 // Reserve buffer for Jad in UTF-8 char set |
|
951 TInt jadSize = 0; |
|
952 err = jadFile.Size(jadSize); |
|
953 User::LeaveIfError(err); |
|
954 HBufC8 *bufUtf8Jad = HBufC8::NewL(jadSize); |
|
955 CleanupStack::PushL(bufUtf8Jad); |
|
956 |
|
957 // Read the content in Utf8 char set |
|
958 TPtr8 tmpPtr(bufUtf8Jad->Des()); |
|
959 err = jadFile.Read(tmpPtr, jadSize); |
|
960 User::LeaveIfError(err); |
|
961 |
|
962 // Convert to Unicode |
|
963 HBufC *bufUnicodeJad = |
|
964 CnvUtfConverter::ConvertToUnicodeFromUtf8L(*bufUtf8Jad); |
|
965 |
|
966 CleanupStack::PopAndDestroy(bufUtf8Jad); |
|
967 CleanupStack::PopAndDestroy(&jadFile); |
|
968 |
|
969 // Return to caller |
|
970 return bufUnicodeJad; |
|
971 |
|
972 } // GetJadContentL |
|
973 |
|
974 /** |
|
975 * Finds the java attribute specified by |
|
976 * aAttributeName from aJad and returns the value of that attribute |
|
977 * in HBufC. |
|
978 * @param[in] aJad contents of Jad file |
|
979 * @param[in] aAttributeName the name of a java attribute |
|
980 * @return the value of the attribute. Caller gets the ownership of the |
|
981 * returned HBufC. |
|
982 * If the attribute is not found, returns NULL |
|
983 */ |
|
984 HBufC *CSilentMIDletInstall::ParseAttribute(const HBufC *aJad, const TDesC& aAttributeName) |
|
985 { |
|
986 JELOG2(EJavaPreinstaller); |
|
987 |
|
988 TInt nInd(0); |
|
989 TBool fullNameFound(EFalse); |
|
990 TUint32 ch; |
|
991 |
|
992 // Start parsing from the beginning of the Jad file |
|
993 TPtrC parsePtr = aJad->Mid(nInd); |
|
994 |
|
995 do |
|
996 { |
|
997 // Find attribute name |
|
998 nInd = parsePtr.Find(aAttributeName); |
|
999 if (nInd < 0) |
|
1000 { |
|
1001 // Returns NULL if the attribute cannot be found |
|
1002 return NULL; |
|
1003 } |
|
1004 |
|
1005 // Check that the attribute name was preceded by line break or |
|
1006 // it was at the beginning of the Jad file |
|
1007 if (nInd == 0) |
|
1008 { |
|
1009 fullNameFound = ETrue; |
|
1010 } |
|
1011 else |
|
1012 { |
|
1013 ch = parsePtr[nInd-1]; |
|
1014 if ((ch == CR) || (ch == LF)) |
|
1015 { |
|
1016 fullNameFound = ETrue; |
|
1017 } |
|
1018 else |
|
1019 { |
|
1020 // Name was just a part of longer string (not 'word match') |
|
1021 fullNameFound = EFalse; |
|
1022 // Skip to the last character of the found match. |
|
1023 // We can skip because we are insterested only in 'word' matches |
|
1024 // so the next cannot start inside the area we are skipping now. |
|
1025 parsePtr.Set(parsePtr.Mid(nInd + aAttributeName.Length() - 1)); |
|
1026 continue; |
|
1027 } |
|
1028 } |
|
1029 |
|
1030 // Check whether Jad file ends after attribute name |
|
1031 if (nInd + aAttributeName.Length() >= parsePtr.Length()) |
|
1032 { |
|
1033 // Jad file ends immediately after the found |
|
1034 // attribute name instance. No attribute value |
|
1035 return NULL; |
|
1036 } |
|
1037 |
|
1038 // Check that there is a white space character or colon after |
|
1039 // attribute name |
|
1040 ch = parsePtr[nInd + aAttributeName.Length()]; |
|
1041 if ((ch == COLON) || (ch == SP) || (ch == HT)) |
|
1042 { |
|
1043 fullNameFound = ETrue; |
|
1044 } |
|
1045 else |
|
1046 { |
|
1047 // Name was just a part of longer string (not 'word match') |
|
1048 fullNameFound = EFalse; |
|
1049 // Skip to the next character after the found match |
|
1050 parsePtr.Set(parsePtr.Mid(nInd + aAttributeName.Length())); |
|
1051 continue; |
|
1052 } |
|
1053 } |
|
1054 while (!fullNameFound); |
|
1055 |
|
1056 // Skip to the end of the attribute name and find ':' after the name. |
|
1057 // The skipped characters must be white space chacraters, otherwise |
|
1058 // the attribute name is illegal and Java Installer will not accept |
|
1059 // the Jad file. |
|
1060 parsePtr.Set(parsePtr.Mid(nInd + aAttributeName.Length() - 1)); |
|
1061 nInd = parsePtr.Locate(COLON); |
|
1062 if (nInd < 0) |
|
1063 { |
|
1064 return NULL; |
|
1065 } |
|
1066 nInd++; |
|
1067 |
|
1068 // Parse attribute value (CR or LF ends) |
|
1069 TInt nEndInd = parsePtr.Locate(CR); |
|
1070 TInt nTmpInd = parsePtr.Locate(LF); |
|
1071 |
|
1072 if (KErrNotFound == nEndInd) |
|
1073 { |
|
1074 nEndInd = parsePtr.Length() - 1; |
|
1075 } |
|
1076 if (KErrNotFound == nTmpInd) |
|
1077 { |
|
1078 nTmpInd = parsePtr.Length() - 1; |
|
1079 } |
|
1080 |
|
1081 if (nTmpInd < nEndInd) |
|
1082 { |
|
1083 nEndInd = nTmpInd; |
|
1084 } |
|
1085 |
|
1086 if (nEndInd < nInd) |
|
1087 { |
|
1088 return NULL; |
|
1089 } |
|
1090 |
|
1091 TPtrC attributeValue = parsePtr.Mid(nInd, (nEndInd - nInd)); |
|
1092 |
|
1093 // Remove possible white space from the beginning and end of the value |
|
1094 HBufC *bufValue = attributeValue.Alloc(); |
|
1095 if (NULL == bufValue) |
|
1096 { |
|
1097 return NULL; |
|
1098 } |
|
1099 TPtr value = bufValue->Des(); |
|
1100 value.Trim(); |
|
1101 |
|
1102 return bufValue; |
|
1103 } // parseAttribute |
|
1104 |
|
1105 /** |
|
1106 * Parses the application version string given in aAppVersionString |
|
1107 * and returns the corresponding Symbian TAppVersion. |
|
1108 * @param[in] aAppVersionString version string to be parsed |
|
1109 * @return application version object |
|
1110 * If parsing cannot be done, returns application version 0.0.0 |
|
1111 */ |
|
1112 TAppVersion CSilentMIDletInstall::DesToAppVersion(const HBufC *aAppVersionString) |
|
1113 { |
|
1114 JELOG2(EJavaPreinstaller); |
|
1115 |
|
1116 TInt err; |
|
1117 TAppVersion midletVersion; |
|
1118 TAppVersion midletVersionZero; |
|
1119 TLex versionParser(*aAppVersionString); |
|
1120 err = versionParser.Val(midletVersion.iMajor); |
|
1121 if (KErrNone != err) |
|
1122 { |
|
1123 WLOG1(EJavaPreinstaller, |
|
1124 "DesToAppVersion cannot parse midlet major version, error %d", err); |
|
1125 return midletVersionZero; |
|
1126 } |
|
1127 |
|
1128 TChar dot = versionParser.Get(); |
|
1129 if (dot != '.') |
|
1130 { |
|
1131 WLOG(EJavaPreinstaller, |
|
1132 "DesToAppVersion suspicious midlet version, no dot after major version"); |
|
1133 // return at least the major version |
|
1134 return midletVersion; |
|
1135 } |
|
1136 err = versionParser.Val(midletVersion.iMinor); |
|
1137 if (KErrNone != err) |
|
1138 { |
|
1139 WLOG1(EJavaPreinstaller, |
|
1140 "DesToAppVersion cannot parse midlet minor version, error %d", err); |
|
1141 // return at least the major version |
|
1142 return midletVersion; |
|
1143 } |
|
1144 |
|
1145 dot = versionParser.Get(); |
|
1146 if (dot != '.') |
|
1147 { |
|
1148 // return the major and minor version |
|
1149 return midletVersion; |
|
1150 } |
|
1151 err = versionParser.Val(iMIDletVersion.iBuild); |
|
1152 if (KErrNone != err) |
|
1153 { |
|
1154 WLOG1(EJavaPreinstaller, |
|
1155 "DesToAppVersion cannot parse midlet build version, error %d", err); |
|
1156 // return at least the major and minor version |
|
1157 return midletVersion; |
|
1158 } |
|
1159 |
|
1160 if (!versionParser.Eos()) |
|
1161 { |
|
1162 WLOG(EJavaPreinstaller, |
|
1163 "DesToAppVersion suspicious midlet version, end has extra non number characters"); |
|
1164 } |
|
1165 |
|
1166 return midletVersion; |
|
1167 } // DesToAppVersion |