javamanager/javacaptain/extensionplugins/preinstallerstarter/src.s60/preinstallerstarter.cpp
author hgs
Fri, 29 Oct 2010 11:49:32 +0300
changeset 87 1627c337e51e
parent 50 023eef975703
permissions -rw-r--r--
v2.2.21_1

/*
* Copyright (c) 2008 - 2010 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:  PreinstallerStarter is Java Captain S60 plugin that starts
*               preinstaller process when the device boots or removable drive
*               is added to the device.
*
*/


#include <e32base.h>
#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
#include <apgcli.h> // for RApaLsSession
#endif
#include <hal_data.h>
#include <hal.h>
#include <sysutil.h>

#include "javaprocessconstants.h"
#include "javasymbianoslayer.h"
#include "javauids.h"
#include "logger.h"
#include "coreinterface.h"
#include "booteventprovidermessages.h"
#include "mmceventprovidermessages.h"
#include "preinstallerstartermessages.h"

#include "preinstallerstarter.h"

#ifdef RD_JAVA_S60_RELEASE_5_0_ROM
// This file in Java Captain private data cage is used to indicate when
// converting old S60 midlets to OMJ midlets has been done after
// ROM upgrade flashing.
_LIT(KAfterFlashConversionDone, "C:\\private\\200211dc\\afconversionsdone.dat");  // codescanner::driveletters

_LIT(KAfterFlashConverterExe, "javaafterflashconverter.exe");

#endif

_LIT(KIad, " iad");
_LIT(KWaitAFConversion , " waitafconversion");

/**
 * Return pointer to ExtensionPluginInterface implementation for this
 * extension dll
 */
java::captain::ExtensionPluginInterface* getExtensionPlugin()
{
    return new java::captain::PreinstallerStarter();
}

namespace java  // codescanner::namespace
{
namespace captain  // codescanner::namespace
{

using java::fileutils::driveInfo;
using java::fileutils::DriveListenerInterface;

/**
 * Initialize member varaibles in constructor
 */
PreinstallerStarter::PreinstallerStarter() :
    CActive(EPriorityStandard), mCore(0), mPreinstaller(0)
{
}

/**
 * Destructor
 */
PreinstallerStarter::~PreinstallerStarter()
{
    DoCancel();
}

/**
 * Implement PluginInterface method
 */
void PreinstallerStarter::startPlugin(CoreInterface* core)
{
    mCore = core;
    CActiveScheduler::Add(this);
}

/**
 * Implement PluginInterface method
 */
void PreinstallerStarter::stopPlugin()
{
    mCore = 0;
}

/**
 * Implement ExtensionPluginInterface method
 */
EventConsumerInterface* PreinstallerStarter::getEventConsumer()
{
    return this;
}

/**
 * Handle Java Captain events sent by Boot event provider or
 * MMC event provider. If IAD boot (Java Captain has been started
 * after OMJ sis package has been installed), start preinstaller process
 * with 'iad' paramater, otherwise start preinstaller process
 * without the parameter.
 *
 * Implement EventConsumerInterface method
 */
void PreinstallerStarter::event(const std::string& eventProvider,
                                java::comms::CommsMessage& aMsg)
{
    if (eventProvider == BOOT_EVENT_PROVIDER)
    {
        int bootType = NORMAL_BOOT_C;
        getBootMessageParams(aMsg, bootType);
        LOG1(
            EJavaCaptain,
            EInfo,
            "PreinstallerStarter::event() boot event received (type=%d)",
            bootType);
        switch (bootType)
        {
        case IAD_BOOT_C:
        {
            // This event is received after OMJ has been (IAD) installed
            // to device.

            // Preinstaller will be started with 'iad' command line option
            // so that it knows that it has been started for the first
            // time after java 2.0 IAD installation.
            startPreinstaller(EIad);
        }
        break;

        case FIRST_DEVICE_BOOT_C:
        case NORMAL_BOOT_C:
        {
#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
            registerMidletApplicationTypeHandler();
#endif

            TPreinstallerStartMode startMode = ENormal;
#ifdef RD_JAVA_S60_RELEASE_5_0_ROM
            if (startConverter())
            {
                // Preinstaller must be started with 'waitconversion' command
                // line option so that it will wait until javaafterflashconverter.exe
                // has converted existing MIDlets.
                startMode = ERomUpgrade;
            }
#endif

            // Start preinstaller
            startPreinstaller(startMode);
        }
        break;

        default:
        {
            WLOG1(EJavaCaptain,
                  "DriveListenerInterface: event() unknown boot event (type=%d)", bootType);
        }
        break;
        }
    }
    else if (eventProvider == MMC_EVENT_PROVIDER)
    {
        int operation = 0;
        driveInfo di;
        getMmcChangedMessageParams(aMsg, operation, di);
        LOG1(
            EJavaCaptain,
            EInfo,
            "PreinstallerStarter::event() mmc event received (operation=%d)",
            operation);

        switch (operation)
        {
            // Preinstaller started reacts only to this one event.
            // All other MMC events are ignored.
        case DriveListenerInterface::REMOVABLE_MEDIA_INSERTED_C:
        {
            startPreinstaller(ENormal);
        }
        break;
        }
    }
}

/**
 * Start preinstaller process if it is not yet running.
 * The name of the executable is javapreinstaller.exe
 * When it is started, it checks all preinstall directories in the device
 * and preinstalls those java applications in the directories that have not
 * yet been installed. After that preinstaller exits.
 *
 * @param aStartMode when value is EIad, starts preinstaller with 'iad' parameter
 *                   when value is ERomUpgrade, starts preinstaller with 'waitconversion' parameter
 *                   when value is ENormal, starts preinstaller with no parameters
 */
void PreinstallerStarter::startPreinstaller(TPreinstallerStartMode aStartMode)
{
    // Check that the device has enough free memory (800kB) to start preinstaller process
    // and (if needed) also java installer
    TInt freeMemory = 0;
    TInt err = HAL::Get(HALData::EMemoryRAMFree, freeMemory);
    if (KErrNone == err)
    {
        if (freeMemory < 819200)
        {
            if (freeMemory > 40960)
            {
                // The device has enough memory to log the error
                ELOG(EJavaCaptain,
                     "PreinstallerStarter: Not enough free mem to start preinstaller");
            }
            return;
        }
    }
    else
    {
        WLOG1(EJavaCaptain, "PreinstallerStarter: Cannot check free mem, err %d", err);
    }

    // Check that the device has enough also free disk space in C: (800kB) to start
    // preinstaller process
    if (SysUtil::FFSSpaceBelowCriticalLevelL(NULL, 819200))
    {
        if (!SysUtil::FFSSpaceBelowCriticalLevelL(NULL, 40960))
        {
            // The device has enough disk space to log the error
            ELOG(EJavaCaptain,
                 "PreinstallerStarter: Not enough space in phone mem to start preinstaller");
        }
        return;
    }

    // Start preinstaller process
    _LIT(KPreinstallerMatch, "javapreinstaller*");
    TFindProcess finder(KPreinstallerMatch);
    TFullName name;

    // Check all processes found
    while (KErrNone == finder.Next(name))
    {
        // Check the state of the already existing preinstaller process
        RProcess oldPreinstaller;
        TInt ret = oldPreinstaller.Open(name);
        if (KErrNone != ret)
        {
            WLOG1(EJavaCaptain,
                  "PreinstallerStarter: Cannot open existing preinstaller process, error %d", ret);
            oldPreinstaller.Close();
            return;
        }
        else
        {
            TExitType exitType = oldPreinstaller.ExitType();
            if (EExitPending == exitType)
            {
                // Strange, preinstaller is already/still running, do nothing
                WLOG(EJavaCaptain, "PreinstallerStarter: preinstaller is already running.");
                oldPreinstaller.Close();
                return;
            }
            else
            {
                // The old preinstaller process has actually already exited,
                // but it is still in the process list due to an Open C 1.5.1 functionalities.
                LOG1(EJavaCaptain,
                     EInfo,
                     "PreinstallerStarter: old preinstaller process had exited, exit type is %d",
                     exitType);
                oldPreinstaller.Close();
            }
        }
    }
    // No preinstaller processes were found or they were all zombies.

    // Start new preinstaller process.
    {
        // Build command line used to pass all necessary info
        TBuf<128> commandLine;  // Actual len of cmd line will be max 20 characters
        int len = strlen(java::runtime::JAVA_PREINSTALLER_STARTER_DLL);
        TPtr8 ptr8((TUint8 *)java::runtime::JAVA_PREINSTALLER_STARTER_DLL, len, len);
        commandLine.Copy(ptr8);

        if (aStartMode == EIad)
        {
            commandLine.Append(KIad);
        }
        else if (aStartMode == ERomUpgrade)
        {
            commandLine.Append(KWaitAFConversion);
        }

        // start preinstaller
        mPreinstaller = new RProcess();  // codescanner::
        TBuf<64> preinstallerProcess;  // Actual len of the process name is 9
        len = strlen(java::runtime::JAVA_PROCESS);
        TPtr8 ptr8Process((TUint8 *)java::runtime::JAVA_PROCESS, len, len);
        preinstallerProcess.Copy(ptr8Process);
        TInt err = mPreinstaller->Create(preinstallerProcess, commandLine);
        if (KErrNone == err)
        {
            // Process has been created.

            // This active object will be activated when preinstaller process exits
            mPreinstaller->Logon(iStatus);

            // Allow the process to run
            mPreinstaller->Resume();
            if (aStartMode == EIad)
            {
                LOG(
                    EJavaCaptain,
                    EInfo,
                    "PreinstallerStarter: started preinstaller with iad parameter");
            }
            else if (aStartMode == ERomUpgrade)
            {
                LOG(
                    EJavaCaptain,
                    EInfo,
                    "PreinstallerStarter: started preinstaller with waitconversion parameter");
            }
            else
            {
                LOG(EJavaCaptain, EInfo, "PreinstallerStarter: started preinstaller");
            }

            SetActive();
        }
        else
        {
            delete mPreinstaller;
            mPreinstaller = 0;

            ELOG1(
                EJavaCaptain,
                "PreinstallerStarter: starting preinstaller failed, err %d",
                err);
        }
    }
}

/**
 * Register 'javalauncher.exe' as the midlet application type handler
 * in AppArc. If necessary unregister old handler first.
 */
#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
void PreinstallerStarter::registerMidletApplicationTypeHandler()
{
    _LIT(KMidpAppArcPlugin, "javalauncher.exe");

    RApaLsSession appLstSession;
    CleanupClosePushL(appLstSession);
    TInt err = appLstSession.Connect();
    if (KErrNone == err)
    {
        TRAP(err, appLstSession.RegisterNonNativeApplicationTypeL(
                 TUid::Uid(KMidletApplicationTypeUid), KMidpAppArcPlugin()));
        if (KErrNone == err)
        {
            // All is well
        }
        else if (KErrAlreadyExists == err)
        {
#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
            // S60 Java has registered MIDlet application type handler StubMIDP2RecogExe.exe,
            // must change that register
            WLOG(EJavaCaptain,
                 "PreinstallerStarter: MIDlet application type is already "
                 "registered (by Java 1.x).");
            TRAP(err, appLstSession.DeregisterNonNativeApplicationTypeL(
                     TUid::Uid(KMidletApplicationTypeUid)));
            TRAP(err, appLstSession.RegisterNonNativeApplicationTypeL(
                     TUid::Uid(KMidletApplicationTypeUid), KMidpAppArcPlugin()));
            if (KErrNone == err)
            {
                WLOG(EJavaCaptain,
                     "PreinstallerStarter: Registered MIDlet application "
                     "type again (for Java 2.x).");
            }
            else
            {
                ELOG1(EJavaCaptain,
                      "PreinstallerStarter: Reregistering MIDlet application "
                      "type failed with err %d",
                      err);
            }
#endif

            // In 9.2 and later environments this situation is OK.
            // We have already made the registration successfully.
        }
        else
        {
            ELOG1(EJavaCaptain,
                  "PreinstallerStarter: Registering MIDlet application type failed with err %d",
                  err);
        }
        CleanupStack::PopAndDestroy(&appLstSession);
    }
    else
    {
        ELOG1(EJavaCaptain,
              "PreinstallerStarter: registerMidletApplicationTypeHandler: "
              "Connecting to AppArc failed with error %d",
              err);
    }
}
#endif

void PreinstallerStarter::RunL()
{
    LOG(EJavaCaptain, EInfo, "PreinstallerStarter::RunL started");

    // Send event to AutoStarter plugin, done only once
    CommsMessage eventMsg;
    setPreinstallerExitedMessageParams(eventMsg, iStatus.Int());
    mCore->getEventDispatcher()->event(PREINSTALLER_EVENT_PROVIDER, eventMsg);

    // process handle is no longer needed
    mPreinstaller->Close();
    delete mPreinstaller;
    mPreinstaller = 0;
}


void PreinstallerStarter::DoCancel()
{
    if (mPreinstaller)
    {
        mPreinstaller->LogonCancel(iStatus);
        // Because exit notification request has been canceled,
        // there is no reason to keep the process handle open.
        mPreinstaller->Close();
        delete mPreinstaller;
        mPreinstaller = 0;
    }
}

#ifdef RD_JAVA_S60_RELEASE_5_0_ROM
/**
 * Check whether there is flag file 'afconversionsdone.dat' in the private
 * data cage of Java Captain.
 * If the flag file exists, just return EFalse to indicate that Java Preinstaller
 * does not need to wait for after ROM flash converter.
 * Otherwise start 'javaafterflashconverter.exe' process and return ETrue
 * so that Java Preinstaller is started with command line parameter that
 * tells it to wait until 'javaafterflashconverter.exe' exits.
 */
TBool PreinstallerStarter::startConverter()
{
    RFs   fs; // codescanner::rfs
    TInt  err = fs.Connect();
    if (KErrNone != err)
    {
        ELOG1(EJavaCaptain,
              "PreinstallerStarter:startConverter: "
              "Cannot connect to RFs, err %d",
              err);
        // Assume that the conversion has been done
        return EFalse;
    }

    // Check whether the flag file exists
    TUint value;
    TBool flagFileExists(ETrue);
    err = fs.Att(KAfterFlashConversionDone, value);
    if ((KErrNotFound == err) || (KErrPathNotFound == err))
    {
        flagFileExists = EFalse;
    }
    else if (KErrNone == err)
    {
        LOG(EJavaCaptain,
            EInfo,
            "PreinstallerStarter:startConverter: Flag file exists");
        flagFileExists = ETrue;
    }
    else
    {
        WLOG1(EJavaCaptain,
              "PreinstallerStarter:startConverter: Checking flag file, unexpected error %d",
              err);
        // Assume that the conversion has been done
        flagFileExists = ETrue;
    }

    if (flagFileExists)
    {
        // Conversion has been done, no need to start converter process.
        return EFalse;
    }

    // Start 'javaafterflashconverter.exe' process
    RProcess converter;
    err = converter.Create(KAfterFlashConverterExe, KNullDesC);
    if (KErrNone == err)
    {
        converter.Resume();
        LOG(EJavaCaptain, EInfo,
            "PreinstallerStarter:startConverter: javaafterflashconverter.exe was started ok");
    }
    else
    {
        ELOG1(EJavaCaptain,
            "PreinstallerStarter:startConverter: starting javaafterflashconverter failed: %d",
            err);
    }
    converter.Close();

    return ETrue;
}
#endif


} // namespace captain
} // namespace java