javamanager/preinstaller/src.s60/silentmidletinstall.cpp
branchRCL_3
changeset 19 04becd199f91
child 48 e0d6e9bd3ca7
child 60 6c158198356e
equal deleted inserted replaced
16:f5050f1da672 19:04becd199f91
       
     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