javaruntimes/midp/runtime/javasrc/com/nokia/mj/impl/rt/midp/MidletLifeCycle.java
branchRCL_3
changeset 19 04becd199f91
child 23 98ccebc37403
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javaruntimes/midp/runtime/javasrc/com/nokia/mj/impl/rt/midp/MidletLifeCycle.java	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,1249 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+package com.nokia.mj.impl.rt.midp;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.nokia.mj.impl.rt.utils.ExtensionUtil;
+
+import com.nokia.mj.impl.rt.support.Jvm;
+import com.nokia.mj.impl.rt.support.JvmInternal;
+import com.nokia.mj.impl.rt.support.ThreadEventListener;
+
+import com.nokia.mj.impl.rt.legacy.LegacySupport;
+
+import com.nokia.mj.impl.gcf.PushSecurityUtils;
+
+import com.nokia.mj.impl.security.packageprotection.PackageProtector;
+import com.nokia.mj.impl.security.common.RuntimeSecurityException;
+import com.nokia.mj.impl.security.midp.authentication.AuthenticationModule;
+import com.nokia.mj.impl.security.midp.storage.AuthenticationStorageData;
+
+import com.nokia.mj.impl.fileutils.FileUtility;
+
+import com.nokia.mj.impl.coreui.CoreUi;
+
+import com.nokia.mj.impl.utils.LineReader;
+import com.nokia.mj.impl.utils.TaskQueue;
+import com.nokia.mj.impl.utils.Uid;
+import com.nokia.mj.impl.utils.StartUpTrace;
+
+/**
+ * A core of the MIDP life cycle. This class controls the life time of the
+ * MIDlet.
+ * <p>
+ * The implementation of this class can be divided into three catgories:
+ *   -The initializing of the life cycle.
+ *   -The state machine.
+ *   -The shut down of the life cycle.
+ * <p>
+ * Initialization can be divided into three different phases. The pre init
+ * are the actions that can be done without knowing the MIDlet to be started.
+ * The pre init phase is done always - even when going into pre warm state.
+ * The last phase is the post actions which require knowing the MIDlet.
+ * The pre warm init is a special phase, which is done only when the MIDlet
+ * after firstly started into pre-warmed state. When the life cycle receves
+ * indication that the MIDlet should be started and receives the MIDlet UID,
+ * the life cycle will do first the pre-warm init phae and finally does the
+ * post initial phase.
+ * <p>
+ * The state machine is based on a simple FIFO style thread safe task queue.
+ * When the life cycle enters into state machine phase it starts wait for
+ * various tasks. It should be noted that in order to ensure thread safeness
+ * of the life cycle all most all actions should be done via sending a task
+ * queue. Once the state machine is exited a shut down phase begins.
+ * <p>
+ * In the shut down phase the life cycle will firstly inform Java Captain that
+ * it is about to start the shut down procedures. If anything should fail in
+ * shut down procedure, it is a responsibility of the Java Captain to terminate
+ * the MIDP process. The MIDP runtime tries to close gracefully the JVM, but
+ * that will fail if any of the started Java threads dont stop as a result of
+ * shut down notifications. That is considered a failure in the shut down phase
+ * and the Java Captain will terminate forcefully the process.
+ *
+ * @author Nokia Corporation
+ * @version $Rev$
+ */
+final class MidletLifeCycle
+{
+    /**
+     * Possible states of the state machine
+     */
+    private static final int STARTING_INIT   = 0x1;
+    private static final int PRE_INIT_DONE   = 0x2;
+    private static final int POST_INIT_DONE  = 0x4;
+    private static final int STARTING_MIDLET = 0x8;
+    private static final int RUNNING         = 0x10;
+    private static final int PAUSED          = 0x20;
+    private static final int STOPPING_MIDLET = 0x40;
+    private static final int CLOSED          = 0x80;
+    private static final int RESUMING        = 0x100;
+
+    /**
+     * A singleton instance of the life cycle. It is singleton for provoding
+     * easy access to all other classes of the MIDP runtime.
+     */
+    private static MidletLifeCycle       mInstance = new MidletLifeCycle();
+
+    /**
+     * Timers for ensuring that correct actions are done if MIDlet doesn't
+     * return from destroyApp().
+     */
+    private        Timer                 mTimer;
+    private        ShutDownTimerTask     mShutDownTimerTask;
+
+    /**
+     * Arguments recived from native starter.
+     */
+    private        MainArgs              mMainArgs;
+
+    /**
+     * The task queue of the life cycle.
+     */
+    private        TaskQueue             mTaskQueue;
+
+    /**
+     * The state of the state machine of the life cycle.
+     */
+    private        int                   mState;
+
+    /**
+     * A comms connection to Java Captain.
+     */
+    private        MidpComms             mMidpcomms;
+
+    /**
+     * The gate to the MIDlet. All the MIDP runtime specific actions from
+     * and to MIDlet are done by using this object.
+     */
+    private        MidletApplicationBase mMidletApplication;
+
+    /**
+     * The UID of the MIDlet. Is not be available in pre-warm start.
+     */
+    private        Uid                   mMidletUid;
+
+    /**
+     * A pointer to native peer.
+     */
+    private        int                   mNativeRuntimeStarterHandle;
+
+    /**
+     * On error cases that require showing error dialogs an instace of
+     * RuntimeErrorDialog will be created. Before starting shut down procedures
+     * the life cycle will check if this contains a valid reference. On normal
+     * case this is null, but if not then the dialog is prompted before
+     * continuing shut down procedures.
+     */
+    private        RuntimeErrorDialog    mRuntimeErrDialog;
+
+    /**
+     * Flag for identifying if the life cycle should be started into pre-warmed
+     * state.
+     */
+    private        boolean               mPrewarmStart = false;
+    /**
+     * Flag for identifying whether the MIDlet should be started to background.
+     */
+    private        boolean               mBackGroundStart = false;
+
+    /**
+     * How many times MIDlet has been 're-started'
+     */
+    private        int                   mRelaunchCount = 0;
+
+    /**
+     * This is set to true if the MIDlet is started with url and
+     * the url contains MIDlet argument 'PromptAppStartup'
+     */
+    private        boolean               mAutoinvocationFromUrl = false;
+
+    /**
+     * Flag for identifying whether the MIDlet is a standalone MIDlet.
+     */
+    private        boolean               mStandAlone = false;
+
+    /*** ----------------------------- PRIVATE ---------------------------- */
+
+
+    /**
+     * The constructor of the MidletLifeCycle.
+     */
+    private MidletLifeCycle()
+    {
+        mState = STARTING_INIT;
+    }
+
+    /*** ----------------------------- PACKAGE ---------------------------- */
+
+    /**
+     * Will return a singleton instance of the life cycle.
+     * @return a singleton instance of the life cycle.
+     */
+    static MidletLifeCycle getInstance()
+    {
+        return mInstance;
+    }
+
+    /**
+     * Can be used for ensuring that important cleanings has been done if some
+     * exception has occured during the shut down procedures. It also destroys
+     * the singelton instance of the life cycle.
+     */
+    static void destroyInstance()
+    {
+        if (mInstance != null)
+        {
+            // Ensure that DRM rights are consumed when the MIDlet is
+            // closed.
+            DrmUtil.consumeRightsStop();
+
+            if (mInstance.mState != CLOSED)
+            {
+                _closeInd(mInstance.mNativeRuntimeStarterHandle);
+            }
+            if (mInstance.mMidpcomms != null)
+            {
+                mInstance.mMidpcomms.close();
+            }
+
+            mInstance = null;
+        }
+    }
+
+    /**
+     * Entry point for starting the life cycle.
+     * @param args The arguments provided to MIDP runtime.
+     */
+    void doRun(String[] args)
+    {
+        // Parse given args.
+        mMainArgs = new MainArgs(args);
+
+        // Make intializations that can be done without knowing the MIDlet to
+        // be launched.
+        doPreInit();
+        startStateMachine();
+
+        DrmUtil.consumeRightsStop();
+
+        if (mRuntimeErrDialog != null)
+        {
+            mRuntimeErrDialog.showDialog();
+        }
+        if (Log.mOn) Log.logI("Sending close indication to runtime starter.");
+        _closeInd(mNativeRuntimeStarterHandle);
+
+        if (Log.mOn) Log.logI("Sending shutdown notifications to listeners.");
+        ApplicationUtilsImpl.doShutdownImpl();
+
+        if (!mStandAlone)
+        {
+            if (Log.mOn) Log.logI("Sending termination indication to Captain.");
+            mMidpcomms.sendTerminatedIndication(0);
+
+            if (Log.mOn) Log.logI("Closing COMMS.");
+            mMidpcomms.close();
+            mMidpcomms = null;
+        }
+
+        if (Log.mOn) Log.logI("Short pause before closing dispatchers.");
+        try
+        {
+            Thread.sleep(200);
+        }
+        catch (Exception e)
+        {
+        }
+
+        if (Log.mOn) Log.logI("Closing dispatchers.");
+        LegacySupport.close();
+
+        // Setting state to closed.
+        mState = CLOSED;
+    }
+
+    /**
+     * For setting the MidletApplication. This is set by the constructor of
+     * the MidletApplicationBase clase during the construction of the MIDlet
+     * class. See description of the MidletApplicationBase and the
+     * mMidletApplication.
+     * @param midletApplication The MidletApplication to be set.
+     */
+    void setMidletApplication(MidletApplicationBase midletApplication)
+    {
+        mMidletApplication = midletApplication;
+    }
+
+    /**
+     * For getting the MidletApplication. See description of the
+     * MidletApplicationBase and the mMidletApplication.
+     * @return The MidletApplication.
+     */
+    MidletApplicationBase getMidletApplication()
+    {
+        return mMidletApplication;
+    }
+
+    /**
+     * For notifying that MIDlet is entering into destroyed state. The
+     * originator of this call is the MIDlet itself.
+     */
+    void notifyDestroyed()
+    {
+        if (Log.mOn) Log.logI("notifyDestroyed() called.");
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.STOP_REQUEST,
+                                             LifeCycleTask.APP_STOP_REQUEST));
+    }
+
+    /**
+     * For notifying that MIDlet is entering into paused state. The
+     * originator of this call is the MIDlet itself.
+     */
+    void notifyPaused()
+    {
+        if (Log.mOn) Log.logI("Pause notification from MIDlet received.");
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.PAUSE_REQUEST));
+    }
+
+    /**
+     * For notifying the MIDlet that something int the device has happened
+     * that would require MIDlet to enter into   entering into actice state from paused
+     * state. The originator of this call is the MIDlet itself or the user
+     * of the ApplicationUtils.resumeApplication method of the Runtime support
+     */
+    void pauseApplication()
+    {
+        if (Log.mOn) Log.logI("Pause application request received.");
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.PAUSE_APP_REQUEST));
+    }
+
+    /**
+     * For notifying that MIDlet is entering into actice state from paused
+     * state. The originator of this call is the MIDlet itself or the user
+     * of the ApplicationUtils.resumeApplication method of the Runtime support.
+     */
+    void resumeRequest()
+    {
+        if (Log.mOn) Log.logI("Resume request received.");
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.RESUME_REQUEST));
+    }
+
+    /**
+     * For handling the start request received from the Java Captain. There are
+     * two use cases when this could happen:
+     *   - The MIDP runtime was in pre-warmed state and received a start cmd.
+     *   - The MIDlet is already running and user "re-starts" the MIDlet.
+     */
+    void launchMidletRequest(Uid uid, boolean backGroundStart, String applicationArgs)
+    {
+        if (Log.mOn) Log.logI("Request for launching MIDlet received.");
+        // Store the info whether MIDlet should be started to back ground.
+        mBackGroundStart = backGroundStart;
+
+        // Update relaunch count if really relaunching (not when activating
+        // prewarmed MIDlet)
+        if (mState != PRE_INIT_DONE)
+        {
+            mRelaunchCount++;
+        }
+        JvmInternal.setSystemProperty("com.nokia.mid.cmdline.instance",
+                                      Integer.toString(mRelaunchCount + 1));
+        if (Log.mOn)
+            Log.logI("MIDlet launch count is : " + Integer.toString(mRelaunchCount + 1));
+
+        // Update possible MIDlet arguments
+        setMidletArguments(applicationArgs);
+
+        if (mState == PRE_INIT_DONE)
+        {
+            // We were waiting in prewarmed state the launch request
+            // and now got it.
+            StartUpTrace.doTrace("Start request in pre-warm state received.");
+            mMidletUid = uid;
+            mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.START_REQUEST,
+                                                 LifeCycleTask.PRE_WARM_START));
+        }
+        else
+        {
+            // Bring the MIDlet to foreground
+            CoreUi.foregroundRequest();
+        }
+    }
+
+    /**
+     * For handling the terminate request originated by the system. There are
+     * two sources for entering into this method - Java Captain sends a message
+     * to the MIDP runtime that the MIDlet should be closed. In that case the
+     * Captain has already a timer running for failures in shut down
+     * procedures. In that case the internal timer won't be started.
+     * The second option is that some one has called notifyExitCmd() of the
+     * Runtime Support APIs. In that case a timer will be started to ensure
+     * the shut down also in case the MIDlet doesn't return from the
+     * destroyApp() call.
+     * @param useTimer Info whether to start the interna timer for ensuring
+     *                  proper shut down.
+     */
+    void terminateMidletRequest(boolean useTimer)
+    {
+        Log.logP("Request for terminating MIDlet " + mMidletUid +
+                 "  received.");
+        if (Log.mOn) Log.logI("  Internal timer used: " + useTimer);
+        if (mState != STOPPING_MIDLET && mState != CLOSED)
+        {
+            if (useTimer)
+            {
+                startShutDownTimer();
+            }
+            mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.STOP_REQUEST,
+                                                 LifeCycleTask.SYSTEM_STOP_REQUEST));
+        }
+        else
+        {
+            if (Log.mOn) Log.logI("  Already doing shutdown.");
+        }
+    }
+
+    /**
+     * For notifying that the MIDletInvoker has succesfully returned from
+     * startApp() call of the MIDlet.
+     */
+    void midletStarted()
+    {
+        if (Log.mOn) Log.logI("MIDlet started indication received.");
+        mTaskQueue.addTask(
+            new LifeCycleTask(LifeCycleTask.MIDLET_RUNNING_IND));
+    }
+
+    /**
+     * For notifying that the MIDletInvoker has succesfully returned from
+     * startApp() call of the MIDlet as a result of resumeRequest.
+     */
+    void midletResumed(boolean ok)
+    {
+        if (Log.mOn) Log.logI("MIDlet resumed indication received. " + ok);
+        if (ok)
+        {
+            mTaskQueue.addTask(
+                new LifeCycleTask(LifeCycleTask.MIDLET_RUNNING_IND));
+        }
+    }
+
+    /**
+     * For notifying that the MIDletInvoker has succesfully returned from
+     * destroyApp() call.
+     */
+    void midletDestroyed()
+    {
+        Log.logP("MIDlet " + mMidletUid + " has been destroyed.");
+        if (Log.mOn) Log.logI("MIDlet destroyed indication received.");
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.STOPPED_IND));
+    }
+
+    /**
+     * For notifying that an exception has occured during the MIDlet start.
+     * @param th The throwable that was catched during the start.
+     */
+    void handleMidletStartUpFailure(Throwable th)
+    {
+        Log.logE("Failed to start MIDlet! ", th);
+        mRuntimeErrDialog = RuntimeErrorDialog.getStartUpErrorDialog(th);
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.STARTUP_FAILURE));
+    }
+
+    /**
+     * For notifying that an exception has occured during pausing the MIDlet.
+     * The MIDlet will be destroyed.
+     */
+    void handleMidletPauseAppFailure()
+    {
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.PAUSE_FAILURE));
+    }
+
+    /**
+     * For notifying that some thread didn't catch a throwable.
+     * @param th The throwable that some thread didn't catch.
+     */
+    void handleUncaughtException(Throwable th)
+    {
+        Log.logE("Uncaught exception! ", th);
+        mRuntimeErrDialog = RuntimeErrorDialog.getUnhandledDialog(th);
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.UNCAUGHT_EXCEPTION));
+    }
+
+    /**
+     * A getter for info whether the MIDlet should be started into background.
+     * @return true if application should be started into back ground, false
+     *         otherwise.
+     */
+    boolean isBackGroundStart()
+    {
+        // If the background flag has already been set by starter just return
+        // If not then we need to check if the user has been set the UI into
+        // background before the UI toolkit has been activated.
+        if (!mBackGroundStart)
+        {
+            mBackGroundStart = !CoreUi.isUiInForeground();
+        }
+        return mBackGroundStart;
+    }
+
+
+    /*** ----------------------------- PRIVATE ---------------------------- */
+
+    /**
+     * For starting the state machine of the life cycle
+     */
+    private void startStateMachine()
+    {
+        if (Log.mOn) Log.logI("Entering main loop.");
+
+        if (mPrewarmStart)
+        {
+            _restoreNormalProcessPriority();
+            int shrinkSize = JvmInternal.shrinkJavaHeapToMinimum();
+            StartUpTrace.doTrace("Heap shrunk by " + shrinkSize + " bytes.");
+            if (Log.mOn) Log.logI("Heap shrunk by " + shrinkSize + " bytes.");
+        }
+        boolean loop = true;
+        while (loop)
+        {
+            LifeCycleTask task = (LifeCycleTask)mTaskQueue.getTask();
+            int mainTask = task.getMainTask();
+            int subTask = task.getSubTask();
+
+            switch (mainTask)
+            {
+                // Start request. Originator is Java Captain.
+            case LifeCycleTask.START_REQUEST:
+                handleStartRequest(subTask);
+                break;
+
+                // Running indication. Originator is MidletInvoker.
+            case LifeCycleTask.MIDLET_RUNNING_IND:
+                if (Log.mOn) Log.logI("LOOP: Handling MIDLET_RUNNING_IND.");
+                mState = RUNNING;
+                break;
+
+                // Stop request. Originator is either Java Captain,
+                // Runtime Support API caller or shut down timer..
+            case LifeCycleTask.STOP_REQUEST:
+                loop = handleStopRequest(subTask);
+                break;
+
+                // Stopped indication. Originator is MidletInvoker.
+            case LifeCycleTask.STOPPED_IND:
+                if (Log.mOn) Log.logI("LOOP: Handling STOPPED_IND.");
+                cancelShutDownTimer();
+                loop = false;
+                break;
+
+                // Pause request. Originator is MIDlet.
+            case LifeCycleTask.PAUSE_REQUEST:
+                handlePauseRequest();
+                break;
+
+                // Pause application request. Originator is MIDlet or the user
+                // of the ApplicationUtils.pauseApplication method of the
+                // Runtime support. This leads to call of MIDlet.pauseApp().
+            case LifeCycleTask.PAUSE_APP_REQUEST:
+                handlePauseAppRequest();
+                break;
+
+                // Resume request. Originator is MIDlet or the user
+                // of the ApplicationUtils.resumeApplication method of the
+                // Runtime support.
+            case LifeCycleTask.RESUME_REQUEST:
+                handleResumeRequest();
+                break;
+
+                // Error in startApp request. Originator is MidletInvoker.
+            case LifeCycleTask.STARTUP_FAILURE:
+                // Error in pauseApp request. Originator is MidletInvoker.
+            case LifeCycleTask.PAUSE_FAILURE:
+                MidletInvoker.stopMidlet();
+                loop = false;
+                break;
+
+            case LifeCycleTask.UNCAUGHT_EXCEPTION:
+                // Midlet will be immediately destroyd without calling
+                // destroyApp().
+                loop = false;
+                break;
+            default:
+                Log.logE("LOOP: Unknown task: " + mainTask);
+                break;
+            }
+        }
+        mState = CLOSED;
+        if (Log.mOn) Log.logI("Leaving main loop.");
+    }
+
+    /**
+     * Handles the start request task. Allowed to be called only from
+     * startStateMachine() method. The only intention of this method is
+     * to diminish the switch case clause in the diminish startStateMachine()
+     * method.
+     * @param subTask The sub task provided by the task setter.
+     */
+    private void handleStartRequest(int subTask)
+    {
+        if (Log.mOn) Log.logI("MidletLifeCycle.handleStartRequest(), subTask: "
+                                  + subTask);
+        if (mState == POST_INIT_DONE || (mState == PRE_INIT_DONE &&
+                                         subTask == LifeCycleTask.PRE_WARM_START))
+        {
+            if (subTask == LifeCycleTask.NORMAL_START)
+            {
+                if (Log.mOn) Log.logI("  Normal start");
+                mState = STARTING_MIDLET;
+                MidletInvoker.startMidlet();
+            }
+            else if (subTask == LifeCycleTask.PRE_WARM_START)
+            {
+                if (Log.mOn) Log.logI("  Pre-warm start");
+                doPreWarmInit();
+            }
+        }
+        else
+        {
+            if (Log.mOn) Log.logI("  No start, since the state was incorrect: "
+                                      + mState);
+        }
+    }
+
+    /**
+     * Handles the stop request task. Allowed to be called only from
+     * startStateMachine() method. The only intention of this method is
+     * to diminish the switch case clause in the startStateMachine()
+     * method.
+     * @param subTask The sub task provided by the task setter.
+     * @return true if the task listening should continue, false otherwise.
+     */
+    private boolean handleStopRequest(int subTask)
+    {
+        if (Log.mOn) Log.logI("MidletLifeCycle.handleStopRequest(), subTask: "
+                                  + subTask);
+        mState = STOPPING_MIDLET;
+        boolean loop = true;
+        if (subTask == LifeCycleTask.APP_STOP_REQUEST)
+        {
+            if (Log.mOn) Log.logI("  Request from app -> no destroyApp call.");
+            loop = false;
+        }
+        else if (subTask == LifeCycleTask.SYSTEM_STOP_REQUEST)
+        {
+            if (Log.mOn) Log.logI("  Request from system -> call destroyApp.");
+            MidletInvoker.stopMidlet();
+        }
+        else if (subTask == LifeCycleTask.DO_FORCED_TERMINATE)
+        {
+            if (Log.mOn) Log.logI("  Doing forceful termination.");
+            loop = false;
+        }
+        return loop;
+    }
+
+    /**
+     * Handles the pause request task. Allowed to be called only from
+     * startStateMachine() method. The only intention of this method is
+     * to diminish the switch case clause in the startStateMachine()
+     * method. This is called when the MIDlet itself wants to go to
+     * paused state.
+     */
+    private void handlePauseRequest()
+    {
+        if (Log.mOn) Log.logI("MidletLifeCycle.handlePauseRequest()");
+        if (mState != RUNNING)
+        {
+            Log.logW("Pause request received in illegal state: " + mState);
+        }
+        mState = PAUSED;
+    }
+
+    /**
+     * Handles the pause app request task. Allowed to be called only from
+     * startStateMachine() method. The only intention of this method is
+     * to diminish the switch case clause in the startStateMachine()
+     * method. This is called when the System wants the MIDlet change to
+     * paused state.
+     */
+    private void handlePauseAppRequest()
+    {
+        if (Log.mOn) Log.logI("MidletLifeCycle.handlePauseAppRequest()");
+        if (mState != RUNNING)
+        {
+            Log.logW("Pause request received in illegal state: " + mState);
+        }
+        MidletInvoker.pauseMidlet();
+        mState = PAUSED;
+    }
+
+
+
+    /**
+     * Handles the resume request task. Allowed to be called only from
+     * startStateMachine() method. The only intention of this method is
+     * to diminish the switch case clause in the startStateMachine()
+     * method.
+     */
+    private void handleResumeRequest()
+    {
+        if (Log.mOn) Log.logI("MidletLifeCycle.handleResumeRequest()");
+        if (mState == PAUSED)
+        {
+            mState = STARTING_MIDLET;
+            MidletInvoker.resumeMidlet();
+        }
+        else
+        {
+            Log.logW("Resume request received in illegal state: " + mState);
+        }
+    }
+
+    /**
+     * For informing the JVM about the protected and restricted packages.
+     */
+    private void setClassProtection()
+    {
+        if (Log.mOn) Log.logI("Setting protected classes.");
+        PackageProtector protector = PackageProtector.getInstance();
+        JvmInternal.addProtectedPackagePrefixes(
+            protector.getProtectedPackageNames());
+        JvmInternal.addRestrictedPackagePrefixes(
+            protector.getRestrictedPackageNames());
+    }
+
+    /**
+     * For doing the initializations that can be done before knowing the UID
+     * of the MIDlet
+     */
+    private void doPreInit()
+    {
+        if (Log.mOn) Log.logI("Doing pre init.");
+
+        // Load the native.
+        Jvm.loadSystemLibrary("javamidpruntime");
+
+        // Start to monitor uncaught exceptions.
+        JvmInternal.setThreadEventListener(new ThreadEventListener()
+        {
+            public void threadStarting(Thread newThread, Thread parentThread)
+            {
+                if (Log.mOn) Log.logI("threadStarting newThread:" + newThread
+                                          + ", parentThread:"+parentThread);
+            }
+            public void threadDied(Thread thread)
+            {
+                if (Log.mOn) Log.logI("threadDied thread:"+thread);
+            }
+            public void uncaughtException(Thread thread, Throwable throwable)
+            {
+                handleUncaughtException(throwable);
+            }
+        });
+
+        // Store the starter handle for native access.
+        mNativeRuntimeStarterHandle =
+            Integer.parseInt(mMainArgs.findArgument("-handle"));
+
+        mStandAlone = mMainArgs.findArgument("-standalone") != null;
+        if (Log.mOn) Log.logI("Is standalone MIDlet = " + mStandAlone);
+
+        if (!mStandAlone)
+        {
+            // Do not allow System.exit().
+            JvmInternal.disableRuntimeExit();
+
+            // Set protected and restricted packages.
+            setClassProtection();
+
+            // Check if there are add-on JSRs.
+            ExtensionUtil.handleExtensions();
+        }
+
+        mTaskQueue = new TaskQueue();
+
+        // If system property com.nokia.mid.cmdline has value, it contains
+        // the arguments for the current MIDlet.
+        String encodedMidletArgs = System.getProperty("com.nokia.mid.cmdline");
+        if ((encodedMidletArgs != null) && (encodedMidletArgs.length() > 0))
+        {
+            // Decode arguments
+            String midletArgs = decodeArgs(encodedMidletArgs);
+
+            // Parse them
+            setMidletArguments(midletArgs);
+        }
+
+        // If the runtime is set to pre warmed state, then the
+        // value of the prewarm flag contans the process id which
+        // is needed by Captain for identification.
+        String pid = mMainArgs.findArgument("-prewarm");
+        mPrewarmStart = pid != null;
+        mState = PRE_INIT_DONE;
+        if (!mPrewarmStart)
+        {
+            // We know the MIDlet to be launched, so post init can be done.
+            mMidletUid = Uid.createUid(mMainArgs.findArgument("-uid"));
+            if (!CoreUi.connectToUi())
+            {
+                // If not in prewarmed state we need to connect
+                // to core UI. If the core Ui is closed, then
+                // don't continue the start up.
+                if (Log.mOn) Log.logI("CoreUi was closed - so no start.");
+                throw new StartupException("Core UI closed.",false);
+            }
+            // Cache the info if the intention is to start the MIDlet into
+            // background.
+            mBackGroundStart = mMainArgs.findArgument("-background") != null;
+
+            doPostInit();
+
+            if (!mStandAlone)
+            {
+                // Create a comms connection to Java Captain.
+                mMidpcomms = new MidpComms(mMidletUid);
+
+                // Send running indication with success status.
+                mMidpcomms.sendRunningIndication(0);
+            }
+        }
+        else
+        {
+            // Create a comms connection to Java Captain.
+            mMidpcomms = new MidpComms();
+
+            // Send running indication. Send the pid to Captain for
+            //identification.
+            mMidpcomms.sendProcessRunningIndication(Integer.parseInt(pid));
+            wakeUpUi();
+        }
+    }
+
+    /**
+     * Decode string in a private format that was safe to pass to Java side
+     * as a Java system property.
+     * Native side function java::util::runtime::MidpRuntimeStarter::encodeArgs()
+     * was used to encode the string
+     *
+     * @param args original wstring
+     * @return encoded wstring
+     */
+    private String decodeArgs(String encodedArgs)
+    {
+        StringBuffer res = new StringBuffer();
+        int idx = encodedArgs.indexOf('%');
+        int cur = 0;
+
+        while (idx != -1)
+        {
+            // Add all characters up to but not including the '%' char
+            // to final result string
+            if ((idx - cur) > 0)
+            {
+                res.append(encodedArgs.substring(cur, idx));
+            }
+
+            // Decode all special sequences 'X%' in same way.
+            // "X%" -> "X", so skip "%"
+            // Note that "%%" is decoded to "%"
+            cur = idx + 1;
+            idx = encodedArgs.indexOf('%', cur + 1);
+        }
+
+        // Add characters after last special character if any
+        res.append(encodedArgs.substring(cur, encodedArgs.length()));
+
+        return res.toString();
+    }
+
+    /**
+     * This method is meant for informing the UI that the MIDP runtime has
+     * entered into pre-warmed state. The method simply tries to instatiate
+     * a class provided by a specified system property. In the constructor
+     * of the object the UI may start the pre warming steps.
+     */
+    private void wakeUpUi()
+    {
+        // Get the class name.
+        String className = System.getProperty("com.nokia.mj.impl.ui");
+        if (className != null)
+        {
+            // If the property is set, instantiate the class.
+            try
+            {
+                Class clazz = Class.forName(className);
+                clazz.newInstance();
+            }
+            catch (Throwable t)
+            {
+                // Silently ignore exceptions.
+            }
+        }
+    }
+
+    /**
+     * This method does the necessary initializations after leaving the pre-
+     * warmed state. When calling this method, the MIDlet UID must be known.
+     * Heap size is not set.
+     */
+    private void doPreWarmInit()
+    {
+        if (Log.mOn) Log.logI("Doing prewarm init.");
+
+        doPostInit();
+
+        // The native peer doesn't know the UID of the started MIDlet.
+        // Informing native.
+        _setUids(mMidletUid.toString(),
+                 ApplicationInfoImpl.getMidletInfo().getSuiteUid().toString(),
+                 mNativeRuntimeStarterHandle);
+        // The Jvm doesn't know about MIDlet class path - need to set it.
+        String classPath = ApplicationInfoImpl.getMidletInfo().getClassPath();
+        if (Log.mOn) Log.logI("  Adding to classpath: "+classPath);
+        JvmInternal.appendToClassPath(classPath);
+    }
+
+    private void doPostInit()
+    {
+        if (Log.mOn) Log.logI("Doing post init.");
+
+        // Set the MidletInfo class to contain correct data. The data is read
+        // from storage.
+        setMidletInfo();
+
+        if (mPrewarmStart)
+        {
+            // Get the recorded heap size from previous run.
+            int targetHeapSize = MemoryLogger.getOldHeapSizeToExpand();
+
+            int expandedSize = JvmInternal.expandJavaHeap(targetHeapSize);
+            StartUpTrace.doTrace("Heap expand req:"+ targetHeapSize +" B. Result: "+ expandedSize + " B.");
+            // Do the post init actions.
+            // In case of pre-warm start we need to create the core ui
+            // from Java side. In order to ensure that Runtime Support
+            // API works ok, the setMidletInfo must be called before
+            // starting the UI.
+            CoreUi.createUi(mMidletUid, mBackGroundStart);
+        }
+        if (!mStandAlone)
+        {
+
+            // Do the MIDlet suite authentication.
+            verifyMIDletSuiteAuthenticity();
+
+            // Inform the DRM util that the MIDlet is about to start.
+            DrmUtil.consumeRightsStart();
+        }
+
+        // If the MIDlet launch is a result of auto invocation we need to
+        // ensure that user allows the start up.
+        if ((mMainArgs.findArgument("-autoinvocation") != null) ||
+                mAutoinvocationFromUrl)
+        {
+            try
+            {
+                if (Log.mOn) Log.logI("Ensuring autoinvocation.");
+                String pushAdditionalInfo =
+                    mMainArgs.findArgument("-autoInvocationAdditional");
+                if (Log.mOn) Log.logI("  addInfo: '" + pushAdditionalInfo + "'");
+                PushSecurityUtils.ensurePermission("autoinvocation",
+                                                   pushAdditionalInfo);
+
+                if (Log.mOn) Log.logI("Autoinvocation allowed.");
+            }
+            catch (SecurityException se)
+            {
+                // The user didn't allow starting. Throw StartupException and
+                // mark it as non fatal.
+                if (Log.mOn) Log.logI("Autoinvocation NOT allowed.");
+                throw new StartupException("Auto invocation not allowed.",
+                                           false);
+            }
+        }
+
+        // Initialize the legacy support layer if exists.
+        LegacySupport.init(
+            ApplicationInfoImpl.getMidletInfo().getMidletAttributes(),
+            isBackGroundStart());
+
+        mState = POST_INIT_DONE;
+
+        // All the initializations done now, ready to start the MIDlet.
+        mTaskQueue.addTask(new LifeCycleTask(LifeCycleTask.START_REQUEST,
+                                             LifeCycleTask.NORMAL_START));
+
+        // If there are any waiters for the start up, release those.
+        ApplicationUtilsImpl.releaseStartWaiterImpl(true);
+    }
+
+    /**
+     * Verifies the authenticity of MIDlet suite.
+     * @throws StartupException on error case.
+     */
+    private void verifyMIDletSuiteAuthenticity()
+    {
+        if (Log.mOn) Log.logI("Verifying MIDlet Suite authenticity.");
+        // Get instance of MidleInfo for getting arguments.
+        MidletInfo midletInfo = ApplicationInfoImpl.getMidletInfo();
+
+        try
+        {
+            // Get instance of AuthenticationModule for doing the verification.
+            AuthenticationModule authenticationModule =
+                AuthenticationModule.getInstance();
+
+
+            // Set a data object to conatin necessary info used during
+            // verificaton.
+            AuthenticationStorageData securityStorageData =
+                new AuthenticationStorageData(
+                midletInfo.getProtectionDomainName(),
+                midletInfo.getProtectionDomain(),
+                midletInfo.getMidletHash(),
+                midletInfo.getRootHash(),
+                midletInfo.getClassPath());
+            authenticationModule.verifyMIDletSuiteAuthenticity(
+                midletInfo.getSuiteUid(),
+                securityStorageData);
+        }
+        catch (RuntimeSecurityException rse)
+        {
+            // Display the error to user
+            RuntimeErrorDialog.showAuthenticationFailed(rse);
+            throw new StartupException("Suite authentication failed.");
+        }
+        if (Log.mOn) Log.logI("MIDlet Suite authenticity verified.");
+    }
+
+    /**
+     * Sets the MIDlet info to contain the MIDlet data from Java Storage.
+     */
+    private void setMidletInfo()
+    {
+        if (Log.mOn) Log.logI("Setting MIDlet data.");
+        // Create MidletInfo instance for storing the ApplicationInfo for the
+        // runtime support.
+        MidletInfo midletInfo = new MidletInfo();
+        midletInfo.setUid(mMidletUid);
+
+        if (!mStandAlone)
+        {
+
+            // Read the "static" arguments. These are used for starting the MIDlet.
+            StorageAccessor.setMidletStartArguments(midletInfo);
+
+            // Read the MIDlet attributes defined in the manifest and Jad (if
+            // present).
+            StorageAccessor.setMidletAttributes(midletInfo);
+
+        }
+        else
+        {
+            // Read the MIDlet attributes defined in the manifest and Jad (if
+            // present).
+            SaMidletInfoProvider.setMidletAttributes(midletInfo, mMainArgs.findArgument("-jad"));
+
+            // Read the "static" arguments. These are used for starting the MIDlet.
+            SaMidletInfoProvider.setMidletStartArguments(midletInfo);
+            // Set the root path of the MIDlet suite.
+            midletInfo.setRootPath(mMainArgs.findArgument("-rootpath"));
+        }
+        // ApplicationInfoImpl will store the MIDlet info.
+        ApplicationInfoImpl.setMidletInfo(midletInfo);
+        if (Log.mOn) Log.logI("MidletInfo: " + midletInfo);
+    }
+
+    /**
+     * Starts the shut down timer if not yet started. The timer is for
+     * ensuring the proper shut down in a case where the MIDlet doesn't
+     * return from destroyApp() in given time. The time is 5 seconds.
+     */
+    private void startShutDownTimer()
+    {
+        if (Log.mOn) Log.logI("Starting shutdown timer.");
+        if (mTimer == null)
+        {
+            mTimer = new Timer();
+            mShutDownTimerTask = new ShutDownTimerTask();
+            mTimer.schedule(mShutDownTimerTask, 5000);
+        }
+        else
+        {
+            Log.logW("Shutdown timer already running");
+        }
+
+    }
+
+    /**
+     * Cancels the shut down timer.
+     */
+    private void cancelShutDownTimer()
+    {
+        if (Log.mOn) Log.logI("Cancelling shutdown timer.");
+        if (mTimer != null)
+        {
+            mTimer.cancel();
+            mTimer = null;
+            mShutDownTimerTask = null;
+        }
+    }
+
+    /**
+     * Parse the MIDlet arguments given as parameter and set them
+     * to system properties so that MIDlet can access them.
+     *
+     * @param applicationArgs the MIDlet arguments, can be empty
+     */
+    private void setMidletArguments(String applicationArgs)
+    {
+        if (applicationArgs == null)
+        {
+            applicationArgs = "";
+        }
+        JvmInternal.setSystemProperty("com.nokia.mid.cmdline", applicationArgs);
+
+        if (applicationArgs.length() > 0)
+        {
+            if (Log.mOn)
+                Log.logI("MIDlet arguments are : " + applicationArgs);
+
+            // parse args and set individual system properties
+            // e.g. "startMode=startFromCmdLine;sound=ON;wizard_mode;landscapeMode=true"
+            int idx;
+            int indEq;
+            int cur = 0;
+            StringBuffer argBuf = new StringBuffer();
+            String arg;
+            String propertyKey;
+            String propertyValue;
+            mAutoinvocationFromUrl = false;
+
+            do
+            {
+                argBuf.setLength(0);
+                idx = applicationArgs.indexOf(";", cur);
+
+                if (idx == 0)
+                {
+                    // Arguments string started with ';'
+                    cur = idx + 1;
+                    continue;
+                }
+
+                argBuf.append("com.nokia.mid.cmdline.param.");
+                if (idx != -1)
+                {
+                    argBuf.append(applicationArgs.substring(cur, idx));
+                }
+                else
+                {
+                    argBuf.append(applicationArgs.substring(cur));
+                }
+
+                // split one arg to key and value
+                arg = argBuf.toString();
+                indEq = arg.indexOf('=');
+                propertyKey = null;
+                propertyValue = "";
+
+                if (indEq == -1)
+                {
+                    // The property doesn't have a value.
+                    propertyKey = arg;
+                }
+                else
+                {
+                    // The property has also a value.
+                    propertyKey = arg.substring(0, indEq);
+                    propertyValue = arg.substring(indEq + 1);
+                }
+
+                if (propertyKey.equals("com.nokia.mid.cmdline.param.PromptAppStartup"))
+                {
+                    mAutoinvocationFromUrl = true;
+                    if (Log.mOn)
+                        Log.logI("MIDlet had argument PromptAppStartup");
+                }
+
+                JvmInternal.setSystemProperty(propertyKey, propertyValue);
+
+                cur = idx + 1;
+            }
+            while ((idx != -1) && (cur < applicationArgs.length()));
+        }
+    }
+
+    /**
+     * Class for extending the TimerTask. This is for the shut down timer.
+     */
+    private class ShutDownTimerTask extends TimerTask
+    {
+        /**
+         * Method to be run if the shut down timer elapses.
+         */
+        public final void run()
+        {
+            try
+            {
+                if (Log.mOn) Log.logI("TIMER elapsed, do forced shut down.");
+                // Do a forceful shutdown.
+                mTaskQueue.addTask(
+                    new LifeCycleTask(LifeCycleTask.STOP_REQUEST,
+                                      LifeCycleTask.DO_FORCED_TERMINATE));
+
+            }
+            catch (Throwable t)
+            {
+                Log.logE("Error in Timer! ", t);
+            }
+        }
+    }
+
+    /*** ----------------------------- NATIVE ----------------------------- */
+
+    /**
+     * For informing the native peer to know the UID of the MIDlet.
+     * When a MIDlet is started by using pre-warmed feature, the start message
+     * is received by the Java peer of the MIDP runtime. The native peer needs
+     * also to know the UID of the MIDlet.
+     * @param midletUid The UID of the MIDlet.
+     * @param midletSuiteUid The UID of the MIDlet suite.
+     * @param starterHandle A pointer to the native runtime peer.
+     */
+    private native void _setUids(String midletUid, String midletSuiteUid,
+                                 int starterHandle);
+
+    /**
+     * Changes the process priority back to normal.
+     */
+    private native void _restoreNormalProcessPriority();
+
+
+    /**
+     * For informing the native peer that the life cycle has started the shut
+     * down procedures.
+     */
+    private static native void _closeInd(int starterHandle);
+}