javatools/javaappbackconverter/src.s60/main.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 27 Apr 2010 16:30:29 +0300
branchRCL_3
changeset 14 04becd199f91
permissions -rw-r--r--
Revision: v2.1.22 Kit: 201017

/*
* 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: Java platform 2.0 javaappbackconverter process
*
*/


#include <e32std.h>
#include <e32base.h>
#include <e32property.h>
#include <f32file.h>
#include <centralrepository.h>
#include <swinstallerinternalpskeys.h>
#include <AknGlobalMsgQuery.h>

#include "javacommonutils.h"
#include "javauids.h"
#include "backconverter.h"
#include "noarmlogs.h"

_LIT_SECURE_ID(KAppInstUiSecureID, 0x101F875A);
_LIT_SECURE_ID(KAppSisLauncherSecureID, 0x1020473F);


/**
 * Create file server connection.
 * If no data storage file exists, exit.
 * Create active scheduler and start it to execute actual back converter.
 */
static void ExecuteBackConverterL(RFs &aFs)
{
    LOG(EJavaConverters, EInfo, "javaappbackconverter: ExecuteBackConverterL called");

    CActiveScheduler* as = new(ELeave) CActiveScheduler();

    // Install active scheduler
    CActiveScheduler::Install(as);
    CleanupStack::PushL(as);

    // The file server session must be shared so that that AppArc can
    // use the icon file handle opened in back converter
    TInt err = aFs.ShareProtected();
    if (KErrNone != err)
    {
        ELOG1(EJavaConverters,
              "javaappbackconverter: ExecuteBackConverterL: "
              "Cannot share file server session, err code is %d ", err);
        User::Leave(err);
    }

    // Setup and start the back conversion
    CBackConverter* back = CBackConverter::NewLC(aFs);

    LOG(EJavaConverters,
        EInfo, "javaappbackconverter: ExecuteBackConverterL: Call CBackConverter::Start()");

    back->Start();

    // Start active scheduler
    LOG(EJavaConverters, EInfo, "ExecuteBackConverterL: Starting CActiveScheduler");
    CActiveScheduler::Start();

    LOG(EJavaConverters, EInfo, "javaappbackconverter: ExecuteBackConverterL: Cleaning up");

    CleanupStack::PopAndDestroy(back);
    CleanupStack::PopAndDestroy(as);
}

/**
 * Menu application has a central repository key that can be used in
 * devices belonging to Nokia 5800 XpressMusic device family to request
 * that the Menu application would rescan all applications it contains.
 */
static void UseCRKeyToUpdateAppShellDataL()
{
    const TUid KCRUidMenu = { 0x101F8847 };
    const TUint32 KMenuUpdateData = 0x00000001;

    // Update Central Rep
    CRepository *pCenRep = CRepository::NewL(KCRUidMenu);

    TInt value = 1;
    TInt err = pCenRep->Set(KMenuUpdateData, value);
    if (KErrNone != err)
    {
        ELOG1(EJavaConverters,
              "javaappbackconverter: UseCRKeyToUpdateAppShellDataL: "
              "setting cenrep value failed, error %d ",
              err);
    }

    delete pCenRep;
}

/**
 * After OMJ has been uninstalled the menu application of the device
 * does not display the icons of the old, restored java applications.
 * The icons are shown after the device is booted.
 * Tell menu application to scan again all applications so that the icons
 * will be shown.
 */
static void AddOldJavaAppIconsToMenuApp()
{
    LOG(EJavaConverters, EInfo, "javaappbackconverter: AddOldJavaAppIconsToMenuApp called.");

    TRAPD(err, UseCRKeyToUpdateAppShellDataL());
    if (KErrNotFound == err)
    {
        // Only Nokia XPressMusic 5800 device family supports this feature,
        // N97 and later devices no longer support it but they have new Menu
        // application that shows all Java application icons anyway.
        LOG(EJavaConverters, EInfo,
            "javaappbackconverter: AddOldJavaAppIconsToMenuApp: This device does not "
            "support refreshing Menu using CR keys.");
    }
    else if (KErrNone != err)
    {
        ELOG1(EJavaConverters,
              "javaappbackconverter: AddOldJavaAppIconsToMenuApp: Error: %d", err);
    }
}

/**
 * Kill the running OMJ javaregistry.exe. After killing next call to
 * Registry API restarts the old S60 server process.
 */
static void KillRegistry()
{
    LOG(EJavaConverters, EInfo, "javaappbackconverter: KillRegistry called.");

    TFullName processName;
    _LIT(KJavaRegistryProcess, "javaregistry*");
    TFindProcess finder(KJavaRegistryProcess);

    if (finder.Next(processName) != KErrNotFound)
    {
        RProcess processToKill;
        TInt err = processToKill.Open(finder);

        if (KErrNone != err)
        {
            WLOG1(EJavaConverters, "javaappbackconverter: Process open: %d", err);
        }
        else
        {
            processToKill.Kill(KErrNone);
            processToKill.Close();
        }
    }
    else
    {
        WLOG(EJavaConverters, "javaappbackconverter: Registry process not found");
    }
}

/**
 * Unregister OMJ MIDlet starter, reregister old S60 MIDlet starter
 */
static void ReregisterOldMidletStarter()
{
    LOG(EJavaConverters, EInfo, "javaappbackconverter: ReregisterOldMidletStarter called");

    _LIT(KStubMIDP2RecogExe, "StubMIDP2RecogExe.exe");

    RApaLsSession appLstSession;

    TInt error = appLstSession.Connect();
    if (error != KErrNone)
    {
        ELOG1(EJavaConverters, "javaappbackconverter: ReregisterOldMidletStarter: "
              "RApaLsSession.Connect failed with error %d", error);
        return;
    }
    TRAP(error, appLstSession.RegisterNonNativeApplicationTypeL(
             TUid::Uid(KMidletApplicationTypeUid), KStubMIDP2RecogExe()));
    if (error == KErrNone)
    {
        LOG(EJavaConverters, EInfo, "javaappbackconverter: ReregisterOldMidletStarter: "
            "Registered MIDlet application type for S60 Java.");
    }
    else if (error != KErrAlreadyExists)
    {
        ELOG1(EJavaConverters, "javaappbackconverter: ReregisterOldMidletStarter: "
              "RegisterNonNativeApplicationTypeL failed with error %d", error);
    }
    else
    {
        // OMJ Java has registered MIDlet application type so that it is handled by
        // OMJ binary 'javalauncher.exe', must change that registration
        WLOG(EJavaConverters, "javaappbackconverter: ReregisterOldMidletStarter: "
             "MIDlet application type was registered (by OMJ Java).");
        // Ignore possible error in deregistration
        TRAP(error, appLstSession.DeregisterNonNativeApplicationTypeL(
                 TUid::Uid(KMidletApplicationTypeUid)));
        TRAP(error, appLstSession.RegisterNonNativeApplicationTypeL(
                 TUid::Uid(KMidletApplicationTypeUid), KStubMIDP2RecogExe()));
        if (KErrNone != error)
        {
            ELOG1(EJavaConverters, "javaappbackconverter: ReregisterOldMidletStarter: "
                  "RegisterNonNativeApplicationTypeL failed with error %d", error);
        }
        else
        {
            LOG(EJavaConverters, EInfo, "javaappbackconverter: ReregisterOldMidletStarter: "
                "Registered MIDlet application type again (for S60 Java).");
        }
    }

    appLstSession.Close();
}


/**
 * Show dialog telling that the device must be rebooted
 */
static void showMustRebootDialog()
{
    LOG(EJavaConverters, EInfo, "javaappbackconverter: showMustRebootDialog() Called");

    // Wait for 2 seconds before showing dialog
    User::After(2000000);

    TRAPD(err,
          TRequestStatus status;
          CAknGlobalMsgQuery* globalMsg = CAknGlobalMsgQuery::NewLC();

          // In OMJ 2.x beta .sis uninstallation it is enough to
          // show the text always in english (non-localized)
          _LIT(KJavaPleaseReboot, "To complete the uninstallation process, \
 the phone must be restarted. Until then some applications may not function properly.");

          // tell that device will be rebooted
          globalMsg->ShowMsgQueryL(
              status,
              KJavaPleaseReboot,
              R_AVKON_SOFTKEYS_OK_EMPTY__OK,
              KNullDesC(),
              KNullDesC(),
              0,
              -1,
              CAknQueryDialog::EWarningTone);

          User::WaitForRequest(status);

          CleanupStack::PopAndDestroy(globalMsg);
         );
    if (KErrNone != err)
    {
        ELOG1(EJavaConverters,
              "javaappbackconverter: showMustRebootDialog() TRAP_IGNORE exited with err %d", err);
    }
}


/**
 * Create cleanup stack and run the javaappbackconverter code inside TRAP
 * harness to log unexpected leaves.
 */
TInt E32Main()
{
    CTrapCleanup* pCleanupStack = CTrapCleanup::New();
    if (NULL == pCleanupStack)
    {
        ELOG(EJavaConverters, "javaappbackconverter: Could not create cleanup stack!");
        return KErrNoMemory;
    }

    LOG(EJavaConverters, EInfo, "javaappbackconverter: Starting backconverter");

    // Create file server session
    RFs fs;
    TInt err = fs.Connect();
    if (KErrNone != err)
    {
        ELOG1(EJavaConverters,
              "javaappbackconverter: Cannot open RFs connection. Error %d", err);
        return err;
    }

    // Determine whether backconversion should be done or not.
    // It should be done
    // - if this process has been started when java_2_0.sis is uninstalled
    // OR
    // - if this process has been started when s60_omj_restore_midlets.sis is installed

    // The path name of the loaded executable on which this process is based is
    // 'javaappbackconverter.exe' if this process has been started from java_2_0.sis and
    // 'javaapprestorer.exe' if this process has been started from s60_omj_restore_midlets.sis
    _LIT(KJavaRestorerFileName, "javaapprestorer.exe");
    TBool fStartedFromOmjSis(ETrue);
    RProcess thisProcess;
    TFileName filename = thisProcess.FileName();
    if (filename.Find(KJavaRestorerFileName) > 0)
    {
        LOG(EJavaConverters, EInfo,
            "javaappbackconverter: Started from s60_omj_restore_midlets.sis");
        fStartedFromOmjSis = EFalse;
    }
    LOG1WSTR(EJavaConverters, EInfo,
             "javaappbackconverter: Process file name is %s", (wchar_t *)(filename.PtrZ()));

    // Check whether uninstalling or (installing/upgrading)
    TBool fUninstallingSisPackage(EFalse);
    TInt value(0);
    // Ignore errors, if the value cannot be read, assume 'installing .sis'
    RProperty::Get(KPSUidSWInstallerUiNotification, KSWInstallerUninstallation, value);
    if (0 == value)
    {
        // Native installer is installing (or upgrading) a .sis package
        LOG(EJavaConverters, EInfo, "javaappbackconverter: native installer is installing .sis");
    }
    else
    {
        // Native installer is uninstalling a .sis package
        fUninstallingSisPackage = ETrue;
        LOG(EJavaConverters, EInfo, "javaappbackconverter: native installer is uninstalling .sis");
    }

    if (fUninstallingSisPackage && fStartedFromOmjSis)
    {
        // backconversion must be done
        LOG(EJavaConverters, EInfo, "javaappbackconverter: Going to do backconversion.");
    }
    else if ((!fUninstallingSisPackage) && (!fStartedFromOmjSis))
    {
        // backconversion must be done
        LOG(EJavaConverters, EInfo, "javaappbackconverter: Going to restore midlets.");
    }
    else
    {
        LOG(EJavaConverters, EInfo,
            "javaappbackconverter: Back conversion / restoration is not needed.");
        fs.Close();
        return KErrNone;
    }

    // The only time that this application should be executed
    // is when native installer starts it
    if ((User::CreatorSecureId() != KAppInstUiSecureID) &&
            (User::CreatorSecureId() != KAppSisLauncherSecureID))
    {
        ELOG(EJavaConverters,
             "javaappbackconverter: Mismatch in secure ID, only AppInstUi "
             "or SisLauncher can launch this exe.");
        ELOG1(EJavaConverters,
              "javaappbackconverter: Starter has SID %x ", User::CreatorSecureId().iId);
        fs.Close();
        return KErrPermissionDenied;
    }
    else
    {
        LOG(EJavaConverters, EInfo, "javaappbackconverter: Starter SID was OK.");
    }

    ReregisterOldMidletStarter();

    TInt ret = KErrNone;
    TRAP(ret, ExecuteBackConverterL(fs));
    if (ret != KErrNone)
    {
        ELOG1(EJavaConverters, "javaappbackconverter: ExecuteBackConverterL: Main error %d", ret);
    }

    // Kill OMJ Java Registry process. Next call to Java Registry API starts
    // old S60 Java Registry server
    KillRegistry();

    // Start also old SystemAMS.exe to restore old S60 Java environment to functional state
    RProcess rSystemAms;
    _LIT(KSystemAmsProcess, "SystemAMS.exe");
    _LIT(KEmptyCommandLine, "");
    err = rSystemAms.Create(KSystemAmsProcess, KEmptyCommandLine);
    if (KErrNone == err)
    {
        rSystemAms.Resume();
    }
    else
    {
        WLOG1(EJavaConverters,
              "javaappbackconverter: Starting SystemAMS.exe failed, err %d", err);
    }
    rSystemAms.Close();

    AddOldJavaAppIconsToMenuApp();

    fs.Close();

    if (fUninstallingSisPackage)
    {
        showMustRebootDialog();
    }

    delete pCleanupStack;
    return ret;
}