appinstaller/AppinstUi/startuplistupdater/src/startuplistupdater.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 02 Sep 2010 20:34:03 +0300
changeset 67 3a625661d1ce
parent 37 6e7b00453237
child 80 9dcba1ee99f7
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* 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:  Startup list updater implementation.
*
*/

#include "startuplistupdater.h"         // CStartupListUpdater
#include "cleanupresetanddestroy.h"     // CleanupResetAndDestroyPushL
#include <featmgr.h>                    // FeatureManager
#include <driveinfo.h>                  // DriveInfo
#include <barsc.h>                      // RResourceFile
#include <barsread.h>                   // TResourceReader
#include <StartupItem.hrh>              // EStartupItemExPolicyNone
#include <dscitem.h>                    // CDscItem
#include <swi/sisregistrysession.h>     // Swi::RSisRegistrySession
#include <swi/sisregistrypackage.h>     // Swi::CSisRegistryPackage
#include <swi/sisregistryentry.h>       // Swi::RSisRegistryEntry
#include <swi/sistruststatus.h>         // Swi::TSisTrustStatus::IsTrusted

_LIT( KImport, "import\\" );
_LIT( KDriveAndPathFormat, "%c:%S" );
_LIT( KResourceFileSpec, "c:*.rsc" );
_LIT( KExecutableExtension, ".exe" );
_LIT( KAsterisk, "*" );

const TInt KDriveSpecLength = 2;
const TInt KFirstStartupItemInfo = 1;


// ======== LOCAL FUNCTIONS ========

// ---------------------------------------------------------------------------
// FileNamesEqual()
// ---------------------------------------------------------------------------
//
TBool FileNamesEqual( const HBufC& aFile1, const HBufC& aFile2 )
    {
    return ( aFile1.CompareF( aFile2 ) == 0 );
    }


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

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

// ---------------------------------------------------------------------------
// CStartupListUpdater::~CStartupListUpdater()
// ---------------------------------------------------------------------------
//
CStartupListUpdater::~CStartupListUpdater()
    {
    delete iPrivateImportPath;
    iFs.Close();

    FeatureManager::UnInitializeLib();
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::UpdateStartupListL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::UpdateStartupListL()
    {
    if ( FeatureManager::FeatureSupported( KFeatureIdExtendedStartup ) )
        {
        ProcessImportsAndUninstallsL();
        }
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::CStartupListUpdater()
// ---------------------------------------------------------------------------
//
CStartupListUpdater::CStartupListUpdater()
    {
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::ConstructL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::ConstructL()
    {
    FeatureManager::InitializeLibL();
    User::LeaveIfError( iFs.Connect() );

    TInt err = iFs.MkDirAll( PrivateImportPathL() );
    if( err != KErrNone && err != KErrAlreadyExists )
        {
        User::Leave( err );
        }
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::PrivateImportPathL()
// ---------------------------------------------------------------------------
//
const TDesC& CStartupListUpdater::PrivateImportPathL()
    {
    if( !iPrivateImportPath )
        {
        TFileName privateImportPath;
        User::LeaveIfError( iFs.PrivatePath( privateImportPath ) );
        privateImportPath.Append( KImport );

        TInt driveNumber;
        TInt err = DriveInfo::GetDefaultDrive( DriveInfo::EDefaultSystem, driveNumber );
        User::LeaveIfError( err );
        TChar driveLetter;
        User::LeaveIfError( RFs::DriveToChar( driveNumber, driveLetter ) );

        iPrivateImportPath = HBufC::NewL( KDriveSpecLength + privateImportPath.Length() );
        TPtr ptr( iPrivateImportPath->Des() );
        ptr.Format( KDriveAndPathFormat, static_cast< TUint >( driveLetter ), &privateImportPath );
        }
    return *iPrivateImportPath;
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::ProcessImportsAndUninstallsL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::ProcessImportsAndUninstallsL()
    {
    RDscStore dscStore;
    OpenDscStoreLC( dscStore );

    ImportNewResourceFilesL( dscStore );
    DeregisterUninstalledAppsL( dscStore );

    CleanupStack::PopAndDestroy( &dscStore );
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::OpenDscStoreLC()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::OpenDscStoreLC( RDscStore& aDscStore )
    {
    if( !aDscStore.IsOpened() )
        {
        aDscStore.OpenL();
        CleanupClosePushL( aDscStore );
        if( !aDscStore.DscExistsL() )
            {
            aDscStore.CreateDscL();
            }
        }
    else
        {
        User::Leave( KErrAlreadyExists );
        }
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::ImportNewResourceFilesL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::ImportNewResourceFilesL( RDscStore& aDscStore )
    {
    RPointerArray<HBufC> executableArray;
    CleanupResetAndDestroyPushL( executableArray );
    RPointerArray<HBufC> resourceFileArray;
    CleanupResetAndDestroyPushL( resourceFileArray );

    GetDataToBeImportedL( executableArray, resourceFileArray );
    ImportExecutablesL( aDscStore, executableArray );
    RemoveImportedResourceFiles( resourceFileArray );

    CleanupStack::PopAndDestroy( 2, &executableArray );
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::DeregisterUninstalledAppsL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::DeregisterUninstalledAppsL( RDscStore& aDscStore )
    {
    RPointerArray<HBufC> startedAtBootArray;
    CleanupResetAndDestroyPushL( startedAtBootArray );
    RPointerArray<HBufC> installedArray;
    CleanupResetAndDestroyPushL( installedArray );
    RPointerArray<HBufC> startedNotInstalled;
    CleanupResetAndDestroyPushL( startedNotInstalled );

    GetStartupListAppsL( aDscStore, startedAtBootArray );
    GetInstalledAppsL( installedArray );
    StartedButNotInstalledAppsL( startedAtBootArray, installedArray, startedNotInstalled );
    RemoveFromStartupListL( aDscStore, startedNotInstalled );

    CleanupStack::PopAndDestroy( 3, &startedAtBootArray );
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::GetDataToBeImportedL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::GetDataToBeImportedL(
        RPointerArray<HBufC>& aExecutableArray,
        RPointerArray<HBufC>& aResourceFileArray )
    {
    TParse resourceFiles;
    User::LeaveIfError( resourceFiles.Set( KResourceFileSpec, &PrivateImportPathL(), NULL ) );
    const TPtrC importDir( resourceFiles.FullName() );

    CDir* dir;
    User::LeaveIfError( iFs.GetDir( importDir, KEntryAttMaskSupported, ESortNone, dir ) );
    CleanupStack::PushL( dir );
    for( TInt index = 0; index < dir->Count(); ++index )
        {
        TFileName resourceFile;
        TInt lastSeparator = importDir.LocateReverse( '\\' );
        if( lastSeparator > 0 )
            {
            resourceFile.Copy( importDir.Mid( 0, lastSeparator + 1 ) );
            resourceFile.Append( ( *dir )[ index ].iName );
            aResourceFileArray.AppendL( resourceFile.AllocL() );

            AppendExecutablesFromResourceFileL( resourceFile, aExecutableArray );
            }
        }
    CleanupStack::PopAndDestroy( dir );
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::ImportExecutablesL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::ImportExecutablesL( RDscStore& aDscStore,
        RPointerArray<HBufC>& aExecutableArray )
    {
    for( TInt index = 0; index < aExecutableArray.Count(); ++index )
        {
        const TDesC& executableName = *( aExecutableArray[ index ] );
        CDscItem* item = CDscItem::NewLC( executableName, KNullDesC );
        if( !aDscStore.ItemExistsL( *item ) )
            {
            aDscStore.AddItemL( *item );
            }
        CleanupStack::PopAndDestroy( item );
        }
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::RemoveImportedResourceFiles()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::RemoveImportedResourceFiles(
        RPointerArray<HBufC>& aResourceFileArray )
    {
    for( TInt index = 0; index < aResourceFileArray.Count(); ++index )
        {
        const TDesC& fileName = *( aResourceFileArray[ index ] );
        TInt err = iFs.Delete( fileName );
        if( err )
            {
#ifdef _DEBUG
            RDebug::Print( _L("CStartupListUpdater: cannot delete %S, error %d"),
                    &fileName, err );
#endif
            }
        }
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::AppendExecutablesFromResourceFileL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::AppendExecutablesFromResourceFileL(
        const TDesC& aResourceFile,
        RPointerArray<HBufC>& aExecutableArray )
    {
    RResourceFile resource;
    CleanupClosePushL( resource );
    resource.OpenL( iFs, aResourceFile );

    for( TInt id = KFirstStartupItemInfo; resource.OwnsResourceId( id ); ++id )
        {
        HBufC8* buffer = resource.AllocReadLC( id );

        TResourceReader reader;
        reader.SetBuffer( buffer );

        // Read STARTUP_ITEM_INFO
        TInt versionInfo = reader.ReadUint8();
        TFileName executableName;
        executableName.Copy( reader.ReadTPtrC() );
        TInt recoveryPolicy = reader.ReadUint16();

        CleanupStack::PopAndDestroy( buffer );

        if( versionInfo == 0 && recoveryPolicy == EStartupItemExPolicyNone )
            {
            // PKG files use '!' for drive letters that user can decide at installation time
            if( executableName.Length() > 0 && executableName[ 0 ] == '!' )
                {
                executableName.Replace( 0, 1, KAsterisk );

                TFindFile fileFinder( iFs );
                CDir* executableDir;            // next FindWildByDir needs AllFiles capability
                TInt err = fileFinder.FindWildByDir( executableName, KNullDesC, executableDir );
                if( !err )
                    {
                    CleanupStack::PushL( executableDir );
                    executableName.Replace( 0, 1, fileFinder.File() );
                    CleanupStack::PopAndDestroy( executableDir );
                    }
                }

            if( IsValidExecutableForStartupL( aResourceFile, executableName ) )
                {
                aExecutableArray.AppendL( executableName.AllocL() );
                }
            }
        }

    CleanupStack::PopAndDestroy( &resource );
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::IsValidExecutableForStartupL()
// ---------------------------------------------------------------------------
//
TBool CStartupListUpdater::IsValidExecutableForStartupL( const TDesC& aResourceFile,
        const TDesC& aExecutableName )
    {
    TBool isValid = EFalse;

    TEntry entry;
    if( iFs.Entry( aExecutableName, entry ) == KErrNone )   // needs AllFiles capability
        {
        isValid = ETrue;

        // Extract package UID from the resource file name
        // - allow both "[1234ABCD]" and "1234ABCD" formats
        // - allow possible "0x" prefix too
        TUid packageUid = KNullUid;
        TParsePtrC parse( aResourceFile );
        TPtrC parseName = parse.Name();
        TInt fileNameLength = parseName.Length();
        if( !parse.IsNameWild() && fileNameLength > 0 )
            {
            TPtr fileName( const_cast<TUint16*>( parseName.Ptr() ),
                fileNameLength, fileNameLength );

            if( fileName[ 0 ] == '[' && fileName[ fileNameLength - 1 ] == ']' )
                {
                const TInt KTwoCharsLength = 2;
                fileNameLength -= KTwoCharsLength;
                fileName = fileName.Mid( 1, fileNameLength );
                }

            _LIT( KHexPrefix, "0x" );
            const TInt KHexPrefixLength = 2;
            if( fileName.Left( KHexPrefixLength ) == KHexPrefix )
                {
                fileNameLength -= KHexPrefixLength;
                fileName = fileName.Mid( KHexPrefixLength, fileNameLength );
                }

            TLex lex( fileName );
            TUint32 uidValue = 0;
            TInt lexError = lex.Val( uidValue, EHex );
            if( !lexError )
                {
                packageUid.iUid = uidValue;
                }
            }

        // Get package info from RSisRegistry, and check that
        // - the package contains the resource file
        // - the package is properly signed
        if( packageUid != KNullUid )
            {
            Swi::RSisRegistrySession sisRegSession;
            User::LeaveIfError( sisRegSession.Connect() );
            CleanupClosePushL( sisRegSession );

            Swi::RSisRegistryEntry package;
            CleanupClosePushL( package );
            TInt openError = package.Open( sisRegSession, packageUid );
            if( !openError )
                {
                TBool hasResourceFile = EFalse;

                RPointerArray<HBufC> files;
                CleanupResetAndDestroyPushL( files );
                package.FilesL( files );
                for( TInt index = 0; index < files.Count() && !hasResourceFile; ++index )
                    {
                    hasResourceFile = ( aResourceFile.CompareF( *files[ index ] ) == 0 );
                    }

                if( hasResourceFile && package.TrustStatusL().IsTrusted() )
                    {
                    isValid = ETrue;
                    }

                CleanupStack::PopAndDestroy( &files );
                }

            CleanupStack::PopAndDestroy( 2, &sisRegSession );  // package, sisRegSession
            }
        }

    return isValid;
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::GetInstalledAppsL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::GetInstalledAppsL(
        RPointerArray<HBufC>& aInstalledExecutableArray )
    {
    Swi::RSisRegistrySession sisRegistrySession;
    User::LeaveIfError( sisRegistrySession.Connect() );
    CleanupClosePushL( sisRegistrySession );

    RPointerArray<Swi::CSisRegistryPackage> removablePackages;
    CleanupResetAndDestroyPushL( removablePackages );
    sisRegistrySession.RemovablePackagesL( removablePackages );

    for( TInt index = 0; index < removablePackages.Count(); ++index )
        {
        Swi::RSisRegistryEntry entry;
        CleanupClosePushL( entry );
        entry.OpenL( sisRegistrySession, *( removablePackages[ index ] ) );
        if( entry.RemovableL() )
            {
            GetExecutablesFromEntryL( entry, aInstalledExecutableArray );
            }
        CleanupStack::PopAndDestroy( &entry );
        }

    CleanupStack::PopAndDestroy( 2, &sisRegistrySession );
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::GetStartupListAppsL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::GetStartupListAppsL( RDscStore& aDscStore,
        RPointerArray<HBufC>& aStartedExecutableArray )
    {
    aDscStore.EnumOpenLC();

    while( CDscItem* item = aDscStore.EnumReadNextL() )
        {
        CleanupStack::PushL( item );
        aStartedExecutableArray.AppendL( item->FileName().AllocL() );
        CleanupStack::PopAndDestroy( item );
        }

    CleanupStack::PopAndDestroy();  // runs EnumClose
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::StartedButNotInstalledAppsL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::StartedButNotInstalledAppsL(
        RPointerArray<HBufC>& aStartedExecutableArray,                  // in
        RPointerArray<HBufC>& aInstalledExecutableArray,                // in
        RPointerArray<HBufC>& aStartedButNotInstalledExecutableArray )  // out
    {
    aStartedButNotInstalledExecutableArray.ResetAndDestroy();

    TIdentityRelation<HBufC> identityRelation( FileNamesEqual );
    for( TInt index = 0; index < aStartedExecutableArray.Count(); ++index )
        {
        const HBufC* startedAppName = aStartedExecutableArray[ index ];
        if( aInstalledExecutableArray.Find( startedAppName, identityRelation ) == KErrNotFound )
            {
            aStartedButNotInstalledExecutableArray.AppendL( startedAppName->AllocL() );
            }
        }
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::RemoveFromStartupListL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::RemoveFromStartupListL( RDscStore& aDscStore,
        RPointerArray<HBufC>& aExecutableArray )
    {
    for( TInt index = 0; index < aExecutableArray.Count(); ++index )
        {
        const TDesC& executableName = *( aExecutableArray[ index ] );
        CDscItem* item = CDscItem::NewLC( executableName, KNullDesC );
        if( aDscStore.ItemExistsL( *item ) )
            {
            aDscStore.DeleteItemL( *item );
            }
        CleanupStack::PopAndDestroy( item );
        }
    }

// ---------------------------------------------------------------------------
// CStartupListUpdater::GetExecutablesFromEntryL()
// ---------------------------------------------------------------------------
//
void CStartupListUpdater::GetExecutablesFromEntryL( Swi::RSisRegistryEntry& aEntry,
        RPointerArray<HBufC>& aExecutableArray )
    {
    RPointerArray<HBufC> filesList;
    CleanupResetAndDestroyPushL( filesList );
    aEntry.FilesL( filesList );

    for( TInt index = 0; index < filesList.Count(); ++index )
        {
        TParse parse;
        TInt err = parse.SetNoWild( KNullDesC, filesList[ index ], NULL );
        if( !err && ( parse.Ext().CompareF( KExecutableExtension ) == 0 ) )
            {
            aExecutableArray.AppendL( parse.FullName().AllocL() );
            }
        }

    CleanupStack::PopAndDestroy( &filesList );
    }