javamanager/javacaptain/extensionplugins/scrupdater/src/scrupdater.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 23 Jun 2010 18:07:10 +0300
changeset 47 f40128debb5d
child 48 e0d6e9bd3ca7
permissions -rw-r--r--
Revision: v2.2.2 Kit: 2010125

/*
* Copyright (c) 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:  ScrUpdater is Java Captain Symbian plugin that updates
*               presence information of Java Applications in USIF SCR
*               when removable drive is added or removed to the device.
*
*/

#include <apgcli.h>
#include <e32base.h>
#include <f32file.h>

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

#include "scrupdater.h"

using namespace Usif;

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

namespace java
{
namespace captain
{

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

/**
 * Empty contructor
 */
ScrUpdater::ScrUpdater() : mCore(0)
{
}

/**
 * Empty destructor
 */
ScrUpdater::~ScrUpdater()
{
}

/**
 * Implement PluginInterface method
 */
void ScrUpdater::startPlugin(CoreInterface* core)
{
    LOG(EJavaCaptain, EInfo, "ScrUpdater plugin started");

    mCore = core;
}

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

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

/**
 * Handle Java Captain events sent by Boot event provider or
 * MMC event provider.
 *
 * Implement EventConsumerInterface method
 */
void ScrUpdater::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,
            "ScrUpdater::event() boot event received (type=%d)",
            bootType);
        switch (bootType)
        {
            case IAD_BOOT_C:
            case FIRST_DEVICE_BOOT_C:
            case NORMAL_BOOT_C:
            {
                // Update presence information
                TRAPD(err, initializeScrPresenceInfoL())
                if (KErrNone != err)
                {
                    ELOG1(EJavaCaptain, "initializeScrPresenceInfoL: leaved (%d)", err);
                }
            }
            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,
            "ScrUpdater::event() mmc event received (operation=%d)",
            operation);

        switch (operation)
        {
            case DriveListenerInterface::REMOVABLE_MEDIA_REMOVED_C:
            {
                // All Java applications in the removed drive are set
                // to 'not present' state
                TRAPD(err, removeScrPresencesL(&di));
                if (KErrNone != err)
                {
                    ELOG1(EJavaCaptain, "removeScrPresencesL leaved (%d)", err);
                }
            }
            break;

            case DriveListenerInterface::REMOVABLE_MEDIA_INSERTED_C:
            {
                // Those Java applications in the drive to where the media
                // (e.g. memory card) was added are set to 'present' state
                // IF the media id is correct (in other words if the same
                // memory card that they have been installed to is added
                // to the drive).
                TRAPD(err, addScrPresencesL(&di));
                if (KErrNone != err)
                {
                    ELOG1(EJavaCaptain, "addScrPresencesL leaved (%d)", err);
                }
            }
            break;
        }
    }
}

/**
 * Set the presence state of all Java applications installed
 * to the removable drive specified in aInfo to not present
 */
void ScrUpdater::removeScrPresencesL(driveInfo *aInfo)
{
    __UHEAP_MARK;
    LOG1WSTR(EJavaCaptain, EInfo,
        "removeScrPresencesL: driveInfo root path is %s", aInfo->iRootPath);

    RSoftwareComponentRegistry *pScr = createScrL();
    CleanupStack::PushL(pScr);

    // Get ids of all Java components in scr
    RArray<TComponentId> componentIdList;
    CComponentFilter *pJavaSwTypeFilter = CComponentFilter::NewLC();
    pJavaSwTypeFilter->SetSoftwareTypeL(Usif::KSoftwareTypeJava);

    pScr->GetComponentIdsL(componentIdList, pJavaSwTypeFilter);
    CleanupStack::PopAndDestroy(pJavaSwTypeFilter);
    CleanupClosePushL(componentIdList);

    // For each component check whether it has been installed
    // to the removed drive
    TInt  nComponents = componentIdList.Count();
    TUint removedDrive = (TUint)(aInfo->iRootPath[0]);
    // Now removedDrive contains the drive letter, convert it to drive number 0-25
    if ((removedDrive > 64) && (removedDrive < 91))
    {
        // 'A' - 'Z'
        removedDrive -= 65;
    }
    else if ((removedDrive > 96) && (removedDrive < 123))
    {
        // 'a' - 'z'
        removedDrive -= 97;
    }
    else
    {
        ELOG1WSTR(EJavaCaptain,
            "removeScrPresencesL: Unexpected root path in remove drive info %s",
            aInfo->iRootPath);
        CleanupStack::PopAndDestroy(pScr);
        return;
    }

    LOG2(EJavaCaptain, EInfo, "Number of Java components is %d, removed drive is %d",
        nComponents, removedDrive);

    TBool fPresenceChange = EFalse;
    RArray<TApaAppUpdateInfo> removedApps;
    CleanupClosePushL(removedApps);

    for (TInt nInd = 0; nInd < nComponents; nInd++)
    {
        CComponentEntry *pEntry = CComponentEntry::NewLC();
        if (!(pScr->GetComponentL(componentIdList[nInd], *pEntry)))
        {
            ELOG1(EJavaCaptain,
                "removeScrPresencesL: SCR GetComponentIdsL returned id %d "
                "but GetComponentL does not find it", componentIdList[nInd]);
            CleanupStack::PopAndDestroy(pEntry);
            continue;
        }

        TInt nInstalledDrives = pEntry->InstalledDrives().Length();
        if (nInstalledDrives <= removedDrive)
        {
            // SCR InstalledDrives should be array of 26 elements (value 0 or 1)
            ELOG2(EJavaCaptain,
                "removeScrPresencesL: The length of InstalledDrives array (%d) "
                "is smaller than removedDrive (%d)", nInstalledDrives, removedDrive);
            CleanupStack::PopAndDestroy(pEntry);
            continue;
        }

        LOG1(EJavaCaptain, EInfo, "Java component id %d", componentIdList[nInd]);

        if (pEntry->InstalledDrives()[removedDrive])
        {
            // This component has been installed to the drive
            // that has just been removed
            pScr->SetIsComponentPresentL(componentIdList[nInd], EFalse);

            LOG1(EJavaCaptain, EInfo,
                "removeScrPresencesL: set component %d to not present",
                componentIdList[nInd]);

            fPresenceChange = ETrue;

            // Gather the Uids of all applications that are no longer present
            RArray<TUid> appsInComponent;
            CleanupClosePushL(appsInComponent);
            pScr->GetAppUidsForComponentL(
                componentIdList[nInd], appsInComponent);
            for (TInt nInd2 = 0; nInd2 < appsInComponent.Count(); nInd2++)
            {
                TApaAppUpdateInfo appInfo;
                appInfo.iAppUid = appsInComponent[nInd2];
                appInfo.iAction = TApaAppUpdateInfo::EAppNotPresent;
                (void)removedApps.Append(appInfo);
            }
            CleanupStack::PopAndDestroy(&appsInComponent);
        }

        CleanupStack::PopAndDestroy(pEntry);
    }

    // Tell AppArc which applications are no longer present
    while (fPresenceChange)
    {
        if (removedApps.Count() == 0)
        {
            ELOG(EJavaCaptain, "removeScrPresencesL: Uids of the removed apps are not known");
            break;
        }

        RApaLsSession apaSession;
        TInt err = apaSession.Connect();
        if (KErrNone != err)
        {
            ELOG1(EJavaCaptain, "removeScrPresencesL: Error %d when connecting AppArc", err);
            break;
        }
        else
        {
            CleanupClosePushL(apaSession);
            apaSession.UpdateAppListL(removedApps);
            CleanupStack::PopAndDestroy(); // closes apaSession
            fPresenceChange = EFalse;
        }
    }

    CleanupStack::PopAndDestroy(); // Close removedApps
    CleanupStack::PopAndDestroy(); // Close componentIdList
    CleanupStack::PopAndDestroy(pScr);
    __UHEAP_MARKEND;
}


/**
 * Set the presence state of all Java applications installed
 * to the removable drive specified in aInfo to present
 */
void ScrUpdater::addScrPresencesL(driveInfo *aInfo)
{
    __UHEAP_MARK;
    LOG1WSTR(EJavaCaptain, EInfo,
        "addScrPresencesL: driveInfo root path is %s", aInfo->iRootPath);

    RSoftwareComponentRegistry *pScr = createScrL();
    CleanupStack::PushL(pScr);

    // Get ids of all Java components in scr
    RArray<TComponentId> componentIdList;
    CComponentFilter *pJavaSwTypeFilter = CComponentFilter::NewLC();
    pJavaSwTypeFilter->SetSoftwareTypeL(Usif::KSoftwareTypeJava);

    pScr->GetComponentIdsL(componentIdList, pJavaSwTypeFilter);
    CleanupStack::PopAndDestroy(pJavaSwTypeFilter);
    CleanupClosePushL(componentIdList);

    // For each component check whether it has been installed
    // to the added drive AND whether the media id is correct
    // (in other words if the actual memory card where the component
    // has been installed to is added to the drive).
    TInt  nComponents  = componentIdList.Count();
    TUint addedMediaId = (TUint)(aInfo->iId);
    TUint addedDrive   = (TUint)(aInfo->iRootPath[0]);
    // Now addedDrive contains the drive letter, convert it to drive number 0-25
    if ((addedDrive > 64) && (addedDrive < 91))
    {
        // 'A' - 'Z'
        addedDrive -= 65;
    }
    else if ((addedDrive > 96) && (addedDrive < 123))
    {
        // 'a' - 'z'
        addedDrive -= 97;
    }
    else
    {
        ELOG1WSTR(EJavaCaptain,
            "addScrPresencesL: Unexpected root path in add drive info %s",
            aInfo->iRootPath);
        CleanupStack::PopAndDestroy(pScr);
        return;
    }

    LOG2(EJavaCaptain, EInfo, "Number of Java components is %d, added drive is %d",
        nComponents, addedDrive);

    TBool fPresenceChange = EFalse;
    RArray<TApaAppUpdateInfo> addedApps;
    CleanupClosePushL(addedApps);

    for (TInt nInd = 0; nInd < nComponents; nInd++)
    {
        CComponentEntry *pEntry = CComponentEntry::NewLC();
        if (!(pScr->GetComponentL(componentIdList[nInd], *pEntry)))
        {
            ELOG1(EJavaCaptain,
                "addScrPresencesL: SCR GetComponentIdsL returned id %d "
                "but GetComponentL does not find it", componentIdList[nInd]);
            CleanupStack::PopAndDestroy(pEntry);
            continue;
        }

        // When Java Installer registers Java app to SCR it stores also
        // the media id using SetComponentPropertyL(TComponentId aComponentId,
        // _L("Media-Id")), TInt64 aValue);  (aValue is actually 32 bit int)
        CIntPropertyEntry* pMediaIdProperty = (CIntPropertyEntry *)
            pScr->GetComponentPropertyL(componentIdList[nInd],_L("Media-Id"));
        if (NULL == pMediaIdProperty)
        {
            ELOG1(EJavaCaptain,
                "addScrPresencesL: media_id property not found for component %d",
                componentIdList[nInd]);
            CleanupStack::PopAndDestroy(pEntry);
            continue;
        }
        CleanupStack::PushL(pMediaIdProperty);

        TInt nInstalledDrives = pEntry->InstalledDrives().Length();
        if (nInstalledDrives <= addedDrive)
        {
            // SCR InstalledDrives should be array of 26 elements (value 0 or 1)
            ELOG2(EJavaCaptain,
                "addScrPresencesL: The length of InstalledDrives array (%d) "
                "is smaller than addedDrive (%d)", nInstalledDrives, addedDrive);
            CleanupStack::PopAndDestroy(pEntry);
            continue;
        }

        LOG1(EJavaCaptain, EInfo, "Java component id %d", componentIdList[nInd]);

        if (pEntry->InstalledDrives()[addedDrive])
        {
            // This component has been installed to the drive
            // that has just been added.
            // Now check whether the media id of the added media
            // is OK for this component.
            if (addedMediaId == pMediaIdProperty->IntValue())
            {
                pScr->SetIsComponentPresentL(componentIdList[nInd], ETrue);

                LOG1(EJavaCaptain, EInfo,
                    "addScrPresencesL: set component %d to present",
                    componentIdList[nInd]);

                fPresenceChange = ETrue;

                // Gather the Uids of all 'new' applications that are now present
                RArray<TUid> appsInComponent;
                CleanupClosePushL(appsInComponent);
                pScr->GetAppUidsForComponentL(
                    componentIdList[nInd], appsInComponent);
                for (TInt nInd2 = 0; nInd2 < appsInComponent.Count(); nInd2++)
                {
                    TApaAppUpdateInfo appInfo;
                    appInfo.iAppUid = appsInComponent[nInd2];
                    appInfo.iAction = TApaAppUpdateInfo::EAppPresent;
                    (void)addedApps.Append(appInfo);
                }
                CleanupStack::PopAndDestroy(&appsInComponent);
            }
        }

        CleanupStack::PopAndDestroy(pMediaIdProperty);
        CleanupStack::PopAndDestroy(pEntry);
    }

    // Tell AppArc which 'new' applications are now present
    while (fPresenceChange)
    {
        if (addedApps.Count() == 0)
        {
            ELOG(EJavaCaptain, "addScrPresencesL: Uids of the 'new' apps are not known");
            break;
        }

        RApaLsSession apaSession;
        TInt err = apaSession.Connect();
        if (KErrNone != err)
        {
            ELOG1(EJavaCaptain, "addScrPresencesL: Error %d when connecting AppArc", err);
            break;
        }
        else
        {
            CleanupClosePushL(apaSession);
            apaSession.UpdateAppListL(addedApps);
            CleanupStack::PopAndDestroy(); // closes apaSession
            fPresenceChange = EFalse;
        }
    }

    CleanupStack::PopAndDestroy(); // Close addedApps
    CleanupStack::PopAndDestroy(); // Close componentIdList
    CleanupStack::PopAndDestroy(pScr);
    __UHEAP_MARKEND;
}


/**
 * Loop through all removable drives and get the media id of
 * the memory card or other removable media in the drive and update
 * presence information of all Java applications installed
 * to removable drives accordingly.
 */
void ScrUpdater::initializeScrPresenceInfoL()
{
    __UHEAP_MARK;
    RFs fs;
    User::LeaveIfError(fs.Connect());
    CleanupClosePushL(fs);

    // Which drives are present and what is the media id of
    // each removable volume
    TInt  err = KErrNone;
    TInt  err2 = KErrNone;
    TBool drivePresent[EDriveZ + 1];
    TUint driveMediaId[EDriveZ + 1];
    TVolumeInfo volumeInfo;
    TDriveInfo  driveInfo;

    for (TInt nInd = EDriveA; nInd < EDriveZ; nInd++)
    {
        err = fs.Volume(volumeInfo, nInd);
        if (KErrNone == err)
        {
            drivePresent[nInd] = ETrue;
            driveMediaId[nInd] = volumeInfo.iUniqueID;
            // If the media is not removable, media id is not checked
            err2 = fs.Drive(driveInfo, nInd);
            if (KErrNone != err2)
            {
                ELOG1(EJavaCaptain,
                    "initializeScrPresenceInfoL: error (%d) when trying to get drive info",
                    err2);
                User::Leave(err2);
            }
            else
            {
                if (!(driveInfo.iDriveAtt & KDriveAttRemovable))
                {
                    driveMediaId[nInd] = 0;
                }
            }
        }
        else if (KErrNotReady == err)
        {
            // no volume in this drive
            drivePresent[nInd] = EFalse;
            driveMediaId[nInd] = 0;
        }
        else
        {
            ELOG1(EJavaCaptain,
                "initializeScrPresenceInfoL: error (%d) when trying to get volume info",
                err);
            User::Leave(err);
        }
    }
    CleanupStack::PopAndDestroy(); // close RFs


    RSoftwareComponentRegistry *pScr = createScrL();
    CleanupStack::PushL(pScr);

    // Get ids of all Java components in scr
    RArray<TComponentId> componentIdList;
    CComponentFilter *pJavaSwTypeFilter = CComponentFilter::NewLC();
    pJavaSwTypeFilter->SetSoftwareTypeL(Usif::KSoftwareTypeJava);

    pScr->GetComponentIdsL(componentIdList, pJavaSwTypeFilter);
    CleanupStack::PopAndDestroy(pJavaSwTypeFilter);
    CleanupClosePushL(componentIdList);

    // For each component check whether the drive it has been installed
    // to is present AND whether the media id is correct
    TInt  nComponents  = componentIdList.Count();

    LOG1(EJavaCaptain, EInfo, "initializeScrPresenceInfoL: Number of Java components is %d",
        nComponents);

    for (TInt nInd = 0; nInd < nComponents; nInd++)
    {
        CComponentEntry *pEntry = CComponentEntry::NewLC();
        if (!(pScr->GetComponentL(componentIdList[nInd], *pEntry)))
        {
            ELOG1(EJavaCaptain,
                "initializeScrPresenceInfoL: SCR GetComponentIdsL returned id %d "
                "but GetComponentL does not find it", componentIdList[nInd]);
            CleanupStack::PopAndDestroy(pEntry);
            continue;
        }

        CIntPropertyEntry* pMediaIdProperty = (CIntPropertyEntry *)
            pScr->GetComponentPropertyL(componentIdList[nInd],_L("Media-Id"));
        if (NULL == pMediaIdProperty)
        {
            ELOG1(EJavaCaptain,
                "initializeScrPresenceInfoL: media_id property not found for component %d",
                componentIdList[nInd]);
            CleanupStack::PopAndDestroy(pEntry);
            continue;
        }
        CleanupStack::PushL(pMediaIdProperty);

        TInt nInstalledDrives = pEntry->InstalledDrives().Length();
        if (nInstalledDrives > (EDriveZ + 1))
        {
            WLOG2(EJavaCaptain,
                "initializeScrPresenceInfoL: too big (%d) installed drives array for "
                "component %d", nInstalledDrives, componentIdList[nInd]);
            nInstalledDrives = EDriveZ;
        }
        // When Java components are installed, only one installed drive
        // and corresponding media id are registered.
        TInt installationDrive = -1;

        for (TInt driveNumber = EDriveA; driveNumber < nInstalledDrives; driveNumber++)
        {
            if (pEntry->InstalledDrives()[driveNumber])
            {
                installationDrive = driveNumber;
                break;
            }
        }

        if (installationDrive == -1)
        {
            ELOG1(EJavaCaptain,
                "initializeScrPresenceInfoL: component (id %d) did not have installed drive info",
                componentIdList[nInd]);
            CleanupStack::PopAndDestroy(pMediaIdProperty);
            CleanupStack::PopAndDestroy(pEntry);
            continue;
        }

        if (drivePresent[installationDrive])
        {
            // Check also the media id
            if (driveMediaId[installationDrive] == pMediaIdProperty->IntValue())
            {
                LOG1(EJavaCaptain, EInfo,
                    "initializeScrPresenceInfoL: set component %d to present",
                    componentIdList[nInd]);

                pScr->SetIsComponentPresentL(componentIdList[nInd], ETrue);
            }
            else
            {
                LOG1(EJavaCaptain, EInfo,
                    "initializeScrPresenceInfoL: set component %d to NOT present",
                    componentIdList[nInd]);

                pScr->SetIsComponentPresentL(componentIdList[nInd], EFalse);
            }
        }
        else
        {
            LOG1(EJavaCaptain, EInfo,
                "initializeScrPresenceInfoL: set component %d to NOT present",
                componentIdList[nInd]);

            // drive is not present -> Java component installed to that
            // drive is not present
            pScr->SetIsComponentPresentL(componentIdList[nInd], EFalse);
        }

        CleanupStack::PopAndDestroy(pMediaIdProperty);
        CleanupStack::PopAndDestroy(pEntry);
    }

    CleanupStack::PopAndDestroy(); // Close componentIdList
    CleanupStack::PopAndDestroy(pScr); // Also closes RSoftwareComponentRegistry

    __UHEAP_MARKEND;
}


/**
 * Creates an instance of RSoftwareComponentRegistry and connects to it.
 */
RSoftwareComponentRegistry *ScrUpdater::createScrL()
{
    RSoftwareComponentRegistry *pScr = new RSoftwareComponentRegistry;
    if (NULL == pScr)
    {
        ELOG(EJavaInstaller,
            "CreateScrL: Creating RSoftwareComponentRegistry failed");
        User::Leave(KErrGeneral);
    }
    TInt err = pScr->Connect();
    if (KErrNone != err)
    {
        ELOG1(EJavaInstaller,
            "CreateScrL: Connecting to RSoftwareComponentRegistry failed, error %d",
            err);
        delete pScr;
        User::Leave(err);
    }

    return pScr;
}


} // namespace captain
} // namespace java