javaruntimes/midp/runtime/javasrc/com/nokia/mj/impl/rt/midp/MidletLifeCycle.java
branchRCL_3
changeset 19 04becd199f91
child 23 98ccebc37403
equal deleted inserted replaced
16:f5050f1da672 19:04becd199f91
       
     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:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 package com.nokia.mj.impl.rt.midp;
       
    20 
       
    21 import java.io.InputStream;
       
    22 import java.io.InputStreamReader;
       
    23 import java.io.IOException;
       
    24 import java.util.Timer;
       
    25 import java.util.TimerTask;
       
    26 
       
    27 import com.nokia.mj.impl.rt.utils.ExtensionUtil;
       
    28 
       
    29 import com.nokia.mj.impl.rt.support.Jvm;
       
    30 import com.nokia.mj.impl.rt.support.JvmInternal;
       
    31 import com.nokia.mj.impl.rt.support.ThreadEventListener;
       
    32 
       
    33 import com.nokia.mj.impl.rt.legacy.LegacySupport;
       
    34 
       
    35 import com.nokia.mj.impl.gcf.PushSecurityUtils;
       
    36 
       
    37 import com.nokia.mj.impl.security.packageprotection.PackageProtector;
       
    38 import com.nokia.mj.impl.security.common.RuntimeSecurityException;
       
    39 import com.nokia.mj.impl.security.midp.authentication.AuthenticationModule;
       
    40 import com.nokia.mj.impl.security.midp.storage.AuthenticationStorageData;
       
    41 
       
    42 import com.nokia.mj.impl.fileutils.FileUtility;
       
    43 
       
    44 import com.nokia.mj.impl.coreui.CoreUi;
       
    45 
       
    46 import com.nokia.mj.impl.utils.LineReader;
       
    47 import com.nokia.mj.impl.utils.TaskQueue;
       
    48 import com.nokia.mj.impl.utils.Uid;
       
    49 import com.nokia.mj.impl.utils.StartUpTrace;
       
    50 
       
    51 /**
       
    52  * A core of the MIDP life cycle. This class controls the life time of the
       
    53  * MIDlet.
       
    54  * <p>
       
    55  * The implementation of this class can be divided into three catgories:
       
    56  *   -The initializing of the life cycle.
       
    57  *   -The state machine.
       
    58  *   -The shut down of the life cycle.
       
    59  * <p>
       
    60  * Initialization can be divided into three different phases. The pre init
       
    61  * are the actions that can be done without knowing the MIDlet to be started.
       
    62  * The pre init phase is done always - even when going into pre warm state.
       
    63  * The last phase is the post actions which require knowing the MIDlet.
       
    64  * The pre warm init is a special phase, which is done only when the MIDlet
       
    65  * after firstly started into pre-warmed state. When the life cycle receves
       
    66  * indication that the MIDlet should be started and receives the MIDlet UID,
       
    67  * the life cycle will do first the pre-warm init phae and finally does the
       
    68  * post initial phase.
       
    69  * <p>
       
    70  * The state machine is based on a simple FIFO style thread safe task queue.
       
    71  * When the life cycle enters into state machine phase it starts wait for
       
    72  * various tasks. It should be noted that in order to ensure thread safeness
       
    73  * of the life cycle all most all actions should be done via sending a task
       
    74  * queue. Once the state machine is exited a shut down phase begins.
       
    75  * <p>
       
    76  * In the shut down phase the life cycle will firstly inform Java Captain that
       
    77  * it is about to start the shut down procedures. If anything should fail in
       
    78  * shut down procedure, it is a responsibility of the Java Captain to terminate
       
    79  * the MIDP process. The MIDP runtime tries to close gracefully the JVM, but
       
    80  * that will fail if any of the started Java threads dont stop as a result of
       
    81  * shut down notifications. That is considered a failure in the shut down phase
       
    82  * and the Java Captain will terminate forcefully the process.
       
    83  *
       
    84  * @author Nokia Corporation
       
    85  * @version $Rev$
       
    86  */
       
    87 final class MidletLifeCycle
       
    88 {
       
    89     /**
       
    90      * Possible states of the state machine
       
    91      */
       
    92     private static final int STARTING_INIT   = 0x1;
       
    93     private static final int PRE_INIT_DONE   = 0x2;
       
    94     private static final int POST_INIT_DONE  = 0x4;
       
    95     private static final int STARTING_MIDLET = 0x8;
       
    96     private static final int RUNNING         = 0x10;
       
    97     private static final int PAUSED          = 0x20;
       
    98     private static final int STOPPING_MIDLET = 0x40;
       
    99     private static final int CLOSED          = 0x80;
       
   100     private static final int RESUMING        = 0x100;
       
   101 
       
   102     /**
       
   103      * A singleton instance of the life cycle. It is singleton for provoding
       
   104      * easy access to all other classes of the MIDP runtime.
       
   105      */
       
   106     private static MidletLifeCycle       mInstance = new MidletLifeCycle();
       
   107 
       
   108     /**
       
   109      * Timers for ensuring that correct actions are done if MIDlet doesn't
       
   110      * return from destroyApp().
       
   111      */
       
   112     private        Timer                 mTimer;
       
   113     private        ShutDownTimerTask     mShutDownTimerTask;
       
   114 
       
   115     /**
       
   116      * Arguments recived from native starter.
       
   117      */
       
   118     private        MainArgs              mMainArgs;
       
   119 
       
   120     /**
       
   121      * The task queue of the life cycle.
       
   122      */
       
   123     private        TaskQueue             mTaskQueue;
       
   124 
       
   125     /**
       
   126      * The state of the state machine of the life cycle.
       
   127      */
       
   128     private        int                   mState;
       
   129 
       
   130     /**
       
   131      * A comms connection to Java Captain.
       
   132      */
       
   133     private        MidpComms             mMidpcomms;
       
   134 
       
   135     /**
       
   136      * The gate to the MIDlet. All the MIDP runtime specific actions from
       
   137      * and to MIDlet are done by using this object.
       
   138      */
       
   139     private        MidletApplicationBase mMidletApplication;
       
   140 
       
   141     /**
       
   142      * The UID of the MIDlet. Is not be available in pre-warm start.
       
   143      */
       
   144     private        Uid                   mMidletUid;
       
   145 
       
   146     /**
       
   147      * A pointer to native peer.
       
   148      */
       
   149     private        int                   mNativeRuntimeStarterHandle;
       
   150 
       
   151     /**
       
   152      * On error cases that require showing error dialogs an instace of
       
   153      * RuntimeErrorDialog will be created. Before starting shut down procedures
       
   154      * the life cycle will check if this contains a valid reference. On normal
       
   155      * case this is null, but if not then the dialog is prompted before
       
   156      * continuing shut down procedures.
       
   157      */
       
   158     private        RuntimeErrorDialog    mRuntimeErrDialog;
       
   159 
       
   160     /**
       
   161      * Flag for identifying if the life cycle should be started into pre-warmed
       
   162      * state.
       
   163      */
       
   164     private        boolean               mPrewarmStart = false;
       
   165     /**
       
   166      * Flag for identifying whether the MIDlet should be started to background.
       
   167      */
       
   168     private        boolean               mBackGroundStart = false;
       
   169 
       
   170     /**
       
   171      * How many times MIDlet has been 're-started'
       
   172      */
       
   173     private        int                   mRelaunchCount = 0;
       
   174 
       
   175     /**
       
   176      * This is set to true if the MIDlet is started with url and
       
   177      * the url contains MIDlet argument 'PromptAppStartup'
       
   178      */
       
   179     private        boolean               mAutoinvocationFromUrl = false;
       
   180 
       
   181     /**
       
   182      * Flag for identifying whether the MIDlet is a standalone MIDlet.
       
   183      */
       
   184     private        boolean               mStandAlone = false;
       
   185 
       
   186     /*** ----------------------------- PRIVATE ---------------------------- */
       
   187 
       
   188 
       
   189     /**
       
   190      * The constructor of the MidletLifeCycle.
       
   191      */
       
   192     private MidletLifeCycle()
       
   193     {
       
   194         mState = STARTING_INIT;
       
   195     }
       
   196 
       
   197     /*** ----------------------------- PACKAGE ---------------------------- */
       
   198 
       
   199     /**
       
   200      * Will return a singleton instance of the life cycle.
       
   201      * @return a singleton instance of the life cycle.
       
   202      */
       
   203     static MidletLifeCycle getInstance()
       
   204     {
       
   205         return mInstance;
       
   206     }
       
   207 
       
   208     /**
       
   209      * Can be used for ensuring that important cleanings has been done if some
       
   210      * exception has occured during the shut down procedures. It also destroys
       
   211      * the singelton instance of the life cycle.
       
   212      */
       
   213     static void destroyInstance()
       
   214     {
       
   215         if (mInstance != null)
       
   216         {
       
   217             // Ensure that DRM rights are consumed when the MIDlet is
       
   218             // closed.
       
   219             DrmUtil.consumeRightsStop();
       
   220 
       
   221             if (mInstance.mState != CLOSED)
       
   222             {
       
   223                 _closeInd(mInstance.mNativeRuntimeStarterHandle);
       
   224             }
       
   225             if (mInstance.mMidpcomms != null)
       
   226             {
       
   227                 mInstance.mMidpcomms.close();
       
   228             }
       
   229 
       
   230             mInstance = null;
       
   231         }
       
   232     }
       
   233 
       
   234     /**
       
   235      * Entry point for starting the life cycle.
       
   236      * @param args The arguments provided to MIDP runtime.
       
   237      */
       
   238     void doRun(String[] args)
       
   239     {
       
   240         // Parse given args.
       
   241         mMainArgs = new MainArgs(args);
       
   242 
       
   243         // Make intializations that can be done without knowing the MIDlet to
       
   244         // be launched.
       
   245         doPreInit();
       
   246         startStateMachine();
       
   247 
       
   248         DrmUtil.consumeRightsStop();
       
   249 
       
   250         if (mRuntimeErrDialog != null)
       
   251         {
       
   252             mRuntimeErrDialog.showDialog();
       
   253         }
       
   254         if (Log.mOn) Log.logI("Sending close indication to runtime starter.");
       
   255         _closeInd(mNativeRuntimeStarterHandle);
       
   256 
       
   257         if (Log.mOn) Log.logI("Sending shutdown notifications to listeners.");
       
   258         ApplicationUtilsImpl.doShutdownImpl();
       
   259 
       
   260         if (!mStandAlone)
       
   261         {
       
   262             if (Log.mOn) Log.logI("Sending termination indication to Captain.");
       
   263             mMidpcomms.sendTerminatedIndication(0);
       
   264 
       
   265             if (Log.mOn) Log.logI("Closing COMMS.");
       
   266             mMidpcomms.close();
       
   267             mMidpcomms = null;
       
   268         }
       
   269 
       
   270         if (Log.mOn) Log.logI("Short pause before closing dispatchers.");
       
   271         try
       
   272         {
       
   273             Thread.sleep(200);
       
   274         }
       
   275         catch (Exception e)
       
   276         {
       
   277         }
       
   278 
       
   279         if (Log.mOn) Log.logI("Closing dispatchers.");
       
   280         LegacySupport.close();
       
   281 
       
   282         // Setting state to closed.
       
   283         mState = CLOSED;
       
   284     }
       
   285 
       
   286     /**
       
   287      * For setting the MidletApplication. This is set by the constructor of
       
   288      * the MidletApplicationBase clase during the construction of the MIDlet
       
   289      * class. See description of the MidletApplicationBase and the
       
   290      * mMidletApplication.
       
   291      * @param midletApplication The MidletApplication to be set.
       
   292      */
       
   293     void setMidletApplication(MidletApplicationBase midletApplication)
       
   294     {
       
   295         mMidletApplication = midletApplication;
       
   296     }
       
   297 
       
   298     /**
       
   299      * For getting the MidletApplication. See description of the
       
   300      * MidletApplicationBase and the mMidletApplication.
       
   301      * @return The MidletApplication.
       
   302      */
       
   303     MidletApplicationBase getMidletApplication()
       
   304     {
       
   305         return mMidletApplication;
       
   306     }
       
   307 
       
   308     /**
       
   309      * For notifying that MIDlet is entering into destroyed state. The
       
   310      * originator of this call is the MIDlet itself.
       
   311      */
       
   312     void notifyDestroyed()
       
   313     {
       
   314         if (Log.mOn) Log.logI("notifyDestroyed() called.");
       
   315         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.STOP_REQUEST,
       
   316                                              LifeCycleTask.APP_STOP_REQUEST));
       
   317     }
       
   318 
       
   319     /**
       
   320      * For notifying that MIDlet is entering into paused state. The
       
   321      * originator of this call is the MIDlet itself.
       
   322      */
       
   323     void notifyPaused()
       
   324     {
       
   325         if (Log.mOn) Log.logI("Pause notification from MIDlet received.");
       
   326         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.PAUSE_REQUEST));
       
   327     }
       
   328 
       
   329     /**
       
   330      * For notifying the MIDlet that something int the device has happened
       
   331      * that would require MIDlet to enter into   entering into actice state from paused
       
   332      * state. The originator of this call is the MIDlet itself or the user
       
   333      * of the ApplicationUtils.resumeApplication method of the Runtime support
       
   334      */
       
   335     void pauseApplication()
       
   336     {
       
   337         if (Log.mOn) Log.logI("Pause application request received.");
       
   338         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.PAUSE_APP_REQUEST));
       
   339     }
       
   340 
       
   341     /**
       
   342      * For notifying that MIDlet is entering into actice state from paused
       
   343      * state. The originator of this call is the MIDlet itself or the user
       
   344      * of the ApplicationUtils.resumeApplication method of the Runtime support.
       
   345      */
       
   346     void resumeRequest()
       
   347     {
       
   348         if (Log.mOn) Log.logI("Resume request received.");
       
   349         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.RESUME_REQUEST));
       
   350     }
       
   351 
       
   352     /**
       
   353      * For handling the start request received from the Java Captain. There are
       
   354      * two use cases when this could happen:
       
   355      *   - The MIDP runtime was in pre-warmed state and received a start cmd.
       
   356      *   - The MIDlet is already running and user "re-starts" the MIDlet.
       
   357      */
       
   358     void launchMidletRequest(Uid uid, boolean backGroundStart, String applicationArgs)
       
   359     {
       
   360         if (Log.mOn) Log.logI("Request for launching MIDlet received.");
       
   361         // Store the info whether MIDlet should be started to back ground.
       
   362         mBackGroundStart = backGroundStart;
       
   363 
       
   364         // Update relaunch count if really relaunching (not when activating
       
   365         // prewarmed MIDlet)
       
   366         if (mState != PRE_INIT_DONE)
       
   367         {
       
   368             mRelaunchCount++;
       
   369         }
       
   370         JvmInternal.setSystemProperty("com.nokia.mid.cmdline.instance",
       
   371                                       Integer.toString(mRelaunchCount + 1));
       
   372         if (Log.mOn)
       
   373             Log.logI("MIDlet launch count is : " + Integer.toString(mRelaunchCount + 1));
       
   374 
       
   375         // Update possible MIDlet arguments
       
   376         setMidletArguments(applicationArgs);
       
   377 
       
   378         if (mState == PRE_INIT_DONE)
       
   379         {
       
   380             // We were waiting in prewarmed state the launch request
       
   381             // and now got it.
       
   382             StartUpTrace.doTrace("Start request in pre-warm state received.");
       
   383             mMidletUid = uid;
       
   384             mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.START_REQUEST,
       
   385                                                  LifeCycleTask.PRE_WARM_START));
       
   386         }
       
   387         else
       
   388         {
       
   389             // Bring the MIDlet to foreground
       
   390             CoreUi.foregroundRequest();
       
   391         }
       
   392     }
       
   393 
       
   394     /**
       
   395      * For handling the terminate request originated by the system. There are
       
   396      * two sources for entering into this method - Java Captain sends a message
       
   397      * to the MIDP runtime that the MIDlet should be closed. In that case the
       
   398      * Captain has already a timer running for failures in shut down
       
   399      * procedures. In that case the internal timer won't be started.
       
   400      * The second option is that some one has called notifyExitCmd() of the
       
   401      * Runtime Support APIs. In that case a timer will be started to ensure
       
   402      * the shut down also in case the MIDlet doesn't return from the
       
   403      * destroyApp() call.
       
   404      * @param useTimer Info whether to start the interna timer for ensuring
       
   405      *                  proper shut down.
       
   406      */
       
   407     void terminateMidletRequest(boolean useTimer)
       
   408     {
       
   409         Log.logP("Request for terminating MIDlet " + mMidletUid +
       
   410                  "  received.");
       
   411         if (Log.mOn) Log.logI("  Internal timer used: " + useTimer);
       
   412         if (mState != STOPPING_MIDLET && mState != CLOSED)
       
   413         {
       
   414             if (useTimer)
       
   415             {
       
   416                 startShutDownTimer();
       
   417             }
       
   418             mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.STOP_REQUEST,
       
   419                                                  LifeCycleTask.SYSTEM_STOP_REQUEST));
       
   420         }
       
   421         else
       
   422         {
       
   423             if (Log.mOn) Log.logI("  Already doing shutdown.");
       
   424         }
       
   425     }
       
   426 
       
   427     /**
       
   428      * For notifying that the MIDletInvoker has succesfully returned from
       
   429      * startApp() call of the MIDlet.
       
   430      */
       
   431     void midletStarted()
       
   432     {
       
   433         if (Log.mOn) Log.logI("MIDlet started indication received.");
       
   434         mTaskQueue.addTask(
       
   435             new LifeCycleTask(LifeCycleTask.MIDLET_RUNNING_IND));
       
   436     }
       
   437 
       
   438     /**
       
   439      * For notifying that the MIDletInvoker has succesfully returned from
       
   440      * startApp() call of the MIDlet as a result of resumeRequest.
       
   441      */
       
   442     void midletResumed(boolean ok)
       
   443     {
       
   444         if (Log.mOn) Log.logI("MIDlet resumed indication received. " + ok);
       
   445         if (ok)
       
   446         {
       
   447             mTaskQueue.addTask(
       
   448                 new LifeCycleTask(LifeCycleTask.MIDLET_RUNNING_IND));
       
   449         }
       
   450     }
       
   451 
       
   452     /**
       
   453      * For notifying that the MIDletInvoker has succesfully returned from
       
   454      * destroyApp() call.
       
   455      */
       
   456     void midletDestroyed()
       
   457     {
       
   458         Log.logP("MIDlet " + mMidletUid + " has been destroyed.");
       
   459         if (Log.mOn) Log.logI("MIDlet destroyed indication received.");
       
   460         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.STOPPED_IND));
       
   461     }
       
   462 
       
   463     /**
       
   464      * For notifying that an exception has occured during the MIDlet start.
       
   465      * @param th The throwable that was catched during the start.
       
   466      */
       
   467     void handleMidletStartUpFailure(Throwable th)
       
   468     {
       
   469         Log.logE("Failed to start MIDlet! ", th);
       
   470         mRuntimeErrDialog = RuntimeErrorDialog.getStartUpErrorDialog(th);
       
   471         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.STARTUP_FAILURE));
       
   472     }
       
   473 
       
   474     /**
       
   475      * For notifying that an exception has occured during pausing the MIDlet.
       
   476      * The MIDlet will be destroyed.
       
   477      */
       
   478     void handleMidletPauseAppFailure()
       
   479     {
       
   480         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.PAUSE_FAILURE));
       
   481     }
       
   482 
       
   483     /**
       
   484      * For notifying that some thread didn't catch a throwable.
       
   485      * @param th The throwable that some thread didn't catch.
       
   486      */
       
   487     void handleUncaughtException(Throwable th)
       
   488     {
       
   489         Log.logE("Uncaught exception! ", th);
       
   490         mRuntimeErrDialog = RuntimeErrorDialog.getUnhandledDialog(th);
       
   491         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.UNCAUGHT_EXCEPTION));
       
   492     }
       
   493 
       
   494     /**
       
   495      * A getter for info whether the MIDlet should be started into background.
       
   496      * @return true if application should be started into back ground, false
       
   497      *         otherwise.
       
   498      */
       
   499     boolean isBackGroundStart()
       
   500     {
       
   501         // If the background flag has already been set by starter just return
       
   502         // If not then we need to check if the user has been set the UI into
       
   503         // background before the UI toolkit has been activated.
       
   504         if (!mBackGroundStart)
       
   505         {
       
   506             mBackGroundStart = !CoreUi.isUiInForeground();
       
   507         }
       
   508         return mBackGroundStart;
       
   509     }
       
   510 
       
   511 
       
   512     /*** ----------------------------- PRIVATE ---------------------------- */
       
   513 
       
   514     /**
       
   515      * For starting the state machine of the life cycle
       
   516      */
       
   517     private void startStateMachine()
       
   518     {
       
   519         if (Log.mOn) Log.logI("Entering main loop.");
       
   520 
       
   521         if (mPrewarmStart)
       
   522         {
       
   523             _restoreNormalProcessPriority();
       
   524             int shrinkSize = JvmInternal.shrinkJavaHeapToMinimum();
       
   525             StartUpTrace.doTrace("Heap shrunk by " + shrinkSize + " bytes.");
       
   526             if (Log.mOn) Log.logI("Heap shrunk by " + shrinkSize + " bytes.");
       
   527         }
       
   528         boolean loop = true;
       
   529         while (loop)
       
   530         {
       
   531             LifeCycleTask task = (LifeCycleTask)mTaskQueue.getTask();
       
   532             int mainTask = task.getMainTask();
       
   533             int subTask = task.getSubTask();
       
   534 
       
   535             switch (mainTask)
       
   536             {
       
   537                 // Start request. Originator is Java Captain.
       
   538             case LifeCycleTask.START_REQUEST:
       
   539                 handleStartRequest(subTask);
       
   540                 break;
       
   541 
       
   542                 // Running indication. Originator is MidletInvoker.
       
   543             case LifeCycleTask.MIDLET_RUNNING_IND:
       
   544                 if (Log.mOn) Log.logI("LOOP: Handling MIDLET_RUNNING_IND.");
       
   545                 mState = RUNNING;
       
   546                 break;
       
   547 
       
   548                 // Stop request. Originator is either Java Captain,
       
   549                 // Runtime Support API caller or shut down timer..
       
   550             case LifeCycleTask.STOP_REQUEST:
       
   551                 loop = handleStopRequest(subTask);
       
   552                 break;
       
   553 
       
   554                 // Stopped indication. Originator is MidletInvoker.
       
   555             case LifeCycleTask.STOPPED_IND:
       
   556                 if (Log.mOn) Log.logI("LOOP: Handling STOPPED_IND.");
       
   557                 cancelShutDownTimer();
       
   558                 loop = false;
       
   559                 break;
       
   560 
       
   561                 // Pause request. Originator is MIDlet.
       
   562             case LifeCycleTask.PAUSE_REQUEST:
       
   563                 handlePauseRequest();
       
   564                 break;
       
   565 
       
   566                 // Pause application request. Originator is MIDlet or the user
       
   567                 // of the ApplicationUtils.pauseApplication method of the
       
   568                 // Runtime support. This leads to call of MIDlet.pauseApp().
       
   569             case LifeCycleTask.PAUSE_APP_REQUEST:
       
   570                 handlePauseAppRequest();
       
   571                 break;
       
   572 
       
   573                 // Resume request. Originator is MIDlet or the user
       
   574                 // of the ApplicationUtils.resumeApplication method of the
       
   575                 // Runtime support.
       
   576             case LifeCycleTask.RESUME_REQUEST:
       
   577                 handleResumeRequest();
       
   578                 break;
       
   579 
       
   580                 // Error in startApp request. Originator is MidletInvoker.
       
   581             case LifeCycleTask.STARTUP_FAILURE:
       
   582                 // Error in pauseApp request. Originator is MidletInvoker.
       
   583             case LifeCycleTask.PAUSE_FAILURE:
       
   584                 MidletInvoker.stopMidlet();
       
   585                 loop = false;
       
   586                 break;
       
   587 
       
   588             case LifeCycleTask.UNCAUGHT_EXCEPTION:
       
   589                 // Midlet will be immediately destroyd without calling
       
   590                 // destroyApp().
       
   591                 loop = false;
       
   592                 break;
       
   593             default:
       
   594                 Log.logE("LOOP: Unknown task: " + mainTask);
       
   595                 break;
       
   596             }
       
   597         }
       
   598         mState = CLOSED;
       
   599         if (Log.mOn) Log.logI("Leaving main loop.");
       
   600     }
       
   601 
       
   602     /**
       
   603      * Handles the start request task. Allowed to be called only from
       
   604      * startStateMachine() method. The only intention of this method is
       
   605      * to diminish the switch case clause in the diminish startStateMachine()
       
   606      * method.
       
   607      * @param subTask The sub task provided by the task setter.
       
   608      */
       
   609     private void handleStartRequest(int subTask)
       
   610     {
       
   611         if (Log.mOn) Log.logI("MidletLifeCycle.handleStartRequest(), subTask: "
       
   612                                   + subTask);
       
   613         if (mState == POST_INIT_DONE || (mState == PRE_INIT_DONE &&
       
   614                                          subTask == LifeCycleTask.PRE_WARM_START))
       
   615         {
       
   616             if (subTask == LifeCycleTask.NORMAL_START)
       
   617             {
       
   618                 if (Log.mOn) Log.logI("  Normal start");
       
   619                 mState = STARTING_MIDLET;
       
   620                 MidletInvoker.startMidlet();
       
   621             }
       
   622             else if (subTask == LifeCycleTask.PRE_WARM_START)
       
   623             {
       
   624                 if (Log.mOn) Log.logI("  Pre-warm start");
       
   625                 doPreWarmInit();
       
   626             }
       
   627         }
       
   628         else
       
   629         {
       
   630             if (Log.mOn) Log.logI("  No start, since the state was incorrect: "
       
   631                                       + mState);
       
   632         }
       
   633     }
       
   634 
       
   635     /**
       
   636      * Handles the stop request task. Allowed to be called only from
       
   637      * startStateMachine() method. The only intention of this method is
       
   638      * to diminish the switch case clause in the startStateMachine()
       
   639      * method.
       
   640      * @param subTask The sub task provided by the task setter.
       
   641      * @return true if the task listening should continue, false otherwise.
       
   642      */
       
   643     private boolean handleStopRequest(int subTask)
       
   644     {
       
   645         if (Log.mOn) Log.logI("MidletLifeCycle.handleStopRequest(), subTask: "
       
   646                                   + subTask);
       
   647         mState = STOPPING_MIDLET;
       
   648         boolean loop = true;
       
   649         if (subTask == LifeCycleTask.APP_STOP_REQUEST)
       
   650         {
       
   651             if (Log.mOn) Log.logI("  Request from app -> no destroyApp call.");
       
   652             loop = false;
       
   653         }
       
   654         else if (subTask == LifeCycleTask.SYSTEM_STOP_REQUEST)
       
   655         {
       
   656             if (Log.mOn) Log.logI("  Request from system -> call destroyApp.");
       
   657             MidletInvoker.stopMidlet();
       
   658         }
       
   659         else if (subTask == LifeCycleTask.DO_FORCED_TERMINATE)
       
   660         {
       
   661             if (Log.mOn) Log.logI("  Doing forceful termination.");
       
   662             loop = false;
       
   663         }
       
   664         return loop;
       
   665     }
       
   666 
       
   667     /**
       
   668      * Handles the pause request task. Allowed to be called only from
       
   669      * startStateMachine() method. The only intention of this method is
       
   670      * to diminish the switch case clause in the startStateMachine()
       
   671      * method. This is called when the MIDlet itself wants to go to
       
   672      * paused state.
       
   673      */
       
   674     private void handlePauseRequest()
       
   675     {
       
   676         if (Log.mOn) Log.logI("MidletLifeCycle.handlePauseRequest()");
       
   677         if (mState != RUNNING)
       
   678         {
       
   679             Log.logW("Pause request received in illegal state: " + mState);
       
   680         }
       
   681         mState = PAUSED;
       
   682     }
       
   683 
       
   684     /**
       
   685      * Handles the pause app request task. Allowed to be called only from
       
   686      * startStateMachine() method. The only intention of this method is
       
   687      * to diminish the switch case clause in the startStateMachine()
       
   688      * method. This is called when the System wants the MIDlet change to
       
   689      * paused state.
       
   690      */
       
   691     private void handlePauseAppRequest()
       
   692     {
       
   693         if (Log.mOn) Log.logI("MidletLifeCycle.handlePauseAppRequest()");
       
   694         if (mState != RUNNING)
       
   695         {
       
   696             Log.logW("Pause request received in illegal state: " + mState);
       
   697         }
       
   698         MidletInvoker.pauseMidlet();
       
   699         mState = PAUSED;
       
   700     }
       
   701 
       
   702 
       
   703 
       
   704     /**
       
   705      * Handles the resume request task. Allowed to be called only from
       
   706      * startStateMachine() method. The only intention of this method is
       
   707      * to diminish the switch case clause in the startStateMachine()
       
   708      * method.
       
   709      */
       
   710     private void handleResumeRequest()
       
   711     {
       
   712         if (Log.mOn) Log.logI("MidletLifeCycle.handleResumeRequest()");
       
   713         if (mState == PAUSED)
       
   714         {
       
   715             mState = STARTING_MIDLET;
       
   716             MidletInvoker.resumeMidlet();
       
   717         }
       
   718         else
       
   719         {
       
   720             Log.logW("Resume request received in illegal state: " + mState);
       
   721         }
       
   722     }
       
   723 
       
   724     /**
       
   725      * For informing the JVM about the protected and restricted packages.
       
   726      */
       
   727     private void setClassProtection()
       
   728     {
       
   729         if (Log.mOn) Log.logI("Setting protected classes.");
       
   730         PackageProtector protector = PackageProtector.getInstance();
       
   731         JvmInternal.addProtectedPackagePrefixes(
       
   732             protector.getProtectedPackageNames());
       
   733         JvmInternal.addRestrictedPackagePrefixes(
       
   734             protector.getRestrictedPackageNames());
       
   735     }
       
   736 
       
   737     /**
       
   738      * For doing the initializations that can be done before knowing the UID
       
   739      * of the MIDlet
       
   740      */
       
   741     private void doPreInit()
       
   742     {
       
   743         if (Log.mOn) Log.logI("Doing pre init.");
       
   744 
       
   745         // Load the native.
       
   746         Jvm.loadSystemLibrary("javamidpruntime");
       
   747 
       
   748         // Start to monitor uncaught exceptions.
       
   749         JvmInternal.setThreadEventListener(new ThreadEventListener()
       
   750         {
       
   751             public void threadStarting(Thread newThread, Thread parentThread)
       
   752             {
       
   753                 if (Log.mOn) Log.logI("threadStarting newThread:" + newThread
       
   754                                           + ", parentThread:"+parentThread);
       
   755             }
       
   756             public void threadDied(Thread thread)
       
   757             {
       
   758                 if (Log.mOn) Log.logI("threadDied thread:"+thread);
       
   759             }
       
   760             public void uncaughtException(Thread thread, Throwable throwable)
       
   761             {
       
   762                 handleUncaughtException(throwable);
       
   763             }
       
   764         });
       
   765 
       
   766         // Store the starter handle for native access.
       
   767         mNativeRuntimeStarterHandle =
       
   768             Integer.parseInt(mMainArgs.findArgument("-handle"));
       
   769 
       
   770         mStandAlone = mMainArgs.findArgument("-standalone") != null;
       
   771         if (Log.mOn) Log.logI("Is standalone MIDlet = " + mStandAlone);
       
   772 
       
   773         if (!mStandAlone)
       
   774         {
       
   775             // Do not allow System.exit().
       
   776             JvmInternal.disableRuntimeExit();
       
   777 
       
   778             // Set protected and restricted packages.
       
   779             setClassProtection();
       
   780 
       
   781             // Check if there are add-on JSRs.
       
   782             ExtensionUtil.handleExtensions();
       
   783         }
       
   784 
       
   785         mTaskQueue = new TaskQueue();
       
   786 
       
   787         // If system property com.nokia.mid.cmdline has value, it contains
       
   788         // the arguments for the current MIDlet.
       
   789         String encodedMidletArgs = System.getProperty("com.nokia.mid.cmdline");
       
   790         if ((encodedMidletArgs != null) && (encodedMidletArgs.length() > 0))
       
   791         {
       
   792             // Decode arguments
       
   793             String midletArgs = decodeArgs(encodedMidletArgs);
       
   794 
       
   795             // Parse them
       
   796             setMidletArguments(midletArgs);
       
   797         }
       
   798 
       
   799         // If the runtime is set to pre warmed state, then the
       
   800         // value of the prewarm flag contans the process id which
       
   801         // is needed by Captain for identification.
       
   802         String pid = mMainArgs.findArgument("-prewarm");
       
   803         mPrewarmStart = pid != null;
       
   804         mState = PRE_INIT_DONE;
       
   805         if (!mPrewarmStart)
       
   806         {
       
   807             // We know the MIDlet to be launched, so post init can be done.
       
   808             mMidletUid = Uid.createUid(mMainArgs.findArgument("-uid"));
       
   809             if (!CoreUi.connectToUi())
       
   810             {
       
   811                 // If not in prewarmed state we need to connect
       
   812                 // to core UI. If the core Ui is closed, then
       
   813                 // don't continue the start up.
       
   814                 if (Log.mOn) Log.logI("CoreUi was closed - so no start.");
       
   815                 throw new StartupException("Core UI closed.",false);
       
   816             }
       
   817             // Cache the info if the intention is to start the MIDlet into
       
   818             // background.
       
   819             mBackGroundStart = mMainArgs.findArgument("-background") != null;
       
   820 
       
   821             doPostInit();
       
   822 
       
   823             if (!mStandAlone)
       
   824             {
       
   825                 // Create a comms connection to Java Captain.
       
   826                 mMidpcomms = new MidpComms(mMidletUid);
       
   827 
       
   828                 // Send running indication with success status.
       
   829                 mMidpcomms.sendRunningIndication(0);
       
   830             }
       
   831         }
       
   832         else
       
   833         {
       
   834             // Create a comms connection to Java Captain.
       
   835             mMidpcomms = new MidpComms();
       
   836 
       
   837             // Send running indication. Send the pid to Captain for
       
   838             //identification.
       
   839             mMidpcomms.sendProcessRunningIndication(Integer.parseInt(pid));
       
   840             wakeUpUi();
       
   841         }
       
   842     }
       
   843 
       
   844     /**
       
   845      * Decode string in a private format that was safe to pass to Java side
       
   846      * as a Java system property.
       
   847      * Native side function java::util::runtime::MidpRuntimeStarter::encodeArgs()
       
   848      * was used to encode the string
       
   849      *
       
   850      * @param args original wstring
       
   851      * @return encoded wstring
       
   852      */
       
   853     private String decodeArgs(String encodedArgs)
       
   854     {
       
   855         StringBuffer res = new StringBuffer();
       
   856         int idx = encodedArgs.indexOf('%');
       
   857         int cur = 0;
       
   858 
       
   859         while (idx != -1)
       
   860         {
       
   861             // Add all characters up to but not including the '%' char
       
   862             // to final result string
       
   863             if ((idx - cur) > 0)
       
   864             {
       
   865                 res.append(encodedArgs.substring(cur, idx));
       
   866             }
       
   867 
       
   868             // Decode all special sequences 'X%' in same way.
       
   869             // "X%" -> "X", so skip "%"
       
   870             // Note that "%%" is decoded to "%"
       
   871             cur = idx + 1;
       
   872             idx = encodedArgs.indexOf('%', cur + 1);
       
   873         }
       
   874 
       
   875         // Add characters after last special character if any
       
   876         res.append(encodedArgs.substring(cur, encodedArgs.length()));
       
   877 
       
   878         return res.toString();
       
   879     }
       
   880 
       
   881     /**
       
   882      * This method is meant for informing the UI that the MIDP runtime has
       
   883      * entered into pre-warmed state. The method simply tries to instatiate
       
   884      * a class provided by a specified system property. In the constructor
       
   885      * of the object the UI may start the pre warming steps.
       
   886      */
       
   887     private void wakeUpUi()
       
   888     {
       
   889         // Get the class name.
       
   890         String className = System.getProperty("com.nokia.mj.impl.ui");
       
   891         if (className != null)
       
   892         {
       
   893             // If the property is set, instantiate the class.
       
   894             try
       
   895             {
       
   896                 Class clazz = Class.forName(className);
       
   897                 clazz.newInstance();
       
   898             }
       
   899             catch (Throwable t)
       
   900             {
       
   901                 // Silently ignore exceptions.
       
   902             }
       
   903         }
       
   904     }
       
   905 
       
   906     /**
       
   907      * This method does the necessary initializations after leaving the pre-
       
   908      * warmed state. When calling this method, the MIDlet UID must be known.
       
   909      * Heap size is not set.
       
   910      */
       
   911     private void doPreWarmInit()
       
   912     {
       
   913         if (Log.mOn) Log.logI("Doing prewarm init.");
       
   914 
       
   915         doPostInit();
       
   916 
       
   917         // The native peer doesn't know the UID of the started MIDlet.
       
   918         // Informing native.
       
   919         _setUids(mMidletUid.toString(),
       
   920                  ApplicationInfoImpl.getMidletInfo().getSuiteUid().toString(),
       
   921                  mNativeRuntimeStarterHandle);
       
   922         // The Jvm doesn't know about MIDlet class path - need to set it.
       
   923         String classPath = ApplicationInfoImpl.getMidletInfo().getClassPath();
       
   924         if (Log.mOn) Log.logI("  Adding to classpath: "+classPath);
       
   925         JvmInternal.appendToClassPath(classPath);
       
   926     }
       
   927 
       
   928     private void doPostInit()
       
   929     {
       
   930         if (Log.mOn) Log.logI("Doing post init.");
       
   931 
       
   932         // Set the MidletInfo class to contain correct data. The data is read
       
   933         // from storage.
       
   934         setMidletInfo();
       
   935 
       
   936         if (mPrewarmStart)
       
   937         {
       
   938             // Get the recorded heap size from previous run.
       
   939             int targetHeapSize = MemoryLogger.getOldHeapSizeToExpand();
       
   940 
       
   941             int expandedSize = JvmInternal.expandJavaHeap(targetHeapSize);
       
   942             StartUpTrace.doTrace("Heap expand req:"+ targetHeapSize +" B. Result: "+ expandedSize + " B.");
       
   943             // Do the post init actions.
       
   944             // In case of pre-warm start we need to create the core ui
       
   945             // from Java side. In order to ensure that Runtime Support
       
   946             // API works ok, the setMidletInfo must be called before
       
   947             // starting the UI.
       
   948             CoreUi.createUi(mMidletUid, mBackGroundStart);
       
   949         }
       
   950         if (!mStandAlone)
       
   951         {
       
   952 
       
   953             // Do the MIDlet suite authentication.
       
   954             verifyMIDletSuiteAuthenticity();
       
   955 
       
   956             // Inform the DRM util that the MIDlet is about to start.
       
   957             DrmUtil.consumeRightsStart();
       
   958         }
       
   959 
       
   960         // If the MIDlet launch is a result of auto invocation we need to
       
   961         // ensure that user allows the start up.
       
   962         if ((mMainArgs.findArgument("-autoinvocation") != null) ||
       
   963                 mAutoinvocationFromUrl)
       
   964         {
       
   965             try
       
   966             {
       
   967                 if (Log.mOn) Log.logI("Ensuring autoinvocation.");
       
   968                 String pushAdditionalInfo =
       
   969                     mMainArgs.findArgument("-autoInvocationAdditional");
       
   970                 if (Log.mOn) Log.logI("  addInfo: '" + pushAdditionalInfo + "'");
       
   971                 PushSecurityUtils.ensurePermission("autoinvocation",
       
   972                                                    pushAdditionalInfo);
       
   973 
       
   974                 if (Log.mOn) Log.logI("Autoinvocation allowed.");
       
   975             }
       
   976             catch (SecurityException se)
       
   977             {
       
   978                 // The user didn't allow starting. Throw StartupException and
       
   979                 // mark it as non fatal.
       
   980                 if (Log.mOn) Log.logI("Autoinvocation NOT allowed.");
       
   981                 throw new StartupException("Auto invocation not allowed.",
       
   982                                            false);
       
   983             }
       
   984         }
       
   985 
       
   986         // Initialize the legacy support layer if exists.
       
   987         LegacySupport.init(
       
   988             ApplicationInfoImpl.getMidletInfo().getMidletAttributes(),
       
   989             isBackGroundStart());
       
   990 
       
   991         mState = POST_INIT_DONE;
       
   992 
       
   993         // All the initializations done now, ready to start the MIDlet.
       
   994         mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.START_REQUEST,
       
   995                                              LifeCycleTask.NORMAL_START));
       
   996 
       
   997         // If there are any waiters for the start up, release those.
       
   998         ApplicationUtilsImpl.releaseStartWaiterImpl(true);
       
   999     }
       
  1000 
       
  1001     /**
       
  1002      * Verifies the authenticity of MIDlet suite.
       
  1003      * @throws StartupException on error case.
       
  1004      */
       
  1005     private void verifyMIDletSuiteAuthenticity()
       
  1006     {
       
  1007         if (Log.mOn) Log.logI("Verifying MIDlet Suite authenticity.");
       
  1008         // Get instance of MidleInfo for getting arguments.
       
  1009         MidletInfo midletInfo = ApplicationInfoImpl.getMidletInfo();
       
  1010 
       
  1011         try
       
  1012         {
       
  1013             // Get instance of AuthenticationModule for doing the verification.
       
  1014             AuthenticationModule authenticationModule =
       
  1015                 AuthenticationModule.getInstance();
       
  1016 
       
  1017 
       
  1018             // Set a data object to conatin necessary info used during
       
  1019             // verificaton.
       
  1020             AuthenticationStorageData securityStorageData =
       
  1021                 new AuthenticationStorageData(
       
  1022                 midletInfo.getProtectionDomainName(),
       
  1023                 midletInfo.getProtectionDomain(),
       
  1024                 midletInfo.getMidletHash(),
       
  1025                 midletInfo.getRootHash(),
       
  1026                 midletInfo.getClassPath());
       
  1027             authenticationModule.verifyMIDletSuiteAuthenticity(
       
  1028                 midletInfo.getSuiteUid(),
       
  1029                 securityStorageData);
       
  1030         }
       
  1031         catch (RuntimeSecurityException rse)
       
  1032         {
       
  1033             // Display the error to user
       
  1034             RuntimeErrorDialog.showAuthenticationFailed(rse);
       
  1035             throw new StartupException("Suite authentication failed.");
       
  1036         }
       
  1037         if (Log.mOn) Log.logI("MIDlet Suite authenticity verified.");
       
  1038     }
       
  1039 
       
  1040     /**
       
  1041      * Sets the MIDlet info to contain the MIDlet data from Java Storage.
       
  1042      */
       
  1043     private void setMidletInfo()
       
  1044     {
       
  1045         if (Log.mOn) Log.logI("Setting MIDlet data.");
       
  1046         // Create MidletInfo instance for storing the ApplicationInfo for the
       
  1047         // runtime support.
       
  1048         MidletInfo midletInfo = new MidletInfo();
       
  1049         midletInfo.setUid(mMidletUid);
       
  1050 
       
  1051         if (!mStandAlone)
       
  1052         {
       
  1053 
       
  1054             // Read the "static" arguments. These are used for starting the MIDlet.
       
  1055             StorageAccessor.setMidletStartArguments(midletInfo);
       
  1056 
       
  1057             // Read the MIDlet attributes defined in the manifest and Jad (if
       
  1058             // present).
       
  1059             StorageAccessor.setMidletAttributes(midletInfo);
       
  1060 
       
  1061         }
       
  1062         else
       
  1063         {
       
  1064             // Read the MIDlet attributes defined in the manifest and Jad (if
       
  1065             // present).
       
  1066             SaMidletInfoProvider.setMidletAttributes(midletInfo, mMainArgs.findArgument("-jad"));
       
  1067 
       
  1068             // Read the "static" arguments. These are used for starting the MIDlet.
       
  1069             SaMidletInfoProvider.setMidletStartArguments(midletInfo);
       
  1070             // Set the root path of the MIDlet suite.
       
  1071             midletInfo.setRootPath(mMainArgs.findArgument("-rootpath"));
       
  1072         }
       
  1073         // ApplicationInfoImpl will store the MIDlet info.
       
  1074         ApplicationInfoImpl.setMidletInfo(midletInfo);
       
  1075         if (Log.mOn) Log.logI("MidletInfo: " + midletInfo);
       
  1076     }
       
  1077 
       
  1078     /**
       
  1079      * Starts the shut down timer if not yet started. The timer is for
       
  1080      * ensuring the proper shut down in a case where the MIDlet doesn't
       
  1081      * return from destroyApp() in given time. The time is 5 seconds.
       
  1082      */
       
  1083     private void startShutDownTimer()
       
  1084     {
       
  1085         if (Log.mOn) Log.logI("Starting shutdown timer.");
       
  1086         if (mTimer == null)
       
  1087         {
       
  1088             mTimer = new Timer();
       
  1089             mShutDownTimerTask = new ShutDownTimerTask();
       
  1090             mTimer.schedule(mShutDownTimerTask, 5000);
       
  1091         }
       
  1092         else
       
  1093         {
       
  1094             Log.logW("Shutdown timer already running");
       
  1095         }
       
  1096 
       
  1097     }
       
  1098 
       
  1099     /**
       
  1100      * Cancels the shut down timer.
       
  1101      */
       
  1102     private void cancelShutDownTimer()
       
  1103     {
       
  1104         if (Log.mOn) Log.logI("Cancelling shutdown timer.");
       
  1105         if (mTimer != null)
       
  1106         {
       
  1107             mTimer.cancel();
       
  1108             mTimer = null;
       
  1109             mShutDownTimerTask = null;
       
  1110         }
       
  1111     }
       
  1112 
       
  1113     /**
       
  1114      * Parse the MIDlet arguments given as parameter and set them
       
  1115      * to system properties so that MIDlet can access them.
       
  1116      *
       
  1117      * @param applicationArgs the MIDlet arguments, can be empty
       
  1118      */
       
  1119     private void setMidletArguments(String applicationArgs)
       
  1120     {
       
  1121         if (applicationArgs == null)
       
  1122         {
       
  1123             applicationArgs = "";
       
  1124         }
       
  1125         JvmInternal.setSystemProperty("com.nokia.mid.cmdline", applicationArgs);
       
  1126 
       
  1127         if (applicationArgs.length() > 0)
       
  1128         {
       
  1129             if (Log.mOn)
       
  1130                 Log.logI("MIDlet arguments are : " + applicationArgs);
       
  1131 
       
  1132             // parse args and set individual system properties
       
  1133             // e.g. "startMode=startFromCmdLine;sound=ON;wizard_mode;landscapeMode=true"
       
  1134             int idx;
       
  1135             int indEq;
       
  1136             int cur = 0;
       
  1137             StringBuffer argBuf = new StringBuffer();
       
  1138             String arg;
       
  1139             String propertyKey;
       
  1140             String propertyValue;
       
  1141             mAutoinvocationFromUrl = false;
       
  1142 
       
  1143             do
       
  1144             {
       
  1145                 argBuf.setLength(0);
       
  1146                 idx = applicationArgs.indexOf(";", cur);
       
  1147 
       
  1148                 if (idx == 0)
       
  1149                 {
       
  1150                     // Arguments string started with ';'
       
  1151                     cur = idx + 1;
       
  1152                     continue;
       
  1153                 }
       
  1154 
       
  1155                 argBuf.append("com.nokia.mid.cmdline.param.");
       
  1156                 if (idx != -1)
       
  1157                 {
       
  1158                     argBuf.append(applicationArgs.substring(cur, idx));
       
  1159                 }
       
  1160                 else
       
  1161                 {
       
  1162                     argBuf.append(applicationArgs.substring(cur));
       
  1163                 }
       
  1164 
       
  1165                 // split one arg to key and value
       
  1166                 arg = argBuf.toString();
       
  1167                 indEq = arg.indexOf('=');
       
  1168                 propertyKey = null;
       
  1169                 propertyValue = "";
       
  1170 
       
  1171                 if (indEq == -1)
       
  1172                 {
       
  1173                     // The property doesn't have a value.
       
  1174                     propertyKey = arg;
       
  1175                 }
       
  1176                 else
       
  1177                 {
       
  1178                     // The property has also a value.
       
  1179                     propertyKey = arg.substring(0, indEq);
       
  1180                     propertyValue = arg.substring(indEq + 1);
       
  1181                 }
       
  1182 
       
  1183                 if (propertyKey.equals("com.nokia.mid.cmdline.param.PromptAppStartup"))
       
  1184                 {
       
  1185                     mAutoinvocationFromUrl = true;
       
  1186                     if (Log.mOn)
       
  1187                         Log.logI("MIDlet had argument PromptAppStartup");
       
  1188                 }
       
  1189 
       
  1190                 JvmInternal.setSystemProperty(propertyKey, propertyValue);
       
  1191 
       
  1192                 cur = idx + 1;
       
  1193             }
       
  1194             while ((idx != -1) && (cur < applicationArgs.length()));
       
  1195         }
       
  1196     }
       
  1197 
       
  1198     /**
       
  1199      * Class for extending the TimerTask. This is for the shut down timer.
       
  1200      */
       
  1201     private class ShutDownTimerTask extends TimerTask
       
  1202     {
       
  1203         /**
       
  1204          * Method to be run if the shut down timer elapses.
       
  1205          */
       
  1206         public final void run()
       
  1207         {
       
  1208             try
       
  1209             {
       
  1210                 if (Log.mOn) Log.logI("TIMER elapsed, do forced shut down.");
       
  1211                 // Do a forceful shutdown.
       
  1212                 mTaskQueue.addTask(
       
  1213                     new LifeCycleTask(LifeCycleTask.STOP_REQUEST,
       
  1214                                       LifeCycleTask.DO_FORCED_TERMINATE));
       
  1215 
       
  1216             }
       
  1217             catch (Throwable t)
       
  1218             {
       
  1219                 Log.logE("Error in Timer! ", t);
       
  1220             }
       
  1221         }
       
  1222     }
       
  1223 
       
  1224     /*** ----------------------------- NATIVE ----------------------------- */
       
  1225 
       
  1226     /**
       
  1227      * For informing the native peer to know the UID of the MIDlet.
       
  1228      * When a MIDlet is started by using pre-warmed feature, the start message
       
  1229      * is received by the Java peer of the MIDP runtime. The native peer needs
       
  1230      * also to know the UID of the MIDlet.
       
  1231      * @param midletUid The UID of the MIDlet.
       
  1232      * @param midletSuiteUid The UID of the MIDlet suite.
       
  1233      * @param starterHandle A pointer to the native runtime peer.
       
  1234      */
       
  1235     private native void _setUids(String midletUid, String midletSuiteUid,
       
  1236                                  int starterHandle);
       
  1237 
       
  1238     /**
       
  1239      * Changes the process priority back to normal.
       
  1240      */
       
  1241     private native void _restoreNormalProcessPriority();
       
  1242 
       
  1243 
       
  1244     /**
       
  1245      * For informing the native peer that the life cycle has started the shut
       
  1246      * down procedures.
       
  1247      */
       
  1248     private static native void _closeInd(int starterHandle);
       
  1249 }