javamanager/javalauncher/src.s60/javalauncher.cpp
branchRCL_3
changeset 14 04becd199f91
child 18 9ac0a0a7da70
equal deleted inserted replaced
13:f5050f1da672 14:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2005-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:  The executable that enables launching OMJ Java
       
    15 *                applications in S60
       
    16 *
       
    17 */
       
    18 
       
    19 #include <apacmdln.h>
       
    20 #include <bacline.h>
       
    21 #include <e32cmn.h>
       
    22 #include <s32mem.h>
       
    23 #include <unistd.h>
       
    24 
       
    25 #include "commsmessage.h"
       
    26 #include "commsclientendpoint.h"
       
    27 #include "exceptionbase.h"
       
    28 #include "javainifileutils.h"
       
    29 #include "javaoslayer.h"
       
    30 #include "javastorage.h"
       
    31 #include "javastorageentry.h"
       
    32 #include "javastoragenames.h"
       
    33 #include "javasymbianoslayer.h"
       
    34 #include "javauids.h"
       
    35 #include "logger.h"
       
    36 #include "rtcmessages.h"
       
    37 #include "runtimeexception.h"
       
    38 
       
    39 
       
    40 using namespace java::captain;
       
    41 using namespace java::storage;
       
    42 using namespace java::util;
       
    43 
       
    44 
       
    45 _LIT(KSemiColon, ";");
       
    46 
       
    47 const TInt KExtraLenForLoggingAndPrompting = 22;
       
    48 const TInt KArgumentValueMaxLen = 1568;  // Support worst case % encoded args of 512 chars
       
    49 
       
    50 // The Uid of the Web Browser process
       
    51 #define KBrowserUid 0x10008D39
       
    52 
       
    53 
       
    54 /**
       
    55  * Return the Uid of the application aMidletName in package aPackageId.
       
    56  * If aMidletName is empty, return the Uid of the first application in
       
    57  * package aPackageId.
       
    58  *
       
    59  * @param aJs           JavaStorage connection, must be open
       
    60  * @param aPackageId    the id of the package
       
    61  * @param aMidletName   the name of the desired application in the package, can be empty
       
    62  * @param aUid          the Uid the found application is returned in this param
       
    63  * @return  KErrNone if Uid was found, otherwise one of the Symbian error codes
       
    64  * @throws  JavaStorageException if accessing Java Storage fails
       
    65  */
       
    66 static TInt getOneApplicationFromPackage(
       
    67     JavaStorage& aJs,
       
    68     const std::wstring& aPackageId,
       
    69     const std::wstring& aMidletName,
       
    70     TInt32 &aUid)
       
    71 {
       
    72     JavaStorageEntry attribute;
       
    73     JavaStorageApplicationEntry_t findPattern;
       
    74     JavaStorageApplicationList_t  foundEntries;
       
    75 
       
    76     // Get ID from APPLICATION_TABLE based on PACKAGE_ID and NAME
       
    77     attribute.setEntry(PACKAGE_ID, aPackageId);
       
    78     findPattern.insert(attribute);
       
    79     if (aMidletName.length() > 0)
       
    80     {
       
    81         attribute.setEntry(NAME, aMidletName);
       
    82         findPattern.insert(attribute);
       
    83     }
       
    84     attribute.setEntry(ID, L"");
       
    85     findPattern.insert(attribute);
       
    86 
       
    87     aJs.search(APPLICATION_TABLE, findPattern, foundEntries);
       
    88 
       
    89     if (foundEntries.size() < 1)
       
    90     {
       
    91         return KErrNotFound;
       
    92     }
       
    93 
       
    94     std::wstring applicationId = foundEntries.front().begin()->entryValue();
       
    95     TUid tmp;
       
    96     TInt err = uidToTUid(applicationId, tmp);
       
    97     if (KErrNone == err)
       
    98     {
       
    99         aUid = tmp.iUid;
       
   100     }
       
   101 
       
   102     return err;
       
   103 }
       
   104 
       
   105 
       
   106 /**
       
   107  * Decode %XX encoded UTF-8 characters embedded to UCS-2
       
   108  *
       
   109  * @param aCmdLineBuf  The command line to be decoded.
       
   110  */
       
   111 static void decodeCommandLineL(TPtr &aCmdLineBuf)
       
   112 {
       
   113     _LIT(KPercentage, "%");
       
   114     TInt ind = aCmdLineBuf.Find(KPercentage);
       
   115     if (KErrNotFound == ind)
       
   116     {
       
   117         // nothing to decode
       
   118         return;
       
   119     }
       
   120 
       
   121     LOG(EJavaCaptain, EInfo,
       
   122         "JavaLauncher:decodeCommandLineL convert percent encoded UTF-8 sequences to UTF-16 ");
       
   123 
       
   124     try
       
   125     {
       
   126         std::wstring cmdLine = desToWstring(aCmdLineBuf);
       
   127         std::wstring res = JavaCommonUtils::percentDecode(cmdLine);
       
   128 
       
   129         LOG1WSTR(EJavaCaptain, EInfo,
       
   130                  "JavaLauncher:decodeCommandLineL: decoded command line is %s", res.c_str());
       
   131 
       
   132         aCmdLineBuf = (const TUint16 *)res.c_str();
       
   133     }
       
   134     catch (std::exception& e)
       
   135     {
       
   136         ELOG1(EJavaCaptain,
       
   137               "JavaLauncher:decodeCommandLineL: cannot decode command line: %s", e.what());
       
   138         User::Leave(KErrGeneral);
       
   139     }
       
   140 }
       
   141 
       
   142 
       
   143 /**
       
   144  * Return the value of the argument specified by aArgName
       
   145  *
       
   146  * @param aMidletCmdLine command line to be parsed
       
   147  * @param aArgName the name of the argument
       
   148  * @return the value of the argument or empty wstring if no such argument
       
   149  */
       
   150 static std::wstring getArgValue(const TPtrC &aMidletCmdLine, const TDesC &aArgName)
       
   151 {
       
   152     TBuf<KArgumentValueMaxLen> valueBuf;
       
   153     TInt argPos = aMidletCmdLine.FindF(aArgName);
       
   154     if (argPos >= 0)
       
   155     {
       
   156         TInt semicolonPos = aMidletCmdLine.Mid(argPos).Find(KSemiColon);
       
   157         if (KErrNotFound == semicolonPos)
       
   158         {
       
   159             semicolonPos = aMidletCmdLine.Mid(argPos).Length();
       
   160         }
       
   161         TInt argLen = semicolonPos - aArgName.Length();
       
   162         if (argLen >= KArgumentValueMaxLen)
       
   163         {
       
   164             // Protect from buffer overflow.
       
   165             WLOG2(EJavaCaptain,
       
   166                   "javalauncher: argument value len too long (%d), cutting it to %d",
       
   167                   argLen, (KArgumentValueMaxLen - 1));
       
   168             argLen = KArgumentValueMaxLen - 1;
       
   169         }
       
   170 
       
   171         valueBuf = aMidletCmdLine.Mid(argPos + aArgName.Length(),  argLen);
       
   172     }
       
   173     valueBuf.Append('\0');
       
   174 
       
   175     std::wstring value = (wchar_t *)&(valueBuf[0]);
       
   176     return value;
       
   177 }
       
   178 
       
   179 
       
   180 /**
       
   181  * Parse the names of the MIDlet suite and MIDlet vendor from aMidletCmdLine
       
   182  * parameter and use them to find the MIDlet suite from Java Storage.
       
   183  * Then return Uid of the named MIDlet or if 'midlet-n' argument is not given
       
   184  * in command line, the Uid of the first MIDlet in the suite.
       
   185  * Return the uid of the MIDlet in aUid.
       
   186  *
       
   187  * @param aMidletCmdLine the command line that contains at least midlet-name
       
   188  *  and midlet-vendor arguments
       
   189  * @param aUid if the MIDlet is found from Java Storage, contains the Uid after return.
       
   190  * @return KErrNone if MIDlet was found. KErrPathNotFound if MIDlet is not found.
       
   191  *  Standard Symbian error codes in other cases.
       
   192  */
       
   193 static TInt getUidByNames(const TPtrC &aMidletCmdLine, TInt32 &aUid)
       
   194 {
       
   195     _LIT(KMidletNameArg, "midlet-name=");
       
   196     _LIT(KMidletVendorArg, "midlet-vendor=");
       
   197     _LIT(KMidletNArg, "midlet-n=");
       
   198 
       
   199     TInt err = aMidletCmdLine.FindF(KMidletNameArg);
       
   200     if (KErrNotFound == err)
       
   201     {
       
   202         return KErrArgument;
       
   203     }
       
   204     err = aMidletCmdLine.FindF(KMidletVendorArg);
       
   205     if (KErrNotFound == err)
       
   206     {
       
   207         return KErrArgument;
       
   208     }
       
   209 
       
   210     std::wstring suiteName = getArgValue(aMidletCmdLine, KMidletNameArg);
       
   211     std::wstring vendorName = getArgValue(aMidletCmdLine, KMidletVendorArg);
       
   212     std::wstring midletName = getArgValue(aMidletCmdLine, KMidletNArg);
       
   213 
       
   214     if (suiteName.empty() || vendorName.empty())
       
   215     {
       
   216         return KErrArgument;
       
   217     }
       
   218 
       
   219     // Find application uid based on names from Java Storage
       
   220     JavaStorage *js = JavaStorage::createInstance();
       
   221 
       
   222     try
       
   223     {
       
   224         js->open(JAVA_DATABASE_NAME);
       
   225 
       
   226         JavaStorageEntry attribute;
       
   227         JavaStorageApplicationEntry_t findPattern;
       
   228         JavaStorageApplicationList_t  foundEntries;
       
   229 
       
   230         // Search for package ID by PACKAGE_NAME and VENDOR from APPLICATION_PACKAGE_TABLE
       
   231         attribute.setEntry(PACKAGE_NAME, suiteName);
       
   232         findPattern.insert(attribute);
       
   233         attribute.setEntry(VENDOR, vendorName);
       
   234         findPattern.insert(attribute);
       
   235         attribute.setEntry(ID, L"");
       
   236         findPattern.insert(attribute);
       
   237 
       
   238         js->search(APPLICATION_PACKAGE_TABLE , findPattern, foundEntries);
       
   239 
       
   240         // Is anything found
       
   241         if (foundEntries.size() > 0)
       
   242         {
       
   243             // The application package has been found, get the ID of the package
       
   244             std::wstring value = foundEntries.front().begin()->entryValue();
       
   245             LOG1WSTR(EJavaCaptain, EInfo,
       
   246                      "JavaLauncher: getUidByNamesL: Found suite uid by name. Uid is %s",
       
   247                      value.c_str());
       
   248 
       
   249             // Now find the Uid of the first or specified application in the package
       
   250             err = getOneApplicationFromPackage(*js, value, midletName, aUid);
       
   251         }
       
   252         else
       
   253         {
       
   254             err = KErrPathNotFound;
       
   255         }
       
   256     }
       
   257     catch (JavaStorageException& e)
       
   258     {
       
   259         ELOG1(EJavaCaptain, "Java Storage exception %s", e.what());
       
   260         err = KErrGeneral;
       
   261     }
       
   262 
       
   263     try
       
   264     {
       
   265         js->close();
       
   266     }
       
   267     catch (JavaStorageException& e2)
       
   268     {
       
   269         WLOG1(EJavaCaptain, "Java Storage exception when closing storage %s", e2.what());
       
   270     }
       
   271 
       
   272     delete js;
       
   273 
       
   274     return err;
       
   275 }
       
   276 
       
   277 
       
   278 /**
       
   279  * Check whether the MIDlet has been installed to device.
       
   280  *
       
   281  * @param aUid the Uid of the MIDlet to be checked
       
   282  * @return KErrNone if the MIDlet has been installed,
       
   283  *         KErrNotFound if the MIDlet has not been installed,
       
   284  *         general Symbian error codes in case of error
       
   285  */
       
   286 static TInt verifyAppExists(TInt32 aUid)
       
   287 {
       
   288     TInt err = KErrNone;
       
   289 
       
   290     if (aUid == 0)
       
   291     {
       
   292         return KErrNotFound;
       
   293     }
       
   294 
       
   295     // Find application uid based on names from Java Storage
       
   296     JavaStorage *js = JavaStorage::createInstance();
       
   297 
       
   298     try
       
   299     {
       
   300         js->open(JAVA_DATABASE_NAME);
       
   301 
       
   302         JavaStorageEntry attribute;
       
   303         JavaStorageApplicationEntry_t findPattern;
       
   304         JavaStorageApplicationList_t  foundEntries;
       
   305 
       
   306         // Search for application NAME by ID from APPLICATION_TABLE
       
   307         Uid uid;
       
   308         TUid tuid;
       
   309         tuid.iUid = aUid;
       
   310         TUidToUid(tuid, uid);
       
   311         attribute.setEntry(ID, uid.toString());
       
   312         findPattern.insert(attribute);
       
   313         attribute.setEntry(NAME, L"");
       
   314         findPattern.insert(attribute);
       
   315 
       
   316         js->search(APPLICATION_TABLE , findPattern, foundEntries);
       
   317 
       
   318         // Is anything found
       
   319         if (foundEntries.size() > 0)
       
   320         {
       
   321             err = KErrNone;
       
   322         }
       
   323         else
       
   324         {
       
   325             err = KErrNotFound;
       
   326         }
       
   327     }
       
   328     catch (JavaStorageException& e)
       
   329     {
       
   330         ELOG1(EJavaCaptain, "Java Storage exception %s", e.what());
       
   331         err = KErrGeneral;
       
   332     }
       
   333 
       
   334     try
       
   335     {
       
   336         js->close();
       
   337     }
       
   338     catch (JavaStorageException& e2)
       
   339     {
       
   340         WLOG1(EJavaCaptain, "Java Storage exception when closing storage %s", e2.what());
       
   341     }
       
   342 
       
   343     delete js;
       
   344 
       
   345     return err;
       
   346 }
       
   347 
       
   348 
       
   349 /**
       
   350  * Either parse the Uid from the value of 'midlet-uid' parameter in
       
   351  * command line given in aMidletCmdLine or find the midlet
       
   352  * based on the 'midlet-name' and 'midlet-vendor' from
       
   353  * Java Storage / AppArc and return the Uid of the midlet.
       
   354  *
       
   355  * @param aMidletCmdLine  command line to be parsed, the format is
       
   356  *  [midlet-name=XXX;midlet-vendor=XXX;|midlet-uid=YYY;]midlet-args=XXX
       
   357  * @param aUid will contain the Uid parsed from command line
       
   358  * @return KErrNone if the command line specified Uid
       
   359  */
       
   360 static TInt getUidFromCommandLine(const TPtrC &aMidletCmdLine, TInt32 &aUid)
       
   361 {
       
   362     _LIT(KMidletUidArg, "midlet-uid=");
       
   363     _LIT(KHexValueStart, "0x");
       
   364     TInt err(KErrNone);
       
   365     TInt argPos = aMidletCmdLine.FindF(KMidletUidArg);
       
   366     if (KErrNotFound != argPos)
       
   367     {
       
   368         TPtrC uidToParse = aMidletCmdLine.Mid(argPos + KMidletUidArg.iTypeLength);
       
   369         TLex parseUid(uidToParse);
       
   370         if (uidToParse.FindF(KHexValueStart) == 0)
       
   371         {
       
   372             parseUid.Inc(2); // skip hex prefix
       
   373             TUint32 tmpValue;
       
   374             err = parseUid.Val(tmpValue, EHex);
       
   375             aUid = tmpValue;
       
   376         }
       
   377         else
       
   378         {
       
   379             err = parseUid.Val(aUid);
       
   380         }
       
   381 
       
   382         if (KErrNone != err)
       
   383         {
       
   384             ELOG1(EJavaCaptain,
       
   385                   "javalauncher failed parsing app Uid from cmdline midlet-uid param. Error %d",
       
   386                   err);
       
   387         }
       
   388 
       
   389         err = verifyAppExists(aUid);
       
   390     }
       
   391     else
       
   392     {
       
   393         err = getUidByNames(aMidletCmdLine, aUid);
       
   394         if (KErrNone != err)
       
   395         {
       
   396             if (KErrArgument == err)
       
   397             {
       
   398                 // In this case the Uid is not in opaque data and there are
       
   399                 // no midlet-uid or midlet-name + midlet-vendor parameters in the command line
       
   400                 ELOG(EJavaCaptain,
       
   401                      "javalauncher cannot launch app because there is no info to determine Uid.");
       
   402             }
       
   403             else
       
   404             {
       
   405                 ELOG1(EJavaCaptain,
       
   406                       "javalauncher failed getting app Uid based on cmdline midlet-name and "
       
   407                       "midlet-vendor params. Error %d",
       
   408                       err);
       
   409             }
       
   410         }
       
   411     }
       
   412 
       
   413     return err;
       
   414 }
       
   415 
       
   416 
       
   417 /**
       
   418  * Parse CApaCommandLine and optional normal process command line.
       
   419  * Determine the uid of the Java application to be started
       
   420  *
       
   421  * @param aCmdLine returns value of midlet-args
       
   422  * @param aUid returns Uid of the Java application to be started
       
   423  * @param aBackGroundLaunch returns info whether back ground launch is needed
       
   424  * @return KErrNone or error code
       
   425  */
       
   426 TInt getCmdLineAndUidL(HBufC **aCmdLine, TInt *aUid, TBool *aBackGroundLaunch)
       
   427 {
       
   428     CApaCommandLine* commandLine;
       
   429 
       
   430     // CApaCommandLine command line is used when AppArc is launching Java application.
       
   431     // Uid is in opaque data and possible document name is in document name field.
       
   432     TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
       
   433     if (KErrNone != err)
       
   434     {
       
   435         return err;
       
   436     }
       
   437     CleanupStack::PushL(commandLine);
       
   438 
       
   439     // The following feature is not supported yet.
       
   440     // It needs changes also to Java Installer and to
       
   441     // Symbian Settings UI
       
   442     TInt maxExtraSpaceForDocumentArg = 0;
       
   443 #ifdef RD_JAVA_SUPPORT_JAVA_APPS_AS_MIME_TYPE_HANDLERS
       
   444     _LIT(KDocumentOnlyCmdLine, "midlet-args=document=");
       
   445     TFullName documentName;
       
   446     documentName = commandLine->DocumentName();
       
   447     if (documentName.Length() > 0)
       
   448     {
       
   449         maxExtraSpaceForDocumentArg =
       
   450             documentName.Length() + KDocumentOnlyCmdLine.iTypeLength +
       
   451             KSemiColon.iTypeLength;
       
   452 
       
   453         LOG1WSTR(EJavaCaptain, EInfo,
       
   454                  "JavaLauncher: document to handle is %s",
       
   455                  (wchar_t *)(documentName.PtrZ()));
       
   456     }
       
   457 #endif
       
   458 
       
   459     // User::CommandLine command line is used when Java application is launched
       
   460     // from native application or from javaapp: or localapp:/jam/launch/ scheme
       
   461     // handler plugin.
       
   462     HBufC *pBufCmdLine =
       
   463         HBufC::NewLC(User::CommandLineLength() +
       
   464                      maxExtraSpaceForDocumentArg +
       
   465                      KExtraLenForLoggingAndPrompting);
       
   466     TPtr cmdLineBuf = pBufCmdLine->Des();
       
   467     User::CommandLine(cmdLineBuf);
       
   468 
       
   469     if (pBufCmdLine->Length() > 0)
       
   470     {
       
   471         LOG1WSTR(EJavaCaptain, EInfo,
       
   472                  "JavaLauncher: command line of this process is %s",
       
   473                  (wchar_t *)(cmdLineBuf.PtrZ()));
       
   474 
       
   475         // If the commandline contains hex encoded UTF-8 characters %XX decode them to UCS-2 (UTF-16)
       
   476         // For example "%C3%80%C3%80nes%C3%80.txt"
       
   477         decodeCommandLineL(cmdLineBuf);
       
   478     }
       
   479 
       
   480     TPtrC8 data = commandLine->OpaqueData();
       
   481     TInt32 uid = 0;  // application uid
       
   482     // New OMJ Java applications have 4 bytes of opaque data.
       
   483     TBool uidInOpaqueData = (data.Length() == 4);
       
   484     TBool backGroundLaunch =
       
   485         (EApaCommandBackground == commandLine->Command()) ||
       
   486         (EApaCommandBackgroundAndWithoutViews == commandLine->Command());
       
   487 
       
   488     if (uidInOpaqueData)
       
   489     {
       
   490         RDesReadStream stream(data);
       
   491         // OMJ java application, read the application uid
       
   492         TRAP(err, uid = stream.ReadInt32L());
       
   493         stream.Close();
       
   494         if (KErrNone != err)
       
   495         {
       
   496             ELOG1(EJavaCaptain,
       
   497                   "javalauncher failed reading app Uid from cmdline opaque data. Error %d",
       
   498                   err);
       
   499 
       
   500             CleanupStack::PopAndDestroy(pBufCmdLine);
       
   501             CleanupStack::PopAndDestroy(commandLine);
       
   502             return err;
       
   503         }
       
   504     }
       
   505     else
       
   506     {
       
   507         // Can the midlet uid be determined using info in the commandline?
       
   508         err = getUidFromCommandLine(cmdLineBuf, uid);
       
   509         if (KErrNone != err)
       
   510         {
       
   511             CleanupStack::PopAndDestroy(pBufCmdLine);
       
   512             CleanupStack::PopAndDestroy(commandLine);
       
   513             return err;
       
   514         }
       
   515     }
       
   516 
       
   517 #ifdef RD_JAVA_SUPPORT_JAVA_APPS_AS_MIME_TYPE_HANDLERS
       
   518     // Add possible document name to Java application command line.
       
   519 
       
   520     // javalauncher.exe can be started with CApaCommandLine coming from AppArc
       
   521     // that may specify document name but no other arguments for Java application.
       
   522     // In this case the current command line is empty and we must create a command
       
   523     // line that contains the document name.
       
   524     if (pBufCmdLine->Length() == 0)
       
   525     {
       
   526         if (documentName.Length() > 0)
       
   527         {
       
   528             cmdLineBuf.Append(KDocumentOnlyCmdLine);
       
   529             cmdLineBuf.Append(documentName);
       
   530             cmdLineBuf.Append(KSemiColon);
       
   531         }
       
   532     }
       
   533 #endif
       
   534 
       
   535     if (cmdLineBuf.Length() > 0)
       
   536     {
       
   537         LOG1WSTR(EJavaCaptain, EInfo,
       
   538                  "JavaLauncher: full java application cmd line is : %s",
       
   539                  (wchar_t *)(cmdLineBuf.PtrZ()));
       
   540     }
       
   541 
       
   542     // Uid has already been determined, the whole command line is not needed
       
   543     // anymore, only the arguments for the Java application
       
   544     _LIT(KMidletArgs, "midlet-args=");
       
   545     TInt  argsPos = cmdLineBuf.FindF(KMidletArgs);
       
   546     TBool cmdLineIsNotEmpty = EFalse;
       
   547     if (argsPos >= 0)
       
   548     {
       
   549         // Pass everything that follows "midlet-args="
       
   550         cmdLineBuf.Delete(0, argsPos + KMidletArgs.iTypeLength);
       
   551         cmdLineIsNotEmpty = ETrue;
       
   552     }
       
   553     else
       
   554     {
       
   555         // No arguments for the Java application
       
   556         cmdLineBuf.Zero();
       
   557     }
       
   558 
       
   559     // If Browser starts Java application with
       
   560     // command line parameters, the user must be asked for a confirmation
       
   561     // before the application is started.
       
   562     // This prevents automatic starting of Java applications from a web
       
   563     // page using 'javaapp:' url and java script.
       
   564     TUid parentUid = User::CreatorIdentity();
       
   565     LOG1(EJavaCaptain, EInfo, "JavaLauncher: Parent process uid is %x", parentUid.iUid);
       
   566     if (parentUid.iUid == KBrowserUid)
       
   567     {
       
   568         // Pass information that the application start up must be prompted
       
   569         // in the java application command line
       
   570         if (cmdLineIsNotEmpty)
       
   571         {
       
   572             cmdLineBuf.Append(KSemiColon);
       
   573         }
       
   574         _LIT(KPromptStart, "PromptAppStartup");
       
   575         cmdLineBuf.Append(KPromptStart);
       
   576     }
       
   577 
       
   578     // Return command line, uid and info whether this is back ground launch
       
   579     *aBackGroundLaunch = backGroundLaunch;
       
   580     *aUid = uid;
       
   581     CleanupStack::Pop(pBufCmdLine);
       
   582     *aCmdLine = pBufCmdLine;
       
   583     CleanupStack::PopAndDestroy(commandLine);
       
   584 
       
   585     return KErrNone;
       
   586 }
       
   587 
       
   588 
       
   589 /**
       
   590  *  Start Java Captain process
       
   591  */
       
   592 TInt startJavaCaptain()
       
   593 {
       
   594     // Start 'systemams.exe' in S60 5.0 (it will start javacaptain) and
       
   595     // 'javacaptain.exe' in 9.2 and later
       
   596 
       
   597 #ifdef RD_JAVA_S60_RELEASE_5_0_IAD
       
   598     _LIT(KJavaCaptainExe, "systemams.exe");
       
   599 #else
       
   600     _LIT(KJavaCaptainExe, "javacaptain.exe");
       
   601 #endif
       
   602     _LIT(KJavaCaptainArg, "");
       
   603     RProcess proc;
       
   604     int err = proc.Create(KJavaCaptainExe, KJavaCaptainArg);
       
   605     if (err == KErrNone)
       
   606     {
       
   607         proc.Resume();
       
   608 #ifdef RD_JAVA_S60_RELEASE_5_0_IAD
       
   609         LOG(EJavaCaptain, EInfo, "javalauncher: startJavaCaptain systemams.exe was started ok");
       
   610 #else
       
   611         LOG(EJavaCaptain, EInfo, "javalauncher: startJavaCaptain javacaptain.exe was started ok");
       
   612 #endif
       
   613 
       
   614         // Wait 3 seconds so that Java Captain has time to start
       
   615         User::After(3000000);
       
   616     }
       
   617     else
       
   618     {
       
   619 #ifdef RD_JAVA_S60_RELEASE_5_0_IAD
       
   620         ELOG1(EJavaCaptain, "javalauncher: startJavaCaptain start systemams.exe failed: %d", err);
       
   621 #else
       
   622         ELOG1(EJavaCaptain, "javalauncher: startJavaCaptain start javacaptain.exe failed: %d", err);
       
   623 #endif
       
   624     }
       
   625     proc.Close();
       
   626 
       
   627     return err;
       
   628 }
       
   629 
       
   630 
       
   631 /**
       
   632  * Determine the uid of the Java application to be started and
       
   633  * ask Java Captain to launch the application.
       
   634  * Pass parsed arguments for the application in the Comms message
       
   635  * that is sent to Java Captain to start the applciation.
       
   636  *
       
   637  * @return KErrNone or error code
       
   638  */
       
   639 TInt handleLaunchL(void)
       
   640 {
       
   641     HBufC *pBufCmdLine = NULL;
       
   642     TInt   uid;
       
   643     TBool  backGroundLaunch = EFalse;
       
   644     TInt err = getCmdLineAndUidL(&pBufCmdLine, &uid, &backGroundLaunch);
       
   645     if (KErrNone != err)
       
   646     {
       
   647         return err;
       
   648     }
       
   649     TPtr cmdLineBuf = pBufCmdLine->Des();
       
   650 
       
   651     LOG1(
       
   652         EJavaCaptain,
       
   653         EInfo,
       
   654         "javalauncher launching app uid %d", uid);
       
   655 
       
   656     try
       
   657     {
       
   658         JavaOsLayer::startUpTrace("JavaLauncher: starting Comms", -1, -1);
       
   659         CommsMessage message;
       
   660         message.setModuleId(PLUGIN_ID_RTC_C);
       
   661         message.setReceiver(IPC_ADDRESS_JAVA_CAPTAIN_C);
       
   662         message.setSender(IPC_ADDRESS_JAVA_CAPTAIN_C);
       
   663         TUid tuid = TUid::Uid(uid);
       
   664         Uid uuid;
       
   665         std::wstring applicationArguments(desToWstring(cmdLineBuf));
       
   666 
       
   667         setLaunchApplicationReqParams(message, TUidToUid(tuid, uuid),
       
   668                                       (backGroundLaunch ? RTC_LAUNCH_TYPE_BACKGROUND_C : RTC_LAUNCH_TYPE_NORMAL_C),
       
   669                                       RTC_LAUNCH_OPTIONS_NONE_C,
       
   670                                       RTC_LAUNCH_RUNTIME_MIDP_C,
       
   671                                       applicationArguments);
       
   672 
       
   673         CommsClientEndpoint comms;
       
   674         err = comms.connect(IPC_ADDRESS_JAVA_CAPTAIN_C);
       
   675         if (KErrNotFound == err)
       
   676         {
       
   677             ELOG(EJavaCaptain,
       
   678                  "javalauncher: Java Captain was not running. Trying to restart it.");
       
   679 
       
   680             // Java Captain is not running, try to start it
       
   681             err = startJavaCaptain();
       
   682             if (KErrNone == err)
       
   683             {
       
   684                 err = comms.connect(IPC_ADDRESS_JAVA_CAPTAIN_C);
       
   685             }
       
   686         }
       
   687 
       
   688         if (KErrNone == err)
       
   689         {
       
   690             err = comms.send(message);
       
   691         }
       
   692 
       
   693         if (KErrNone != err)
       
   694         {
       
   695             ELOG1(EJavaCaptain,
       
   696                   "javalauncher: OMJ app launch: Comms connect/send failed. Error %d ",
       
   697                   err);
       
   698         }
       
   699 
       
   700         // Ignore possible errors in disconnect
       
   701         (void)comms.disconnect();
       
   702     }
       
   703     catch (ExceptionBase& e)
       
   704     {
       
   705         ELOG1(EJavaCaptain,
       
   706               "javalauncher: OMJ app launch: ExceptionBase caught: %s ",
       
   707               e.toString().c_str());
       
   708     }
       
   709     catch (std::exception& e)
       
   710     {
       
   711         ELOG1(EJavaCaptain,
       
   712               "javalauncher: OMJ app launch: Exception %s caught", e.what());
       
   713     }
       
   714 
       
   715     return err;
       
   716 }
       
   717 
       
   718 
       
   719 /**
       
   720  * Main function of executable javalauncher.exe.
       
   721  * Symbian AppArc starts this executable when AppArc APIs are used to
       
   722  * start a Java application that has been registered to AppArc.
       
   723  * (Because this application has been registered to AppArc as the starter
       
   724  * application for all OMJ Java applications.)
       
   725  *
       
   726  * Reads the opaque data of the CApaCommandLine command line and
       
   727  * if the opaque data contains valid OMJ Java application Uid
       
   728  * sends a COMMS message to Java Captain asking that Captain starts
       
   729  * the application specified by the Uid.
       
   730  *
       
   731  * The document field of the CApaCommandline command line may contain the full path
       
   732  * name of the document that the java application should handle. It will be passed
       
   733  * to the Java application as an argument.
       
   734  *
       
   735  * This executable can be started also directly from other native processes
       
   736  * to start a Java application with arguments specified in normal process
       
   737  * command line.
       
   738  *
       
   739  * The command line format is
       
   740  * [midlet-name=XXX;midlet-vendor=XXX;[midlet-n=XXX;]|midlet-uid=YYY;]midlet-args=XXX
       
   741  * for example
       
   742  * midlet-name=Chess;midlet-vendor=Nokia;midlet-args=startMode=playChessDemo;sound=off;
       
   743  * 'midlet-args' specifies the arguments passed to Java application.
       
   744  * 'midlet-uid' or 'midlet-name'+'midlet-vendor' specify the Java application to be started
       
   745  *
       
   746  * Sample code for starting MIDlet from native code
       
   747  * @code
       
   748     RProcess rProcess;
       
   749     TInt err = rProcess.Create(_L("javalauncher.exe"),
       
   750         _L("midlet-uid=0x10137c4d;midlet-args=startMode=startFromCmdLine;sound=ON;landscapeMode=true;"));
       
   751     if (KErrNone == err)
       
   752     {
       
   753         TRequestStatus status;
       
   754         rProcess.Logon(status);
       
   755         rProcess.Resume();
       
   756 
       
   757         // now wait until javalauncher exits
       
   758         User::WaitForRequest(status);
       
   759         if (status.Int() != KErrNone)
       
   760         {
       
   761             // Launching midlet failed
       
   762             ...
       
   763         }
       
   764     }
       
   765     else
       
   766     {
       
   767         // Cannot start javalauncher.exe
       
   768         ...
       
   769     }
       
   770     rProcess.Close();
       
   771  * @endcode
       
   772  *
       
   773  */
       
   774 TInt E32Main(void)
       
   775 {
       
   776     JavaOsLayer::startUpTrace("JavaLauncher: Start", -1, -1);
       
   777 
       
   778     CTrapCleanup *pCleanupStack = CTrapCleanup::New();
       
   779     if (NULL == pCleanupStack)
       
   780     {
       
   781         ELOG(EJavaCaptain, "Cannot create CleanupStack in javalauncher main()");
       
   782         return KErrNoMemory;
       
   783     }
       
   784 
       
   785     TInt ret = KErrNone;
       
   786     TRAPD(err, ret = handleLaunchL());
       
   787     if (KErrNone != err)
       
   788     {
       
   789         ELOG1(EJavaCaptain, "javalauncher.exe: handleLaunchL leaved with err %d", err);
       
   790         delete pCleanupStack;
       
   791         return err;
       
   792     }
       
   793 
       
   794     delete pCleanupStack;
       
   795     return ret;
       
   796 }
       
   797