javatools/javaappbackconverter/src.s60/backconverter.cpp
branchRCL_3
changeset 18 9ac0a0a7da70
parent 17 0fd27995241b
child 19 71c436fe3ce0
equal deleted inserted replaced
17:0fd27995241b 18:9ac0a0a7da70
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "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: Java platform 2.0 javaappbackconverter process.
       
    15 *              Reregisters the old S60 MIDlets back to AppArc
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 #include <e32base.h>
       
    21 #include <apgicnfl.h>
       
    22 #include <s32mem.h>
       
    23 #include <e32property.h>
       
    24 
       
    25 #include "javacommonutils.h"
       
    26 #include "javauids.h"
       
    27 #include "backconverter.h"
       
    28 #include "noarmlogs.h"
       
    29 
       
    30 
       
    31 const TInt KDelayWhenWaitingAppArc = 500000;
       
    32 
       
    33 // This is in the private data cage of javaappbackconverter
       
    34 _LIT(KMidletImportDirectory, "C:\\private\\20022D90\\data\\");
       
    35 
       
    36 // Symbian file path separator
       
    37 _LIT(KPathSeperator, "\\");
       
    38 
       
    39 // Postfix for the fake application name generated only to make AppArc happy
       
    40 _LIT(KAppPostfix, ".fakeapp");
       
    41 
       
    42 // The application type Uid for MIDlets in S60
       
    43 const TUid KUidMidletApplicationType = { 0x10210E26 };
       
    44 
       
    45 /**
       
    46  * To create new instance of this class.
       
    47  *
       
    48  * @param aFs - A reference to the file server.
       
    49  * @return Reference to the object of this class.
       
    50  * @exception If construction fails.
       
    51  *
       
    52  */
       
    53 CBackConverter* CBackConverter::NewLC(RFs& aFs)
       
    54 {
       
    55     CBackConverter* self = new(ELeave) CBackConverter(aFs);
       
    56     CleanupStack::PushL(self);
       
    57     self->ConstructL();
       
    58     return self;
       
    59 }
       
    60 
       
    61 /**
       
    62  * To do 1st phase construction for this object.
       
    63  *
       
    64  * Adds this active object to the scheduler.
       
    65  *
       
    66  * @param param aFs - A reference to the file server.
       
    67  * @return Reference to the object of this class.
       
    68  */
       
    69 CBackConverter::CBackConverter(RFs& aFs) :
       
    70         CActive(EPriorityStandard), iFs(aFs)
       
    71 {
       
    72     CActiveScheduler::Add(this);
       
    73 }
       
    74 
       
    75 /**
       
    76  * To do 2nd phase construction for this object.
       
    77  *
       
    78  * @exception If the method is not able to allocate necessary buffers.
       
    79  */
       
    80 void CBackConverter::ConstructL()
       
    81 {
       
    82     JELOG2(EJavaConverters);
       
    83 
       
    84     iMidlets = new(ELeave) CMidletList();
       
    85     iState = EInitialize;
       
    86 }
       
    87 
       
    88 /**
       
    89  * Deletes this object.
       
    90  * All allocated resources are released.
       
    91  */
       
    92 CBackConverter::~CBackConverter()
       
    93 {
       
    94     JELOG2(EJavaConverters);
       
    95     Cancel();
       
    96     if (iMidlets)
       
    97     {
       
    98         iMidlets->ResetAndDestroy();
       
    99         delete iMidlets;
       
   100         iMidlets = NULL;
       
   101     }
       
   102 }
       
   103 
       
   104 /**
       
   105  * To start back conversion
       
   106  */
       
   107 void CBackConverter::Start()
       
   108 {
       
   109     JELOG2(EJavaConverters);
       
   110     iState = EInitialize;
       
   111     CompleteRequest();
       
   112 }
       
   113 
       
   114 /**
       
   115  * To stop whole back conversion.
       
   116  * Stops the active scheduler.
       
   117  */
       
   118 void CBackConverter::Exit()
       
   119 {
       
   120     Deque();
       
   121     CActiveScheduler::Stop();
       
   122 }
       
   123 
       
   124 /**
       
   125  * To complete the request for this object.
       
   126  *
       
   127  * @Postconditions The following conditions are true immediately after
       
   128  * returning from this method.
       
   129  * - iStatus == KErrNone
       
   130  * - IsActive() == ETrue
       
   131  */
       
   132 void CBackConverter::CompleteRequest()
       
   133 {
       
   134     JELOG2(EJavaConverters);
       
   135 
       
   136     TRequestStatus *status = &iStatus;
       
   137     User::RequestComplete(status, KErrNone);
       
   138     if (!IsActive())
       
   139     {
       
   140         SetActive();
       
   141     }
       
   142 }
       
   143 
       
   144 /**
       
   145  * To run this active object.
       
   146  *
       
   147  * The state logic is:
       
   148  *
       
   149  * EInitialize:
       
   150  *   - if midlet export data file does not exist, exit
       
   151  *
       
   152  * EReadConversionData:
       
   153  *   - read data from data file to iMidlets
       
   154  *
       
   155  * EReregisterMidlets:
       
   156  *   - register each midlet in iMidlets to AppArc
       
   157  *
       
   158  * EExit:
       
   159  *   - free resources and exit
       
   160  *
       
   161  */
       
   162 void CBackConverter::RunL()
       
   163 {
       
   164     JELOG2(EJavaConverters);
       
   165 
       
   166     switch (iState)
       
   167     {
       
   168 
       
   169     case EInitialize:
       
   170     {
       
   171         LOG(EJavaConverters, EInfo,
       
   172             "CBackConverter::RunL EInitialize");
       
   173 
       
   174         TFileName dataFile(KMidletImportDirectory);
       
   175         dataFile.Append(KMidletExportDataFileName);
       
   176         TUint attributes;
       
   177         TInt  err = iFs.Att(dataFile, attributes);
       
   178         if (KErrNone != err)
       
   179         {
       
   180             WLOG1(EJavaConverters,
       
   181                   "CBackConverter::RunL EInitialize "
       
   182                   "Data file does not exist (%d). Cannot do back conversion.", err);
       
   183             LOG1WSTR(EJavaConverters, EInfo,
       
   184                      "Data file name is %s", (wchar_t *)(dataFile.PtrZ()));
       
   185             iState = EExit;
       
   186         }
       
   187         else
       
   188         {
       
   189             iState = EReadConversionData;
       
   190         }
       
   191         CompleteRequest();
       
   192     }
       
   193     break;
       
   194 
       
   195     case EReadConversionData:
       
   196     {
       
   197         LOG(EJavaConverters, EInfo,
       
   198             "CBackConverter::RunL EReadConversionData");
       
   199 
       
   200         // Read all midlet info from data file to iMidlets
       
   201         TFileName importDirectory(KMidletImportDirectory);
       
   202         iMidlets->ImportListL(iFs, importDirectory);
       
   203 
       
   204         iState = EUnregisterOldMidletData;
       
   205         CompleteRequest();
       
   206     }
       
   207     break;
       
   208 
       
   209     case EUnregisterOldMidletData:
       
   210     {
       
   211         LOG(EJavaConverters, EInfo,
       
   212             "CBackConverter::RunL EUnregisterOldMidletData");
       
   213 
       
   214         // If executing backconverter after user cancel,
       
   215         // AppArc may contain Java 2.0 specific data
       
   216         // for converted midlets. Remove it or reregistration
       
   217         // will not update the data.
       
   218         UnregisterOldMidletData();
       
   219 
       
   220         iState = EReregisterMidlets;
       
   221         CompleteRequest();
       
   222     }
       
   223     break;
       
   224 
       
   225     case EReregisterMidlets:
       
   226     {
       
   227         LOG(EJavaConverters, EInfo,
       
   228             "CBackConverter::RunL EReregisterMidlets");
       
   229 
       
   230         // Reregister old midlet info back to AppArc
       
   231         RegisterMidletsL();
       
   232 
       
   233         // If this line is executed, registering old midlets
       
   234         // back to AppArc succeeded. So the data file can be
       
   235         // removed.
       
   236         RemoveDataFile();
       
   237 
       
   238         iState = EExit;
       
   239         CompleteRequest();
       
   240     }
       
   241     break;
       
   242 
       
   243     case EExit:
       
   244     {
       
   245         LOG(EJavaConverters, EInfo, "CBackConverter::RunL EExit");
       
   246 
       
   247         FullCleanup();
       
   248 
       
   249         // The whole javaappbackconverter process is stopped.
       
   250         Exit();
       
   251     }
       
   252     break;
       
   253 
       
   254     }
       
   255 }
       
   256 
       
   257 /**
       
   258  * To handle leave from RunL.
       
   259  * This method exits this active object using normal state machine
       
   260  * After calling this method this active object will exit.
       
   261  *
       
   262  * @param aError - A reason of error.
       
   263  * @return KErrNone.
       
   264  */
       
   265 TInt CBackConverter::RunError(TInt aError)
       
   266 {
       
   267     ELOG2(EJavaConverters,
       
   268           "CBackConverter::RunError(%d) from state %d", aError, iState);
       
   269 
       
   270     Cancel();
       
   271 
       
   272     iState = EExit;
       
   273     CompleteRequest();
       
   274 
       
   275     return KErrNone;
       
   276 }
       
   277 
       
   278 /**
       
   279  * To do cancelling for this object.
       
   280  *
       
   281  */
       
   282 void CBackConverter::DoCancel()
       
   283 {
       
   284     ELOG1(EJavaConverters,
       
   285           "CBackConverter::DoCancel from state %d", iState);
       
   286 
       
   287 }
       
   288 
       
   289 /**
       
   290  * To cleanup member variables.
       
   291  */
       
   292 void CBackConverter::FullCleanup()
       
   293 {
       
   294     JELOG2(EJavaPreinstaller);
       
   295 
       
   296     if (iMidlets)
       
   297     {
       
   298         iMidlets->ResetAndDestroy();
       
   299         delete iMidlets;
       
   300         iMidlets = NULL;
       
   301     }
       
   302 }
       
   303 
       
   304 /**
       
   305  * Register all midlets in iMidlets to AppArc.
       
   306  */
       
   307 void CBackConverter::RegisterMidletsL()
       
   308 {
       
   309     RApaLsSession apaSession;
       
   310 
       
   311     // open AppArc session
       
   312     TInt err = apaSession.Connect();
       
   313     if (KErrNone != err)
       
   314     {
       
   315         // Cannot connect to AppArc server
       
   316         ELOG(EJavaConverters,
       
   317              "CBackConverter::RegisterMidletsL: Cannot connect to AppArc server");
       
   318         User::Leave(err);
       
   319     }
       
   320     CleanupClosePushL(apaSession);
       
   321 
       
   322     // Delete any pending (un)registrations (possible if
       
   323     // e.g. device rebooted before commit).
       
   324     // This call does nothing if there is no pending registrations.
       
   325     // Ignore errors.
       
   326     (void)apaSession.RollbackNonNativeApplicationsUpdates();
       
   327 
       
   328     // Prepare for Java application registrations / unregistrations
       
   329     TRAP(err, apaSession.PrepareNonNativeApplicationsUpdatesL());
       
   330     if (KErrNone != err)
       
   331     {
       
   332         ELOG1(EJavaConverters,
       
   333               "CBackConverter::RegisterMidletsL: "
       
   334               "PrepareNonNativeApplicationsUpdatesL leaved with err %d",
       
   335               err);
       
   336         User::Leave(err);
       
   337     }
       
   338 
       
   339     // register midlets one by one
       
   340     CMidletInfo *midlet = iMidlets->GetFirst();
       
   341     TBuf8<512>   midletDesc;
       
   342 
       
   343     while (NULL != midlet)
       
   344     {
       
   345         midlet->ToString8(midletDesc);
       
   346         WLOG(EJavaConverters,
       
   347              "CBackConverter::RegisterMidletsL Going to reregister this midlet:");
       
   348         midletDesc.ZeroTerminate();
       
   349         WLOG(EJavaPreinstaller, (const char *)(midletDesc.Ptr()));
       
   350         midletDesc.Zero();
       
   351 
       
   352         RegisterOneMidletL(&apaSession, midlet);
       
   353         midlet = iMidlets->GetNext();
       
   354     }
       
   355 
       
   356     // commit registrations
       
   357     TRAP(err, apaSession.CommitNonNativeApplicationsUpdatesL());
       
   358     if (KErrNone != err)
       
   359     {
       
   360         ELOG1(EJavaConverters,
       
   361               "CBackConverter::RegisterMidletsL: "
       
   362               "CommitNonNativeApplicationsUpdatesL leaved with err %d",
       
   363               err);
       
   364         User::Leave(err);
       
   365     }
       
   366 
       
   367     CleanupStack::PopAndDestroy(); // apaSession
       
   368 }
       
   369 
       
   370 /**
       
   371  * Register one midlet to AppArc
       
   372  *
       
   373  * @param aSession AppArc session
       
   374  * @param aMidlet  the midlet to be registered
       
   375  * @exception If registering application fails
       
   376  */
       
   377 void CBackConverter::RegisterOneMidletL(RApaLsSession *aSession, CMidletInfo *aMidlet)
       
   378 {
       
   379     JELOG2(EJavaPreinstaller);
       
   380 
       
   381     RFile appArcIcon;
       
   382     TInt  numberOfIcons = 1;
       
   383 
       
   384     // open the icon in the shared mode required by AppArc
       
   385     TInt err = appArcIcon.Open(
       
   386                    iFs,
       
   387                    aMidlet->GetIconFileName(),
       
   388                    (EFileShareReadersOrWriters | EFileWrite));
       
   389     if (KErrNone != err)
       
   390     {
       
   391         ELOG1(EJavaConverters,
       
   392               "CBackConverter::RegisterOneMidletL: Cannot open icon, err code is %d ",
       
   393               err);
       
   394         User::Leave(err);
       
   395     }
       
   396 
       
   397     // Now icon is open
       
   398     CleanupClosePushL(appArcIcon);
       
   399 
       
   400     // Generate the executable name name using the same
       
   401     // algorithm as used earlier in S60 platform
       
   402     // in case some external S60 application
       
   403     // needs to parse the Uid from the executable name.
       
   404     TFileName appName;
       
   405     appName.Copy(KPathSeperator);
       
   406     appName.AppendNum(aMidlet->GetMidletUid().iUid);
       
   407     appName.Append(KAppPostfix);
       
   408 
       
   409     // Create writer needed for actual registration
       
   410     CApaRegistrationResourceFileWriter *writer = NULL;
       
   411     writer =
       
   412         CApaRegistrationResourceFileWriter::NewL(
       
   413             aMidlet->GetMidletUid(),
       
   414             appName,
       
   415             TApaAppCapability::ENonNative);
       
   416     CleanupStack::PushL(writer);
       
   417 
       
   418     writer->SetGroupNameL(aMidlet->GetGroupName());
       
   419 
       
   420     // Write MIDlet suite id and MIDlet id to opaque data  (needed by S60 MIDlet launcher)
       
   421     TBuf8<8>         opaqueData;     // opaque data will contain two signed 32-bit int
       
   422     RDesWriteStream  writeStream(opaqueData);
       
   423     writeStream.WriteInt32L(aMidlet->GetSuiteId());
       
   424     writeStream.WriteInt32L(aMidlet->GetMidletId());
       
   425     writeStream.CommitL();
       
   426     writer->SetOpaqueDataL(opaqueData);
       
   427 
       
   428     CApaLocalisableResourceFileWriter*  lWriter = NULL;
       
   429     lWriter =
       
   430         CApaLocalisableResourceFileWriter::NewL(
       
   431             KNullDesC,  // short caption
       
   432             aMidlet->GetMidletName(),  // caption
       
   433             numberOfIcons,
       
   434             KNullDesC);
       
   435     CleanupStack::PushL(lWriter);
       
   436 
       
   437     TDriveUnit targetDrive(aMidlet->GetDrive());
       
   438 
       
   439     // Register application to AppArc
       
   440     aSession->RegisterNonNativeApplicationL(
       
   441         KUidMidletApplicationType,
       
   442         targetDrive,
       
   443         *writer,
       
   444         lWriter,
       
   445         &appArcIcon);
       
   446 
       
   447     CleanupStack::PopAndDestroy(lWriter);
       
   448     CleanupStack::PopAndDestroy(writer);
       
   449     // close icon file handle
       
   450     CleanupStack::PopAndDestroy();  // appArcIcon
       
   451 }
       
   452 
       
   453 /**
       
   454  * Unregisters the applications to be back converted from AppArc
       
   455  * so that they can be registered again with the same Uid but with
       
   456  * new opaque data (needed for old S60 Java).
       
   457  * This function needs to called only if making back conversion after
       
   458  * the user has canceled the installation of Java 2.0.
       
   459  * If back conversion is done while uninstalling Java 2.0, all Java applications
       
   460  * have been uninstalled and there are no Uids to be unregistered.
       
   461  *
       
   462  * Leaves with error code if AppArc cannot be connected or if
       
   463  * unregistrations cannot be committed.
       
   464  */
       
   465 void CBackConverter::UnregisterOldMidletData()
       
   466 {
       
   467     // connect to AppArc
       
   468     RApaLsSession apaSession;
       
   469 
       
   470     TInt err = apaSession.Connect();
       
   471     if (KErrNone != err)
       
   472     {
       
   473         // Fatal error, try to connect again. The midlets cannot be back converted
       
   474         // using the same uids as earlier if the unregistration cannot be done.
       
   475         TInt retryCount = 0;
       
   476         do
       
   477         {
       
   478             ELOG1(EJavaConverters,
       
   479                   "CBackConverter::UnregisterCurrentJavaAppsL Cannot connect to "
       
   480                   "AppArc server, err %d", err);
       
   481 
       
   482             // wait
       
   483             User::After(KDelayWhenWaitingAppArc);
       
   484 
       
   485             err = apaSession.Connect();
       
   486             if (KErrNone == err)
       
   487             {
       
   488                 break;
       
   489             }
       
   490 
       
   491             retryCount++;
       
   492         }
       
   493         while (retryCount < 10);
       
   494 
       
   495         if (KErrNone != err)
       
   496         {
       
   497             return;
       
   498         }
       
   499     }
       
   500 
       
   501     // Delete any pending (un)registrations (possible if
       
   502     // e.g. device rebooted before commit).
       
   503     // This call does nothing if there is no pending registrations.
       
   504     // Ignore errors.
       
   505     (void)apaSession.RollbackNonNativeApplicationsUpdates();
       
   506 
       
   507     // Prepare for Java application unregistrations
       
   508     TRAP(err, apaSession.PrepareNonNativeApplicationsUpdatesL());
       
   509     if (KErrNone != err)
       
   510     {
       
   511         ELOG1(EJavaConverters,
       
   512               "CBackConverter::UnregisterCurrentJavaAppsL: "
       
   513               "PrepareNonNativeApplicationsUpdatesL leaved with err %d",
       
   514               err);
       
   515         apaSession.Close();
       
   516         return;
       
   517     }
       
   518 
       
   519     // Unregister all apps
       
   520     CMidletInfo *midlet = iMidlets->GetFirst();
       
   521 
       
   522     while (NULL != midlet)
       
   523     {
       
   524         TRAP(err, apaSession.DeregisterNonNativeApplicationL(midlet->GetMidletUid()));
       
   525         if (KErrNone != err)
       
   526         {
       
   527             WLOG2(EJavaConverters,
       
   528                   "CBackConverter::UnregisterCurrentJavaAppsL: "
       
   529                   "DeregisterNonNativeApplicationL leaved with err %d for uid %d",
       
   530                   err, midlet->GetMidletUid().iUid);
       
   531             // Ignore error, this particular application cannot be back converted.
       
   532         }
       
   533 
       
   534         midlet = iMidlets->GetNext();
       
   535     }
       
   536 
       
   537     // Commit unregistrations
       
   538     TRAP(err, apaSession.CommitNonNativeApplicationsUpdatesL())
       
   539     {
       
   540         if (KErrNone != err)
       
   541         {
       
   542             ELOG1(EJavaConverters,
       
   543                   "CBackConverter::UnregisterCurrentJavaAppsL: "
       
   544                   "CommitNonNativeApplicationsUpdatesL leaved with err %d",
       
   545                   err);
       
   546             apaSession.Close();
       
   547             return;
       
   548         }
       
   549     }
       
   550 
       
   551     apaSession.Close();
       
   552     return;
       
   553 }
       
   554 
       
   555 /**
       
   556  * Remove data file that contains info about midlets to be back converted.
       
   557  */
       
   558 void CBackConverter::RemoveDataFile()
       
   559 {
       
   560     TFileName dataFile(KMidletImportDirectory);
       
   561     dataFile.Append(KMidletExportDataFileName);
       
   562 
       
   563     TInt err = iFs.Delete(dataFile);
       
   564     if (KErrNone != err)
       
   565     {
       
   566         ELOG1(EJavaConverters,
       
   567               "CBackConverter::RemoveDataFile: Cannot delete data file, err %d ",
       
   568               err);
       
   569     }
       
   570 }