javamanager/javainstaller/appinstuiplugin/src/javainstalllauncher.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 19 Aug 2010 09:48:13 +0300
branchRCL_3
changeset 24 6c158198356e
parent 14 04becd199f91
child 25 ae942d28ec0e
permissions -rw-r--r--
Revision: v2.2.9 Kit: 201033

/*
* 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:  This file contains the implementation of CJavaInstallLauncher
*               class member functions. ECOM Plugin for native installer.
*
*/


#include <memory>
#include <e32cmn.h>
#include <e32property.h>
#include <charconv.h>
#include <data_caging_path_literals.hrh>
#include <SWInstDefs.h>

#include <CUIUtils.h>
#include <eikenv.h>
#include <SisxUIData.rsg>

#include <javadomainpskeys.h>

#include "javauids.h"
#include "logger.h"
#include "javainstalllauncher.h"
#include "javaoslayer.h"
#include "javaprocessconstants.h"
#include "javasymbianoslayer.h"

using namespace SwiUI;
using namespace Java::Installer;
using namespace java::util;

_LIT(KJavaInstUIResourceFileName, "SisxUIData.rsc");
_LIT(KJavaInstUIResourceDir, "\\Resource\\");
_LIT(KPrivateDataCage, "\\private\\");
_LIT(KInboxDataCage, "\\private\\1000484b\\");
_LIT(KJavaInstallerDataCage, "\\private\\102033e6\\");
_LIT(KJavaInstallerTmp, "\\private\\102033E6\\installer\\tmp\\");
_LIT(KAnyExtension, ".*");


/**
 * This function is called to hide the 'Preparing Installation' dialog
 * from a timer after 7 seconds have elapsed.
 */
LOCAL_C TInt HidePreInstDialog(TAny* aInstallLauncher)
{
    CJavaInstallLauncher *pLauncher = (CJavaInstallLauncher *)aInstallLauncher;
    if (NULL != pLauncher)
    {
        TRAP_IGNORE(pLauncher->HidePreparingInstallationDialogL());
    }
    return KErrNone;
}


// ============================ MEMBER FUNCTIONS ===============================

CJavaInstallLauncher* CJavaInstallLauncher::NewL()
{
    CJavaInstallLauncher* self = new(ELeave) CJavaInstallLauncher();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
}

CJavaInstallLauncher::~CJavaInstallLauncher()
{
    if (iWaitToHideDialog)
    {
        iWaitToHideDialog->Cancel();
        delete iWaitToHideDialog;
        iWaitToHideDialog = NULL;
    }

    if (iCommonDialogs != NULL)
    {
        TRAP_IGNORE(HidePreparingInstallationDialogL());
    }

    if (iEik && iResourceFileOffset)
    {
        iEik->DeleteResourceFile(iResourceFileOffset);
    }
    iRFs.Close();

    TInt nHandles = iHandlesToClose.Count();
    while (nHandles > 0)
    {
        nHandles--;
        iHandlesToClose[nHandles].Close();
    }
    iHandlesToClose.Reset();
}

void CJavaInstallLauncher::InstallL(RFile& aFile, TInstallReq& aInstallParams,
                                    TBool /* aIsDRM */, TRequestStatus& aStatus)
{
    // aIsDRM parameter is ignored because DRM protected .jar files are always
    // passed to Installer
//    JavaOsLayer::startUpTrace("CJavaInstallLauncher::InstallL start", -1, -1);

    // Show preparing installation dialog to user.
    ShowPreparingInstallationDialogL();

    RProcess rJavaInstaller;
    TFileName fileName;
    // Max two path names and some options -> 1536 is enough
    TBuf<1536> commandLine;

    // Build command line used to pass all necessary info to Java Installer
    std::auto_ptr<HBufC> installerStarterDll(
        stringToDes(java::runtime::JAVA_INSTALLER_STARTER_DLL));
    commandLine = installerStarterDll->Des();
    commandLine.Append(_L(" install"));

    TInt err = aFile.FullName(fileName);

    // Java Installer does not have AllFiles capability.
    // So if the .jad/.jar file is in the private data cage of
    // Remove Application Management system, it must be copied
    // to the private data cage of Java Installer in this
    // plugin which is executed in native installer which has
    // AllFiles capability.
    CopyFilesIfNeededL(fileName, aFile);

    if (aInstallParams.iMIME == _L8("text/vnd.sun.j2me.app-descriptor"))
    {
        // installation should be started from JAD file
        commandLine.Append(_L(" -jad="));
    }
    else
    {
        // from JAR file
        commandLine.Append(_L(" -jar="));
    }
    // Filename parameter must be surrounded in double quotes to
    // ensure that spaces in filename are passed correctly.
    commandLine.Append(_L("\""));
    commandLine.Append(fileName);
    commandLine.Append(_L("\""));

    // Find source url. If iSourceURL length is KSWInstHeapPointerLength,
    // iSourceURL contains pointer to URL allocated from heap.
    HBufC* sourceURL= NULL;
    if (aInstallParams.iSourceURL.Length() == KSWInstHeapPointerLength)
    {
        TInstallReqURLPckg urlPckg;
        urlPckg.Copy(aInstallParams.iSourceURL);
        TInstallReqHeapURL heapURL = urlPckg();
        sourceURL = heapURL.iSourcePtr->AllocL();
    }
    else
    {
        sourceURL = aInstallParams.iSourceURL.AllocL();
    }
    // pass also source url
    commandLine.Append(_L(" -sourceurl="));
    commandLine.Append(*sourceURL);
    delete sourceURL;

    commandLine.Append(_L(" -iap="));
    commandLine.AppendNum(aInstallParams.iIAP);

    // Charset is identified by S60 platform Uid,
    // get the Internet-standard name of the charset and
    // pass that to Java Installer
    if (aInstallParams.iCharsetId != 0)
    {
        CCnvCharacterSetConverter *pConverter =
            CCnvCharacterSetConverter::NewL();
        CleanupStack::PushL(pConverter);
        HBufC8* pName =
            pConverter->ConvertCharacterSetIdentifierToStandardNameL(
                aInstallParams.iCharsetId, iRFs);
        CleanupStack::PushL(pName);
        // must convert the 8-bit name to 16-bit
        HBufC16* pLName = Convert(*pName);
        if (pLName)
        {
            commandLine.Append(_L(" -charset="));
            commandLine.Append(*pLName);
        }
        delete pLName;
        CleanupStack::PopAndDestroy(pName);
        CleanupStack::PopAndDestroy(pConverter);
    }

    // start JavaInstaller
    std::auto_ptr<HBufC> installerProcess(
        stringToDes(java::runtime::JAVA_PROCESS));
    err = rJavaInstaller.Create(installerProcess->Des(), commandLine);
    if (KErrNone == err)
    {
        // the exit status of Java Installer will be passed to
        // the asynch caller through aStatus
        rJavaInstaller.Logon(aStatus);
    }
    else
    {
        ELOG1(EJavaInstaller,
              "CJavaInstallLauncher::InstallL: starting JavaInstaller failed, err=%d", err);
        User::Leave(err);
    }

    iWaitToHideDialog = CAsyncWaitCallBack::NewL(TCallBack(HidePreInstDialog, this));
    // The active object will wait until Java Installer process calls Rendezvous.
    // If Java Installer specifies reason code EJavaInstaller, then
    // the active object will call call back function that will hide the
    // 'Preparing installation' dialog. If reason code is not EJavaInstaller,
    // the wait object will automatically wait for the next rendezvous.
    //iWaitToHideDialog->Wait( rJavaInstaller, EJavaInstaller );
    iWaitToHideDialog->Wait(rJavaInstaller, 0);

    rJavaInstaller.Resume();

    // Do NOT close rJavaInstaller now -> the caller gets notification when the
    // process actually closes.
    iHandlesToClose.AppendL(rJavaInstaller);
}

void CJavaInstallLauncher::SilentInstallL(RFile& aFile,
        TInstallReq& aInstallParams, TBool /*aIsDRM*/, TInstallOptions& aOptions,
        TRequestStatus& aStatus)
{
//    JavaOsLayer::startUpTrace("CJavaInstallLauncher::SilentInstallL start", -1, -1);
    // aIsDRM parameter is ignored because DRM protected .jar files are always
    // passed to Installer

    RProcess rJavaInstaller;
    TFileName fileName;
    // Max two path name, user name and password and some options ->
    // 1536 is still enough
    TBuf<1536> commandLine;

    // Build command line used to pass all necessary info to Java Installer
    std::auto_ptr<HBufC> installerStarterDll(
        stringToDes(java::runtime::JAVA_INSTALLER_STARTER_DLL));
    commandLine = installerStarterDll->Des();
    commandLine.Append(_L(" install -silent"));

    TInt err = aFile.FullName(fileName);

    // Java Installer does not have AllFiles capability.
    // So if the .jad/.jar file is in the private data cage of
    // Remove Application Management system, it must be copied
    // to the private data cage of Java Installer in this
    // plugin which is executed in native installer which has
    // AllFiles capability.
    CopyFilesIfNeededL(fileName, aFile);

    if (aInstallParams.iMIME == _L8("text/vnd.sun.j2me.app-descriptor"))
    {
        // installation should be started from JAD file
        commandLine.Append(_L(" -jad="));
    }
    else
    {
        // from JAR file
        commandLine.Append(_L(" -jar="));
    }
    // Filename parameter must be surrounded in double quotes to
    // ensure that spaces in filename are passed correctly.
    commandLine.Append(_L("\""));
    commandLine.Append(fileName);
    commandLine.Append(_L("\""));

    commandLine.Append(_L(" -iap="));
    commandLine.AppendNum(aInstallParams.iIAP);

    // pass also source url
    commandLine.Append(_L(" -sourceurl="));
    commandLine.Append(aInstallParams.iSourceURL);

    // Charset is identified by S60 platform Uid,
    // get the Internet-standard name of the charset and
    // pass that to Java Installer
    if (aInstallParams.iCharsetId != 0)
    {
        CCnvCharacterSetConverter *pConverter =
            CCnvCharacterSetConverter::NewL();
        CleanupStack::PushL(pConverter);
        HBufC8* pName =
            pConverter->ConvertCharacterSetIdentifierToStandardNameL(
                aInstallParams.iCharsetId, iRFs);
        CleanupStack::PushL(pName);
        // must convert the 8-bit name to 16-bit
        HBufC16* pLName = Convert(*pName);
        if (pLName)
        {
            commandLine.Append(_L(" -charset="));
            commandLine.Append(*pLName);
        }
        delete pLName;
        CleanupStack::PopAndDestroy(pName);
        CleanupStack::PopAndDestroy(pConverter);
    }

    // pass also information in aOptions
    if (EPolicyAllowed == aOptions.iUpgrade)
    {
        commandLine.Append(_L(" -upgrade=yes"));
    }
    else
    {
        commandLine.Append(_L(" -upgrade=no"));
    }

    if (EPolicyAllowed == aOptions.iOCSP)
    {
        commandLine.Append(_L(" -ocsp=yes"));
    }
    else
    {
        commandLine.Append(_L(" -ocsp=no"));
    }

    if (EPolicyAllowed == aOptions.iIgnoreOCSPWarnings)
    {
        commandLine.Append(_L(" -ignore_ocsp_warnings=yes"));
    }
    else
    {
        commandLine.Append(_L(" -ignore_ocsp_warnings=no"));
    }

    if (EPolicyAllowed == aOptions.iUntrusted)
    {
        commandLine.Append(_L(" -untrusted=yes"));
    }
    else
    {
        commandLine.Append(_L(" -untrusted=no"));
    }

    if (EPolicyAllowed == aOptions.iOverwrite)
    {
        commandLine.Append(_L(" -overwrite=yes"));
    }
    else
    {
        commandLine.Append(_L(" -overwrite=no"));
    }

    if (EPolicyAllowed == aOptions.iDownload)
    {
        commandLine.Append(_L(" -download=yes"));
    }
    else
    {
        commandLine.Append(_L(" -download=no"));
    }

    if (aOptions.iLogin.Length() > 0)
    {
        commandLine.Append(_L(" -username="));
        commandLine.Append(aOptions.iLogin);
    }

    if (aOptions.iPassword.Length() > 0)
    {
        commandLine.Append(_L(" -password="));
        commandLine.Append(aOptions.iPassword);
    }

    if (aOptions.iDrive > 'C')
    {
        commandLine.Append(_L(" -drive="));
        commandLine.Append(aOptions.iDrive);
    }

    if (EPolicyAllowed == aOptions.iUpgradeData)
    {
        commandLine.Append(_L(" -upgrade_data=yes"));
    }
    else
    {
        commandLine.Append(_L(" -upgrade_data=no"));
    }

    // start JavaInstaller
    std::auto_ptr<HBufC> installerProcess(
        stringToDes(java::runtime::JAVA_PROCESS));
    err = rJavaInstaller.Create(installerProcess->Des(), commandLine);
    if (KErrNone == err)
    {
        // the exit status of Java Installer will be passed to
        // the asynch caller through aStatus
        rJavaInstaller.Logon(aStatus);

        rJavaInstaller.Resume();
    }
    else
    {
        ELOG1(EJavaInstaller,
              "CJavaInstallLauncher::SilentInstallL: starting JavaInstaller failed, err=%d", err);
    }

    // Do NOT close rJavaInstaller now -> the caller gets notification when the
    // process actually closes.
    iHandlesToClose.AppendL(rJavaInstaller);
}

void CJavaInstallLauncher::UninstallL(const TUid& aUid, const TDesC8&, /*aMIME*/
                                      TRequestStatus& aStatus)
{
//    JavaOsLayer::startUpTrace("CJavaInstallLauncher::UninstallL start", -1, -1);
    RProcess rJavaInstaller;
    TFileName fileName;
    // Max one uid and some options -> 256 is enough
    TBuf<256> commandLine;

    // Build command line used to pass all necessary info to Java Installer
    std::auto_ptr<HBufC> installerStarterDll(
        stringToDes(java::runtime::JAVA_INSTALLER_STARTER_DLL));
    commandLine = installerStarterDll->Des();
    commandLine.Append(_L(" uninstall"));

    commandLine.Append(_L(" -uid="));
    commandLine.Append(aUid.Name());

    // start JavaInstaller
    std::auto_ptr<HBufC> installerProcess(
        stringToDes(java::runtime::JAVA_PROCESS));
    TInt err = rJavaInstaller.Create(installerProcess->Des(), commandLine);
    if (KErrNone == err)
    {
        // the exit status of Java Installer will be passed to
        // the asynch caller through aStatus
        rJavaInstaller.Logon(aStatus);

        rJavaInstaller.Resume();
    }
    else
    {
        ELOG1(EJavaInstaller,
              "CJavaInstallLauncher::UninstallL: starting JavaInstaller failed, err=%d", err);
    }

    // Do NOT close rJavaInstaller now -> the caller gets notification when the
    // process actually closes.
    iHandlesToClose.AppendL(rJavaInstaller);
}

void CJavaInstallLauncher::SilentUninstallL(const TUid& aUid, const TDesC8&, /*aMIME*/
        TUninstallOptions& /*aOptions*/, TRequestStatus& aStatus)
{
//    JavaOsLayer::startUpTrace("CJavaInstallLauncher::SilentUninstallL start", -1, -1);
    RProcess rJavaInstaller;
    TFileName fileName;
    // Max one uid and some options -> 256 is enough
    TBuf<256> commandLine;


#ifdef RD_JAVA_S60_RELEASE_5_0_IAD
    // When upgrading Java 2.0 to S60 5.0 devices that already have an older
    // version of Java we have to do one special operation.

    // In old Java environment the PS key that is used to tell how the
    // installation of MIDlet suite proceeds was owned by the native
    // installer (appinstui) process, not by Java Installer.
    // In Java 2.0 environment Java Installer has to own it.

    // We have to destroy the old PS key from this plugin that is loaded and
    // executed by the native installer because the PS key was created so that
    // only the native installer can update and destroy it.
    if (aUid.iUid == KRandomIllegalAppUid)
    {
        // The Uid tells that this is actually request (from javapostupdater.exe)
        // to destroy the PS key.
        LOG(EJavaInstaller, EInfo,
            "CJavaInstallLauncher: SilentUninstallL was called with KRandomIllegalAppUid.");

        TInt err = RProperty::Delete(KUidSystemCategory, KPSUidJavaLatestInstallation);
        if ((err == KErrNone) || (err == KErrNotFound))
        {
            LOG(EJavaInstaller, EInfo,
                "CJavaInstallLauncher: deleted PS key KPSUidJavaLatestInstallation");
            // The caller expects that we leave with cancel status if delete succeeded
            User::Leave(KErrCancel);
        }
        else if (err == KErrPermissionDenied)
        {
            WLOG(EJavaInstaller,
                 "CJavaInstallLauncher: SilentUninstallL: Not owner, so cannot "
                 "delete PS key KPSUidJavaLatestInstallation");
            // It makes no sense to try this again so leave with cancel status
            User::Leave(KErrCancel);
        }
        else
        {
            ELOG1(EJavaInstaller,
                  "CJavaInstallLauncher: SilentUninstallL: Deleting PS key "
                  "KPSUidJavaLatestInstallation error %d", err);
            // Leave with current error code, caller can try deleting PS key again
            User::Leave(err);
        }
    }
#endif

    // Build command line used to pass all necessary info to Java Installer
    std::auto_ptr<HBufC> installerStarterDll(
        stringToDes(java::runtime::JAVA_INSTALLER_STARTER_DLL));
    commandLine = installerStarterDll->Des();
    commandLine.Append(_L(" uninstall -silent"));

    commandLine.Append(_L(" -uid="));
    commandLine.Append(aUid.Name());

    // start JavaInstaller
    std::auto_ptr<HBufC> installerProcess(
        stringToDes(java::runtime::JAVA_PROCESS));
    TInt err = rJavaInstaller.Create(installerProcess->Des(), commandLine);
    if (KErrNone == err)
    {
        // the exit status of Java Installer will be passed to
        // the asynch caller through aStatus
        rJavaInstaller.Logon(aStatus);

        rJavaInstaller.Resume();
    }
    else
    {
        ELOG1(EJavaInstaller,
              "CJavaInstallLauncher::SilentUninstallL: starting JavaInstaller failed, err=%d", err);
    }

    // Do NOT close rJavaInstaller now -> the caller gets notification when the
    // process actually closes.
    iHandlesToClose.AppendL(rJavaInstaller);
}

TBool CJavaInstallLauncher::IsAppShellUpdate()
{
    // All successfull install/uninstall operations cause need to
    // update AppShell.
    // This method has been marked obsolete in SWInstUIPluginAPI.h
    return ETrue;
}

void CJavaInstallLauncher::Cancel()
{
    // Cancel is not supported.
    // Do nothing.
    return;
}

void CJavaInstallLauncher::CompleteL()
{
    // Do nothing. JavaInstaller process has already exited.
}

CErrDetails* CJavaInstallLauncher::GetErrorDetails()
{
    // Java Installer will log the possible errors
    // also in release builds. It will also show detailed error
    // messages in UI in dialog if not in -silent mode
    return NULL;
}

void CJavaInstallLauncher::CustomUninstallL(TOperation, /*aOperation*/
        const TDesC8&, /*aParams*/
        TRequestStatus& /*aStatus*/)
{
    WLOG(EJavaInstaller, "CJavaInstallLauncher: Not supported CustomUninstallL was called.");
    User::Leave(KErrNotSupported);
}

void CJavaInstallLauncher::SilentCustomUninstallL(TOperation, /*aOperation*/
        TUninstallOptions&, /*aOptions*/
        const TDesC8&, /*aParams*/
        TRequestStatus& /*aStatus*/)
{
    WLOG(EJavaInstaller, "CJavaInstallLauncher: Not supported SilentCustomUninstallL was called.");
    User::Leave(KErrNotSupported);
}

CJavaInstallLauncher::CJavaInstallLauncher()
{
}

void CJavaInstallLauncher::ConstructL()
{
    User::LeaveIfError(iRFs.Connect());
    iWaitToHideDialog = NULL;
}

HBufC16* CJavaInstallLauncher::Convert(const TDesC8& aSrc)
{
    if (aSrc.Length() < 1)
    {
        return NULL;
    }

    HBufC16* buf = HBufC16::New(aSrc.Length() + 1);
    if (buf)
    {
        TPtr16 ptr = buf->Des();
        ptr.Copy(aSrc);
        ptr.ZeroTerminate();
    }
    return buf;
}

void CJavaInstallLauncher::OpenUiResourcesL()
{
    // Open UI env and resource file.
    if (!iEik)
    {
        iEik = CEikonEnv::Static();  // codescanner::eikonenvstatic
    }
    if (!iEik)
    {
        ELOG(EJavaInstaller, "CJavaInstallLauncher: CEikonEnv::Static() call returned NULL.");
        User::Leave(KErrGeneral);
    }
    if (!iResourceFileOffset)
    {
        TFileName resourceFileName;
        resourceFileName.Append(KJavaInstUIResourceDir);
        resourceFileName.Append(KJavaInstUIResourceFileName);
        iResourceFileOffset = CommonUI::CUIUtils::LoadResourceFileL(resourceFileName, iEik);
    }
}

void CJavaInstallLauncher::ShowPreparingInstallationDialogL()
{
    // Open UI resources before showing the dialog.
    OpenUiResourcesL();
    // Open wait dialog.
    iCommonDialogs = CommonUI::CCUIDialogs::NewL();
    iCommonDialogs->ShowWaitDialogL(R_SISXUI_PREPARING, this, R_AVKON_SOFTKEYS_EMPTY);
}

void CJavaInstallLauncher::HidePreparingInstallationDialogL()
{
    // Stop further timed calls
    if (iWaitToHideDialog)
    {
        iWaitToHideDialog->Cancel();
    }

    // Close wait dialog.
    if (iCommonDialogs)
    {
        iCommonDialogs->CloseWaitDialogL();
        delete iCommonDialogs;
        iCommonDialogs = NULL;
    }
}

TBool CJavaInstallLauncher::HandleDialogExitL(TInt /*aButtonId*/)
{
    // There is no way to cancel wait dialog, so this method
    // will never be called.
    return ETrue;
}

void CJavaInstallLauncher::CopyFilesIfNeededL(
    TFileName &aFileName,
    RFile& aFile)
{
    // If the file in the private data cage of some process?
    TInt idx = aFileName.FindF(KPrivateDataCage);
    if ((idx != KErrNotFound) && (idx < 3))
    {
        // In case of device Inbox or Java Installer itself do nothing
        if ((aFileName.FindF(KInboxDataCage) != KErrNotFound)
                || (aFileName.FindF(KJavaInstallerDataCage) != KErrNotFound))
        {
            return;
        }

        // The file handle must be shared or copy operation fails
        TInt tmpErr = aFile.ChangeMode(EFileShareReadersOnly);
        if (KErrNone != tmpErr)
        {
            ELOG1(EJavaInstaller,
                  "CJavaInstallLauncher::CopyFilesIfNeededL: "
                  "Err (%d) when changing the mode of the file handle to shared.", tmpErr);
        }


        // Copy ALL files with the same base filename as aFileName
        // to Java Installer tmp dir so that both .jad file and
        // the corresponding .jar file are copied.
        // (aFileName is <path>\<name>.<ext>, copy <path>\<name>.*
        // to Java Installer tmp dir.)
        TParse fp;
        iRFs.Parse(aFileName, fp);

        CFileMan* fm = CFileMan::NewL(iRFs);
        TFileName filesToCopy = fp.DriveAndPath();
        filesToCopy.Append(fp.Name());
        filesToCopy.Append(KAnyExtension);

        TInt err = fm->Copy(
                       filesToCopy, KJavaInstallerTmp, CFileMan::ERecurse | CFileMan::EOverWrite);
        delete fm;
        if (KErrNone != err)
        {
            ELOG1(EJavaInstaller,
                  "CJavaInstallLauncher::CopyFilesIfNeededL: err (%d), copying files "
                  "to Java Installer data cage failed", err);
            User::Leave(err);
        }

        // aFileName must point to the copy of the file
        aFileName = fp.Drive();
        aFileName.Append(KJavaInstallerTmp);
        aFileName.Append(fp.NameAndExt());
    }

    return;
}

//  End of File