javaruntimes/midp/runtimestarter/src/midpruntimestarter.cpp
changeset 21 2a9601315dfc
child 23 98ccebc37403
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     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:  This class provides container for message.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <string>
       
    20 #include <string.h>
       
    21 #include <algorithm>
       
    22 #include <iostream>
       
    23 #include <fstream>
       
    24 #include <unistd.h>
       
    25 
       
    26 #include "midpruntimestarter.h"
       
    27 #include "applicationinfosetter.h"
       
    28 #include "runtimeexception.h"
       
    29 #include "runtimestarterutils.h"
       
    30 #include "midpruntimearguments.h"
       
    31 
       
    32 #include "dynamiclibloader.h"
       
    33 #include "javainifileutils.h"
       
    34 #include "javacommonutils.h"
       
    35 #include "javaoslayer.h"
       
    36 #include "logger.h"
       
    37 
       
    38 #include "commsmessage.h"
       
    39 #include "rtcmessages.h"
       
    40 
       
    41 #include "pushcontrollerstarter.h"
       
    42 
       
    43 #include "javastoragenames.h"
       
    44 
       
    45 #include "javacoreui.h"
       
    46 #include "javacoreuiparams.h"
       
    47 
       
    48 #include "com_nokia_mj_impl_rt_midp_MemoryLogger.h"
       
    49 
       
    50 using namespace java::runtime;
       
    51 using namespace java::util;
       
    52 using namespace java::push;
       
    53 using namespace java::storage;
       
    54 using namespace java::captain;
       
    55 using namespace java::ui;
       
    56 
       
    57 const wchar_t* const RUNTIME_MAIN_CLASS = L"com.nokia.mj.impl.rt.midp.Main";
       
    58 const wchar_t* const TRUE_WSTR          = L"true";
       
    59 
       
    60 
       
    61 MidpRuntimeStarter::MidpRuntimeStarter(): mMidletInfo(new MidletInfo()), // codescanner::nonleavenew
       
    62         mRuntimeState(Constructed)
       
    63 {
       
    64     JELOG2(EJavaRuntime);
       
    65 }
       
    66 
       
    67 MidpRuntimeStarter::~MidpRuntimeStarter()
       
    68 {
       
    69     JELOG2(EJavaRuntime);
       
    70     if (mPushLib.get())
       
    71     {
       
    72         mPushLib->closeLib();
       
    73     }
       
    74 }
       
    75 
       
    76 int MidpRuntimeStarter::start(int argc, char *argv[])
       
    77 {
       
    78     JELOG2(EJavaRuntime);
       
    79 
       
    80     // Create instance of RuntimeStarterUtils for thread supervisioning.
       
    81     std::auto_ptr<RuntimeStarterUtils> starterUtils(new RuntimeStarterUtils()); // codescanner::nonleavenew
       
    82     starterUtils->startThreadSupervisor();
       
    83 
       
    84     // Parse the args received from Captain.
       
    85     parseArgs(argc, argv);
       
    86 
       
    87     initComms();
       
    88 
       
    89     // Some push plugins needs to get the UID of the MIDlet and the root
       
    90     // path. Setting MidpRuntimeStarter as a service provider.
       
    91     setApplicationInfoProvider(*this);
       
    92 
       
    93     // Check if push command was receieved.
       
    94     if (mMidletInfo->mPushStart)
       
    95     {
       
    96         // In order ot serve ApplicationInfo we need to solve the
       
    97         // MIDlet suite UID.
       
    98         std::auto_ptr<JavaStorage> storage(JavaStorage::createInstance());
       
    99         storage->open();
       
   100         getMIDletSuiteUidFromStorage(*storage.get());
       
   101         storage->close();
       
   102         storage.reset(0);
       
   103 
       
   104         handlePushStart();
       
   105         // Handle case where during the push listening we receive a close cmd.
       
   106         if (mRuntimeState == Closing)
       
   107         {
       
   108             closePush();
       
   109             return 0;
       
   110         }
       
   111     }
       
   112     // Load the core UI
       
   113     std::auto_ptr<java::util::DynamicLibLoader> coreUiLoader;
       
   114     startCoreUi(coreUiLoader);
       
   115 
       
   116     // Create starter for starting the JVM
       
   117     std::auto_ptr<JvmStarter>
       
   118     jvm(JvmStarter::getJvmStarterInstance(JvmStarter::CLDC,
       
   119                                           L"Midp"));
       
   120 
       
   121     // Don't know the class path in pre-warm state.
       
   122     if (!mMidletInfo->mPreWarmStart)
       
   123     {
       
   124         jvm->appendClassPath(mMidletInfo->mClassPath);
       
   125         jvm->appendApplicationArgument(L"-uid");
       
   126         jvm->appendApplicationArgument(mMidletInfo->mMIDletUid.toString());
       
   127 
       
   128         // Get the heap size recorded from the previous runs.
       
   129         int heapSize = getHeapSize();
       
   130         if (heapSize > com_nokia_mj_impl_rt_midp_MemoryLogger_MAX_OLD_SPACE)
       
   131         {
       
   132             heapSize = com_nokia_mj_impl_rt_midp_MemoryLogger_MAX_OLD_SPACE;
       
   133         }
       
   134 
       
   135         if (heapSize > com_nokia_mj_impl_rt_midp_MemoryLogger_DEFAULT_OLD_SPACE)
       
   136         {
       
   137             jvm->overrideOldHeapSize(heapSize / 1024);
       
   138         }
       
   139     }
       
   140 
       
   141     jvm->setMainClass(RUNTIME_MAIN_CLASS);
       
   142     jvm->enableThreadDumping();
       
   143     jvm->appendSystemProperty(L"-Dcom.nokia.rt.port=midp");
       
   144 #ifndef RD_JAVA_UI_QT
       
   145     jvm->appendSystemProperty(L"-Dcom.nokia.legacy.support=LegacySymbian");
       
   146 #endif // RD_JAVA_UI_QT
       
   147 
       
   148     // Provide access to this object by Java peer via delivering a pointer
       
   149     // to this object.
       
   150     jvm->appendApplicationArgument(L"-handle");
       
   151     MidpStarterInternalSupport* internalSupport = this;
       
   152     int handle = reinterpret_cast<int>(internalSupport);
       
   153     jvm->appendApplicationArgument(JavaCommonUtils::intToWstring(handle));
       
   154 
       
   155     // If the intention is to go to prewarmed state pass the info to Java peer.
       
   156     if (mMidletInfo->mPreWarmStart)
       
   157     {
       
   158         jvm->appendApplicationArgument(L"-prewarm");
       
   159         // Captain needs a pid in order to identify the prewarmed runtime.
       
   160         jvm->appendApplicationArgument(JavaCommonUtils::intToWstring(getpid()));
       
   161 
       
   162         // Starting with lower old space in pre warm case.
       
   163         jvm->overrideOldHeapSize(36);
       
   164     }
       
   165 
       
   166     // If the requested to go to back ground, pass the info to Java peer.
       
   167     if (mMidletInfo->mBackGroundRequested)
       
   168     {
       
   169         jvm->appendApplicationArgument(L"-background");
       
   170         jvm->appendApplicationArgument(TRUE_WSTR);
       
   171     }
       
   172 
       
   173     // If the autoinvocation happened pass the info to Java peer.
       
   174     if (mMidletInfo->mAutoInvocationRequested)
       
   175     {
       
   176         jvm->appendApplicationArgument(L"-autoinvocation");
       
   177         jvm->appendApplicationArgument(TRUE_WSTR);
       
   178         jvm->appendApplicationArgument(L"-autoInvocationAdditional");
       
   179         jvm->appendApplicationArgument(mPushAdditionalInfo);
       
   180     }
       
   181 
       
   182     // Enable thread dumping. If the captain informed about debug mode
       
   183     // or arguments for MIDlet set the arguments provided by the captain.
       
   184     std::wstring midletArgs;
       
   185     starterUtils->enableDevelopmentFeatures(*jvm.get(),
       
   186                                             mMidletInfo->mDebugRequested || mMidletInfo->mMIDletHasArgs,
       
   187                                             &midletArgs);
       
   188 
       
   189     if (midletArgs.length() == 0)
       
   190     {
       
   191         // If MIDlet was waiting for push or was pre-warmed,
       
   192         // the arguments can be already in midlet info
       
   193         midletArgs = mMidletInfo->mMIDletArgs;
       
   194     }
       
   195 
       
   196     if (midletArgs.length() > 0)
       
   197     {
       
   198         // Pass the arguments to 'Java side' in encoded form.
       
   199         // Encoding is done to prevent security risks.
       
   200         std::wstring encodedArgs = L"-Dcom.nokia.mid.cmdline=";
       
   201 
       
   202         encodedArgs.append(encodeArgs(midletArgs));
       
   203 
       
   204         jvm->appendSystemProperty(encodedArgs);
       
   205         // remember the args
       
   206         mMidletInfo->mMIDletArgs = encodedArgs;
       
   207     }
       
   208 
       
   209     // When starting this property has always value "1"
       
   210     jvm->appendSystemProperty(L"-Dcom.nokia.mid.cmdline.instance=1");
       
   211 
       
   212     // There might be extensions available. Solving if those exist.
       
   213     std::wstring extendedBootClassPath;
       
   214     // This call is platform dependent.
       
   215     starterUtils->getExtBootClassPath(extendedBootClassPath);
       
   216     if (extendedBootClassPath.length() > 0)
       
   217     {
       
   218         // Append the extensions to bootclasspath.
       
   219         jvm->appendBootClassPath(extendedBootClassPath);
       
   220 
       
   221         // Provide the bootclasspath also as a system propery
       
   222         // for solving the protected and restricted packages.
       
   223         std::wstring addOnList(L"-Dcom.nokia.mj.addon.list=");
       
   224         addOnList += extendedBootClassPath;
       
   225         jvm->appendSystemProperty(addOnList);
       
   226     }
       
   227 
       
   228     mRuntimeState = Active;
       
   229 
       
   230     // Start the JVM.
       
   231     int status = jvm->startJvm();
       
   232 
       
   233     if (mComms.get())
       
   234     {
       
   235         mComms->disconnect();
       
   236     }
       
   237     CoreUi::releaseUi(coreUiLoader);
       
   238 
       
   239     return status;
       
   240 }
       
   241 
       
   242 
       
   243 void MidpRuntimeStarter::parseArgs(int argc, char* argv[])
       
   244 {
       
   245     JELOG2(EJavaRuntime);
       
   246 
       
   247     bool appUidFound = false;
       
   248 
       
   249     // Loop through the arguments. First one can be skipped, because it
       
   250     // contains the name of the executable.
       
   251     for (int index = 1 ; index < argc; index++)
       
   252     {
       
   253         const char* key = argv[index];
       
   254         const char* value = 0;
       
   255 
       
   256         // Checking if there is value available.
       
   257         if (index+1 < argc)
       
   258         {
       
   259             value = argv[index+1];
       
   260         }
       
   261         LOG2(EJavaRuntime, EInfo,"MidpRuntimeStarter::parseArgs(). "
       
   262              "Handling key %s with value %s",
       
   263              key,
       
   264              value==0?"<No Value>":value);
       
   265 
       
   266         if (strcmp(key, APP_UID_ARGUMENT) == 0)
       
   267         {
       
   268             if (value)
       
   269             {
       
   270                 mMidletInfo->mMIDletUid =
       
   271                     Uid(java::util::JavaCommonUtils::utf8ToWstring(value));
       
   272 
       
   273                 appUidFound = true;
       
   274                 index++;
       
   275             }
       
   276         }
       
   277 
       
   278         else if (strcmp(key, PREWARM_ARGUMENT) == 0)
       
   279         {
       
   280             mMidletInfo->mPreWarmStart = true;
       
   281             LOG1(EJavaRuntime, EInfo,"PREWARM_ARGUMENT = %d ",  mMidletInfo->mPreWarmStart);
       
   282         }
       
   283 
       
   284         else if (strcmp(key, PUSH_ARGUMENT) == 0)
       
   285         {
       
   286             mMidletInfo->mPushStart = true;
       
   287             LOG1(EJavaRuntime, EInfo,"PUSH_ARGUMENT = %d ",  mMidletInfo->mPushStart);
       
   288         }
       
   289 
       
   290         else if (strcmp(key, AUTO_INVOCATION_ARGUMENT) == 0)
       
   291         {
       
   292             mMidletInfo->mAutoInvocationRequested = true;
       
   293             LOG1(EJavaRuntime, EInfo,"AUTO_INVOCATION_ARGUMENT = %d ",  mMidletInfo->mAutoInvocationRequested);
       
   294         }
       
   295 
       
   296         else if (strcmp(key, DEBUG_ARGUMENT) == 0)
       
   297         {
       
   298             mMidletInfo->mDebugRequested = true;
       
   299             LOG1(EJavaRuntime, EInfo,"DEBUG_ARGUMENT = %d ",  mMidletInfo->mDebugRequested);
       
   300         }
       
   301 
       
   302         else if (strcmp(key, EXTRA_ARGUMENTS) == 0)
       
   303         {
       
   304             mMidletInfo->mMIDletHasArgs = true;
       
   305             LOG1(EJavaRuntime, EInfo,"EXTRA_ARGUMENTS = %d ",  mMidletInfo->mMIDletHasArgs);
       
   306         }
       
   307 
       
   308         else if (strcmp(key, BG_START_ARGUMENT) == 0)
       
   309         {
       
   310             mMidletInfo->mBackGroundRequested = true;
       
   311             LOG1(EJavaRuntime, EInfo,"BG_START_ARGUMENT = %d ",  mMidletInfo->mBackGroundRequested);
       
   312         }
       
   313 
       
   314         else
       
   315         {
       
   316             std::string errorStr("Unknown argument received: ");
       
   317             errorStr.append(key);
       
   318             throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   319         }
       
   320     }
       
   321 
       
   322     if (appUidFound == false && mMidletInfo->mPreWarmStart == false)
       
   323     {
       
   324         std::string errorStr("Argument ");
       
   325         errorStr.append(APP_UID_ARGUMENT);
       
   326         errorStr.append(" not defined!");
       
   327         throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   328     }
       
   329 }
       
   330 
       
   331 void MidpRuntimeStarter::startCoreUi(std::auto_ptr<java::util::DynamicLibLoader>& coreUiLoader)
       
   332 {
       
   333     CoreUi& coreUi = CoreUi::getUiInstance(coreUiLoader);
       
   334 
       
   335     // Create the default UI only if not going into pre-warmed state.
       
   336     if (!mMidletInfo->mPreWarmStart)
       
   337     {
       
   338 
       
   339         // Open a session to JavaStorage.
       
   340         std::auto_ptr<JavaStorage> javaStorage(JavaStorage::createInstance());
       
   341         javaStorage->open();
       
   342 
       
   343         CoreUiParams uiParams;
       
   344 
       
   345         // Get the MIDlet suite UID from storage.
       
   346         if (mMidletInfo->mMIDletSuiteUid.toString() == L"")
       
   347         {
       
   348             getMIDletSuiteUidFromStorage(*javaStorage.get());
       
   349         }
       
   350 
       
   351         // Check if the MIDlet has defined the Nokia-MIDlet-App-Orientation
       
   352         // JAD attribute.
       
   353         std::auto_ptr<std::wstring> appOrientation
       
   354         (getMidletAttributeFromStorage(*javaStorage.get(),
       
   355                                        L"Nokia-MIDlet-App-Orientation"));
       
   356         if (appOrientation.get() != 0)
       
   357         {
       
   358 
       
   359             std::transform(appOrientation->begin(), appOrientation->end(),
       
   360                            appOrientation->begin(), tolower);
       
   361             if (*appOrientation == L"portrait")
       
   362             {
       
   363                 uiParams.setOrientation(PORTRAIT);
       
   364             }
       
   365             else if (*appOrientation == L"landscape")
       
   366             {
       
   367                 uiParams.setOrientation(LANDSCAPE);
       
   368             }
       
   369             else
       
   370             {
       
   371                 WLOG1(EJavaRuntime, "appOrientation contained unknown value: %S",
       
   372                       appOrientation->c_str());
       
   373             }
       
   374         }
       
   375         else
       
   376         {
       
   377             LOG(EJavaRuntime, EInfo, "Nokia-MIDlet-App-Orientation not defined");
       
   378         }
       
   379 
       
   380         // Check if the MIDlet has defined the MIDlet-Splash-Screen-Image
       
   381         // JAD attribute.
       
   382         std::auto_ptr<std::wstring> splashScreen
       
   383         (getMidletAttributeFromStorage(*javaStorage.get(),
       
   384                                        L"MIDlet-Splash-Screen-Image"));
       
   385         if (splashScreen.get() != 0)
       
   386         {
       
   387             std::transform(splashScreen->begin(), splashScreen->end(),
       
   388                            splashScreen->begin(), tolower);
       
   389             if (*splashScreen == L"suppress")
       
   390             {
       
   391                 // If MIDlet-Splash-Screen-Image JAD attribute is suppress then
       
   392                 // we start the UI into background.
       
   393                 LOG(EJavaRuntime, EInfo, "MIDlet-Splash-Screen-Image is suppress");
       
   394                 uiParams.setScreenMode(NO_START_SCREEN);
       
   395                 uiParams.setBackgroundStart(true);
       
   396             }
       
   397             else
       
   398             {
       
   399                 // If MIDlet-Splash-Screen-Image JAD attribute is not suppress then
       
   400                 // we need to solve the root path of the MIDlet and provide that
       
   401                 // to the coreUI.
       
   402                 uiParams.setScreenMode(MIDLET_DEFINED_SCREEN);
       
   403                 LOG1(EJavaRuntime, EInfo, "MIDlet-Splash-Screen-Image, setPath to %S",
       
   404                      mMidletInfo->mMIDletRootPath.c_str());
       
   405             }
       
   406         }
       
   407         else
       
   408         {
       
   409             LOG(EJavaRuntime, EInfo, "MIDlet-Splash-Screen-Image not defined");
       
   410             uiParams.setScreenMode(DEFAULT_START_SCREEN);
       
   411         }
       
   412 
       
   413         getRootPath();
       
   414         uiParams.setImagePath(mMidletInfo->mMIDletRootPath);
       
   415 
       
   416         // If there was a background start requst pass the info to coreUi.
       
   417         // Also the autoinvocation start puts the screen into BG.
       
   418         if (mMidletInfo->mBackGroundRequested || mMidletInfo->mAutoInvocationRequested)
       
   419         {
       
   420             uiParams.setBackgroundStart(true);
       
   421         }
       
   422 
       
   423         // Start the coreUI.
       
   424         JavaOsLayer::startUpTrace("Starting CoreUI", -1, -1);
       
   425         coreUi.start(mMidletInfo->mMIDletUid, &uiParams);
       
   426         JavaOsLayer::startUpTrace("CoreUI started", -1, -1);
       
   427 
       
   428         getMIDletSuiteInfoFromStorage(javaStorage.get(), JAR_PATH,
       
   429                                       mMidletInfo->mClassPath);
       
   430     }
       
   431 
       
   432 }
       
   433 
       
   434 void MidpRuntimeStarter::
       
   435 ApplicationStateChangeRequest(ApplicationState state)
       
   436 {
       
   437     JELOG2(EJavaRuntime);
       
   438     LOG1(EJavaRuntime, EInfo, "ApplicationStateChangeRequest: %d", state);
       
   439     switch (state)
       
   440     {
       
   441     case START_APPLICATION:
       
   442     case CONTINUE_APPLICATION_STARTUP:
       
   443         doStateChange(Start);
       
   444         break;
       
   445 
       
   446     case CLOSE_APPLICATION:
       
   447         doStateChange(Stop);
       
   448         break;
       
   449 
       
   450     default:
       
   451         std::string errorStr("Illegal state ");
       
   452         errorStr.append(JavaCommonUtils::intToString(state));
       
   453         throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   454     }
       
   455 }
       
   456 
       
   457 void MidpRuntimeStarter::doStateChange(StateChangeRequest request)
       
   458 {
       
   459     JELOG2(EJavaRuntime);
       
   460     LOG2(EJavaRuntime, EInfo, "MidpRuntimeStarter::doStateChange. Request: %d,"
       
   461          " current state: %d", request, mRuntimeState);
       
   462     ScopedLock lock(mProcessesMutex); // Making the method thread safe
       
   463     switch (request)
       
   464     {
       
   465     case Start:
       
   466         // Check if we are still waiting start command.
       
   467         if (mRuntimeState == PushListen)
       
   468         {
       
   469             mRuntimeState = Active;
       
   470             //Allow application startUp.
       
   471             mMonitor->notify();
       
   472         }
       
   473         break;
       
   474 
       
   475     case Stop:
       
   476         // Check if we are still waiting start command.
       
   477         if (mRuntimeState == PushListen)
       
   478         {
       
   479             //Allow application to close.
       
   480             mRuntimeState = Closing;
       
   481             mMonitor->notify();
       
   482         }
       
   483         break;
       
   484 
       
   485     default:
       
   486         std::string errorStr("Illegal request ");
       
   487         errorStr.append(JavaCommonUtils::intToString(request));
       
   488         throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   489     }
       
   490 
       
   491 }
       
   492 void MidpRuntimeStarter::closeRuntimeInd()
       
   493 {
       
   494     JELOG2(EJavaRuntime);
       
   495     LOG(EJavaRuntime, EInfo, "Starter got close indication from JVM");
       
   496     if (mMidletInfo->mPushStart)
       
   497     {
       
   498         closePush();
       
   499     }
       
   500 }
       
   501 
       
   502 void MidpRuntimeStarter::setUids(const Uid& midletUid, const Uid& midletSuiteUid)
       
   503 {
       
   504     JELOG2(EJavaRuntime);
       
   505     mMidletInfo->mMIDletUid = midletUid;
       
   506     mMidletInfo->mMIDletSuiteUid = midletSuiteUid;
       
   507     LOG2(EJavaRuntime, EInfo, "Setting UID set during pre-warm start: m=%S, s=%S",
       
   508          mMidletInfo->mMIDletUid.toString().c_str(),
       
   509          mMidletInfo->mMIDletSuiteUid.toString().c_str());
       
   510 }
       
   511 
       
   512 int MidpRuntimeStarter::getHeapSize() const
       
   513 {
       
   514     JELOG2(EJavaRuntime);
       
   515     // No need to do charcter conversion in here.
       
   516     std::string root(mMidletInfo->mClassPath.begin(),
       
   517                      mMidletInfo->mClassPath.end());
       
   518     int heapSize = -1;
       
   519 
       
   520     // The file is stored into same location where the jar file is put.
       
   521     // replace the 'xxx.jar' with 'heap' and open the file.
       
   522 
       
   523     size_t pos = root.find_last_of("/\\");
       
   524     if (pos != std::string::npos)
       
   525     {
       
   526         root.erase(pos+1);
       
   527         root += "heap";
       
   528         LOG1(EJavaRuntime, EInfo, "Heap size from file %s.", root.c_str());
       
   529         try
       
   530         {
       
   531             std::ifstream heapFile;
       
   532             heapFile.open(root.c_str(), std::ifstream::in);
       
   533             heapFile >> heapSize;
       
   534             heapFile.close();
       
   535             LOG1(EJavaRuntime, EInfo, "  heap: %d.", heapSize);
       
   536         }
       
   537         catch (std::exception& e)
       
   538         {
       
   539             LOG2(EJavaRuntime, EInfo, "Not able to read from file %s. Error %s",
       
   540                  root.c_str(), e.what());
       
   541         }
       
   542     }
       
   543     return heapSize;
       
   544 }
       
   545 
       
   546 std::wstring MidpRuntimeStarter::encodeArgs(const std::wstring& str)
       
   547 {
       
   548     // Modify the places where the following characters are used to prevent
       
   549     // possible security problems when this string is passed as an command line
       
   550     // system property parameter to JVM
       
   551     const std::wstring specials(L"= -%");
       
   552 
       
   553     std::string::size_type idx = str.find_first_of(specials);
       
   554     std::string::size_type cur = 0;
       
   555 
       
   556     std::wstring res;
       
   557     std::string convBuf;
       
   558 
       
   559     while (idx != std::string::npos)
       
   560     {
       
   561         // Add all characters up to and including the current special char to
       
   562         // final result string
       
   563         if (idx >= cur)
       
   564         {
       
   565             res.append(str.substr(cur, (idx - cur) + 1));
       
   566         }
       
   567 
       
   568         // Encode all special characters 'X' in same way.
       
   569         // "X" -> "X%"
       
   570         res.append(L"%");
       
   571 
       
   572         cur = idx + 1;
       
   573         idx = str.find_first_of(specials, cur);
       
   574     }
       
   575 
       
   576     // Add characters after last special character if any
       
   577     res.append(str.substr(cur, str.length() - cur));
       
   578 
       
   579     return res;
       
   580 }
       
   581 
       
   582 void MidpRuntimeStarter::getMIDletSuiteUidFromStorage(java::storage::JavaStorage& storage)
       
   583 {
       
   584     JELOG2(EJavaRuntime);
       
   585 
       
   586     // Get the MIDlet suite UID.
       
   587     JavaStorageApplicationEntry_t midletEntries;
       
   588 
       
   589     // Reading the MIDlet specific attributes from APPLICATION_TABLE.
       
   590     // MIDlet UID is a key.
       
   591     storage.read(APPLICATION_TABLE, mMidletInfo->mMIDletUid,
       
   592                  midletEntries);
       
   593     // Storing UID of the MIDlet suite.
       
   594     mMidletInfo->mMIDletSuiteUid = Uid(getDbValue(midletEntries, PACKAGE_ID));
       
   595 }
       
   596 
       
   597 void MidpRuntimeStarter::getMIDletSuiteInfoFromStorage(JavaStorage* storageConnection,
       
   598         const std::wstring& key,
       
   599         std::wstring& value) const
       
   600 {
       
   601     JELOG2(EJavaRuntime);
       
   602 
       
   603     // If the JavaStorage connection is created temporarily in this method, auto_ptr is used to
       
   604     // ensure closing and destroyng the JavaStorage connection. Don't use javaStorage ptr to any
       
   605     // other purposes - instead use storageConnection.
       
   606     std::auto_ptr<JavaStorage> javaStorage;
       
   607     if (storageConnection == 0)
       
   608     {
       
   609         javaStorage.reset(JavaStorage::createInstance());
       
   610         storageConnection = javaStorage.get();
       
   611         javaStorage->open();
       
   612     }
       
   613 
       
   614     JavaStorageApplicationEntry_t midletSuiteEntries;
       
   615 
       
   616     // Reading the MIDlet suite specific attributes from
       
   617     // APPLICATION_PACKAGE_TABLE. MIDlet suite UID is a key.
       
   618     storageConnection->read(APPLICATION_PACKAGE_TABLE,
       
   619                             mMidletInfo->mMIDletSuiteUid,
       
   620                             midletSuiteEntries);
       
   621     value = getDbValue(midletSuiteEntries, key);
       
   622 }
       
   623 
       
   624 std::wstring*
       
   625 MidpRuntimeStarter::getMidletAttributeFromStorage(JavaStorage& storage,
       
   626         const std::wstring& searchKey)
       
   627 const
       
   628 {
       
   629     JELOG2(EJavaRuntime);
       
   630 
       
   631     JavaStorageEntry findPattern;
       
   632     JavaStorageApplicationEntry_t findPatterns;
       
   633     JavaStorageApplicationList_t foundEntries;
       
   634 
       
   635     findPattern.setEntry(ID, mMidletInfo->mMIDletSuiteUid.toString(),
       
   636                          JavaStorageEntry::STRING);
       
   637     findPatterns.insert(findPattern);
       
   638 
       
   639     findPattern.setEntry(NAME, searchKey, JavaStorageEntry::STRING);
       
   640     findPatterns.insert(findPattern);
       
   641 
       
   642     findPattern.setEntry(VALUE,L"");
       
   643     findPatterns.insert(findPattern);
       
   644 
       
   645     storage.search(APPLICATION_PACKAGE_ATTRIBUTES_TABLE, findPatterns, foundEntries);
       
   646 
       
   647     JavaStorageApplicationList_t::iterator iter = foundEntries.begin();
       
   648 
       
   649     if (iter != foundEntries.end())
       
   650     {
       
   651         JavaStorageEntry findPatternForValue;
       
   652         findPatternForValue.setEntry(VALUE, L"");
       
   653         JavaStorageApplicationEntry_t::iterator valueIter = iter->find(findPatternForValue);
       
   654         if (valueIter != iter->end())
       
   655         {
       
   656             return new std::wstring(valueIter->entryValue()); // codescanner::nonleavenew
       
   657         }
       
   658         else
       
   659         {
       
   660             std::string errorStr("MIDLET with UID: ");
       
   661             std::wstring uid = mMidletInfo->mMIDletUid.toString();
       
   662             errorStr += std::string(uid.begin(), uid.end());
       
   663             errorStr += ". Error reading from storage: ";
       
   664             errorStr += std::string(searchKey.begin(), searchKey.end());
       
   665             throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   666         }
       
   667     }
       
   668     return 0;
       
   669 }
       
   670 
       
   671 
       
   672 
       
   673 std::wstring MidpRuntimeStarter::getDbValue(
       
   674     const java::storage::JavaStorageApplicationEntry_t& entry,
       
   675     const std::wstring& key) const
       
   676 {
       
   677     JELOG2(EJavaRuntime);
       
   678     JavaStorageEntry findPattern;
       
   679     std::wstring empty;
       
   680 
       
   681     findPattern.setEntry(key, empty);
       
   682 
       
   683     // Get attribute from read attributes.
       
   684     JavaStorageApplicationEntry_t::const_iterator findIterator =
       
   685         entry.find(findPattern);
       
   686 
       
   687     if (findIterator != entry.end())
       
   688     {
       
   689         return findIterator->entryValue();
       
   690     }
       
   691     else
       
   692     {
       
   693         std::string errorStr("MIDLET with UID: ");
       
   694         std::wstring uid = mMidletInfo->mMIDletUid.toString();
       
   695         errorStr += std::string(uid.begin(), uid.end());
       
   696         errorStr += ". Not able to find attribute ";
       
   697         errorStr += std::string(key.begin(), key.end());
       
   698         throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   699     }
       
   700 }
       
   701 
       
   702 void MidpRuntimeStarter::handlePushStart()
       
   703 {
       
   704     JELOG2(EJavaRuntime);
       
   705     mMonitor.reset(Monitor::createMonitor());
       
   706     mRuntimeState = PushListen;
       
   707     PushControllerStarter::getPushControllerStarter(mPushLib).
       
   708     startListen(mMidletInfo->mMIDletUid, this);
       
   709     mMonitor->wait();
       
   710 }
       
   711 
       
   712 void MidpRuntimeStarter::closePush()
       
   713 {
       
   714     // Received a close message from Java peer.
       
   715     PushControllerStarter::getPushControllerStarter(mPushLib).close();
       
   716 }
       
   717 
       
   718 void MidpRuntimeStarter::
       
   719 startMidletRequestFromPush(const std::wstring& pushAdditionalInfo)
       
   720 {
       
   721     JELOG2(EJavaRuntime);
       
   722     mPushAdditionalInfo = pushAdditionalInfo;
       
   723 
       
   724     // This can be considered to be auto invocation. Setting flag on
       
   725     // to be delivered to Java runtime.
       
   726     mMidletInfo->mAutoInvocationRequested = true;
       
   727 
       
   728     doStateChange(Start);
       
   729 }
       
   730 
       
   731 void MidpRuntimeStarter::closeRuntimeRequestFromPush()
       
   732 {
       
   733     JELOG2(EJavaRuntime);
       
   734     doStateChange(Stop);
       
   735 }
       
   736 
       
   737 void MidpRuntimeStarter::initComms()
       
   738 {
       
   739     JELOG2(EJavaRuntime);
       
   740     mComms.reset(new CommsClientEndpoint(L"javacaptain")); // codescanner::nonleavenew
       
   741     mComms->registerDefaultListener(this);
       
   742     int result = mComms->connect(IPC_ADDRESS_JAVA_CAPTAIN_C);
       
   743     if (result != 0)
       
   744     {
       
   745         std::string errorStr("Connection to JavaCaptain failed: Reason = ");
       
   746         errorStr.append(JavaCommonUtils::intToString(result));
       
   747         throw RuntimeException(errorStr, __FILE__, __FUNCTION__, __LINE__);
       
   748     }
       
   749     CommsMessage msg;
       
   750     msg.setModuleId(PLUGIN_ID_RTC_C);
       
   751     setApplicationRunningIndParams(msg, mMidletInfo->mMIDletUid, 0);
       
   752     mComms->send(msg);
       
   753 }
       
   754 
       
   755 void MidpRuntimeStarter::processMessage(java::comms::CommsMessage& message)
       
   756 {
       
   757     JELOG2(EJavaRuntime);
       
   758     int messageId = message.getMessageId();
       
   759 
       
   760     // RTC_MSG_ID_LAUNCH_APPLICATION_REQ and
       
   761     // RTC_MSG_ID_TERMINATE_APPLICATION_REQ are received from the Java Captain
       
   762     // when we are listening push connection and the VM is not started.
       
   763     // When the MIDlet is running normally, these two messages are handled
       
   764     // by Java peer.
       
   765     // RTC_MSG_ID_ADD_PUSH_CONNECTION_IND is always handled here.
       
   766 
       
   767     switch (messageId)
       
   768     {
       
   769     case RTC_MSG_ID_LAUNCH_APPLICATION_REQ:
       
   770     {
       
   771         LOG(EJavaRuntime, EInfo, "RTC_MSG_ID_LAUNCH_APPLICATION_REQ");
       
   772         // Start the push MIDlet that is pre started to listen mode.
       
   773 
       
   774         Uid          uid;
       
   775         int          type;
       
   776         int          options;
       
   777         std::string  rtc;
       
   778         std::wstring midletArgs;
       
   779         std::wstring runtimeArguments;
       
   780 
       
   781         getLaunchApplicationReqParams(message, uid, type, options, rtc,
       
   782                                       midletArgs,
       
   783                                       runtimeArguments);
       
   784         if (type == RTC_LAUNCH_TYPE_AUTO_INVOCATION_C)
       
   785         {
       
   786             mMidletInfo->mAutoInvocationRequested = true;
       
   787         }
       
   788 
       
   789         // The arguments will be passed to midlet when JVM is started
       
   790         mMidletInfo->mMIDletArgs = midletArgs;
       
   791 
       
   792         ApplicationStateChangeRequest(START_APPLICATION);
       
   793     }
       
   794     break;
       
   795 
       
   796     case RTC_MSG_ID_TERMINATE_APPLICATION_REQ:
       
   797         LOG(EJavaRuntime, EInfo, "RTC_MSG_ID_TERMINATE_APPLICATION_REQ");
       
   798 
       
   799         // Stop the push MIDlet that is pre started to listen mode.
       
   800         ApplicationStateChangeRequest(CLOSE_APPLICATION);
       
   801         break;
       
   802 
       
   803     case RTC_MSG_ID_ADD_PUSH_CONNECTION_IND:
       
   804     {
       
   805         LOG(EJavaRuntime, EInfo, "RTC_MSG_ID_ADD_PUSH_CONNECTION_IND");
       
   806         Uid uidFromMessage;
       
   807         getUpdatePushReqParams(message, uidFromMessage);
       
   808         if (uidFromMessage == mMidletInfo->mMIDletUid)
       
   809         {
       
   810 
       
   811             PushControllerStarter::getPushControllerStarter(mPushLib).
       
   812             updatePushRegs(mMidletInfo->mMIDletUid, this);
       
   813         }
       
   814         else
       
   815         {
       
   816             ELOG2(EJavaRuntime, "getUpdatePushReqParams: wrong UID!: "
       
   817                   "%S should be %S",
       
   818                   uidFromMessage.toString().c_str(),
       
   819                   mMidletInfo->mMIDletUid.toString().c_str());
       
   820         }
       
   821     }
       
   822     break;
       
   823 
       
   824     default:
       
   825         ELOG1(EJavaRuntime, "Unknown message sent to Runtime %d",
       
   826               messageId);
       
   827         break;
       
   828     }
       
   829 }
       
   830 
       
   831 const std::wstring& MidpRuntimeStarter::getRootPath() const
       
   832 {
       
   833     JELOG2(EJavaRuntime);
       
   834     // If the root path is not yet cached, read it from storage.
       
   835     if (mMidletInfo->mMIDletRootPath.length() == 0)
       
   836     {
       
   837         getMIDletSuiteInfoFromStorage(0, ROOT_PATH,
       
   838                                       mMidletInfo->mMIDletRootPath);
       
   839     }
       
   840     return mMidletInfo->mMIDletRootPath;
       
   841 }
       
   842 
       
   843 const java::util::Uid& MidpRuntimeStarter::getUid() const
       
   844 {
       
   845     return mMidletInfo->mMIDletUid;
       
   846 }