--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/swis/server/installationplanner.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,2322 @@
+/*
+* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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:
+* Definition of the CInstallationPlanner
+*
+*/
+
+
+/**
+ @file
+*/
+
+#include "siscontroller.h"
+#include "sisstring.h"
+#include "sisinstallationresult.h"
+#include "sissupportedlanguages.h"
+#include "sislanguage.h"
+#include "installationplanner.h"
+#include "plan.h"
+#include "application.h"
+#include "userselections.h"
+#include "siscontentprovider.h"
+#include "sishelperclient.h"
+#include "securitypolicy.h"
+
+#include <swi/msisuihandlers.h>
+
+#include "sisinstallblock.h"
+#include "sisproperties.h"
+#include "sisproperty.h"
+#include "siselseif.h"
+#include "sisinfo.h"
+#include "sisuid.h"
+
+#include "sisuihandler.h"
+
+#include "expressionevaluator.h"
+
+#include "log.h"
+
+#include "sisregistrywritableentry.h"
+#include "sisregistrysession.h"
+#include "sisregistrypackage.h"
+#include "sisregistryfiledescription.h"
+#include "sisregistrywritablesession.h"
+
+#include "sisinstallerrors.h"
+#include "cleanuputils.h"
+
+#include "securitycheckutil.h"
+#include "sistruststatus.h"
+#include "securitypolicy.h"
+#include "certchainconstraints.h"
+
+#include "sisregistryserverconst.h"
+#include "dessisdataprovider.h"
+#include "adornedutilities.h"
+
+using namespace Swi;
+using namespace Swi::Sis;
+
+_LIT(KSysBin, "\\sys\\bin\\");
+_LIT(KPluginPath, "\\resource\\plugins\\");
+
+CInstallationPlanner* CInstallationPlanner::NewL(RSisHelper& aSisHelper,
+ RUiHandler& aInstallerUI, const CContentProvider& aContentProvider,
+ CInstallationResult& aInstallationResult)
+ {
+ CInstallationPlanner* self = CInstallationPlanner::NewLC(aSisHelper,
+ aInstallerUI, aContentProvider, aInstallationResult);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CInstallationPlanner* CInstallationPlanner::NewLC(RSisHelper& aSisHelper,
+ RUiHandler& aInstallerUI, const CContentProvider& aContentProvider,
+ CInstallationResult& aInstallationResult)
+ {
+ CInstallationPlanner* self = new (ELeave) CInstallationPlanner(aSisHelper,
+ aInstallerUI, aContentProvider, aInstallationResult);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+CInstallationPlanner::~CInstallationPlanner()
+ {
+ iControllersToProcess.Close();
+ delete iMainApplication;
+
+ delete iExpressionEnvironment;
+ delete iExpressionEvaluator;
+ iPackagesToBeProcessed.ResetAndDestroy();
+ iPackagesProcessed.Close();
+ iEclipsableRomFiles.ResetAndDestroy();
+ iOverwriteableFiles.ResetAndDestroy();
+ iEclipsableOverwriteFiles.Close();
+ iFilesFromPlannedControllers.ResetAndDestroy();
+ iDrives.Close();
+ iDriveSpaces.Close();
+ }
+
+
+CInstallationPlanner::CInstallationPlanner(RSisHelper& aSisHelper,
+ RUiHandler& aInstallerUI, const CContentProvider& aContentProvider,
+ CInstallationResult& aInstallationResult)
+ : CPlanner(aInstallerUI, aInstallationResult) ,iSisHelper(aSisHelper),
+ iContentProvider(aContentProvider), iStubFirstDriveLetter(KNoDriveSelected)
+ {
+ }
+
+void CInstallationPlanner::ConstructL()
+ {
+ CPlanner::ConstructL();
+
+ // Setup the application info to the default, until the user selects a language.
+ Plan().SetAppInfoL(iContentProvider.DefaultLanguageAppInfoL());
+
+ // Add the main controller as the first in the list of controllers
+ iControllersToProcess.AppendL(TControllerAndParentApplication(iContentProvider.Controller(), NULL));
+
+ // Find out how much space is available on each drive before
+ // installation commences. That way we can keep avaialble space
+ // up to date as we plan embedded application installations
+ iSisHelper.FillDrivesAndSpacesL(iDrives, iDriveSpaces);
+ }
+
+void CInstallationPlanner::FinalisePlanL(void)
+ {
+ // Transfer ownership of the main application
+ Plan().SetApplication(iMainApplication);
+ iMainApplication = NULL;
+ ProcessRemainingPackagesL();
+ // Note that the UninstallationPlanner informs the UI of the final progress
+ // bar value here - this needs to be done after post-requisite checks for
+ // an installation, since orphans to be overwritten will be planned for
+ // removal in the post-requisite checks.
+ }
+
+void CInstallationPlanner::ChooseOptionsDialogL(CContentProvider& aContent, CApplication& aApplication)
+ {
+ TAppInfo info = aContent.LocalizedAppInfoL(iDisplayLanguageIndex);
+ RPointerArray<TDesC> optionNames = aContent.LocalizedOptionsL(iDisplayLanguageIndex);
+ RArray<TBool> optionSelections;
+
+ CleanupClosePushL(optionNames);
+ CleanupClosePushL(optionSelections);
+
+ if (optionNames.Count() > 0)
+ {
+ CDisplayOptions* optionsCmd = CDisplayOptions::NewLC(info, optionNames, optionSelections);
+
+ UiHandler().ExecuteL(*optionsCmd);
+ TBool result = optionsCmd->ReturnResult();
+ CleanupStack::PopAndDestroy(optionsCmd);
+
+ if (!result) // User pressed cancel
+ {
+ AbortL();
+ }
+
+ aApplication.UserSelections().SetOptionsL(optionSelections);
+ }
+ CleanupStack::PopAndDestroy(2, &optionNames); //&optionSelections
+ }
+
+void CInstallationPlanner::ChooseDriveDialogL(CContentProvider& aContent, CApplication& aApplication, const TInt64 &aSize)
+ {
+ TAppInfo info = aContent.LocalizedAppInfoL(iDisplayLanguageIndex);
+
+ TInt selectedDrive=0;
+
+ // Only call the dialog if there is more than one drive to choose from
+ if (iDrives.Count() > 1)
+ {
+ CDisplayDrive* driveCmd = CDisplayDrive::NewLC(info, aSize, iDrives, iDriveSpaces);
+
+ UiHandler().ExecuteL(*driveCmd);
+ selectedDrive = driveCmd->ReturnResult();
+ CleanupStack::PopAndDestroy(driveCmd);
+
+ if ((selectedDrive < 0)||(selectedDrive >= iDrives.Count()))
+ {
+ // UI returned an out of bound index, abort installation please...
+ AbortL();
+ }
+
+ aApplication.UserSelections().SetDrive(iDrives[selectedDrive]);
+ }
+ else
+ {
+ // Only one drive, select it automatically.
+ aApplication.UserSelections().SetDrive(iDrives[0]);
+ }
+ }
+
+void CInstallationPlanner::ReclaimUninstallSpaceL(const CApplication& aApplication)
+ {
+ // Search through the files to remove and add the space saved
+ // back to the free space on given drives.
+ for(TInt i = 0; i < aApplication.FilesToRemove().Count(); i++)
+ {
+ CSisRegistryFileDescription& fileDescription = *aApplication.FilesToRemove()[i];
+ TChar drive(fileDescription.Target()[0]);
+ drive.UpperCase();
+ TInt index = iDrives.Find(drive);
+ if(index >= 0)
+ {
+ iDriveSpaces[index] += fileDescription.UncompressedLength();
+ }
+ }
+ }
+
+
+void CInstallationPlanner::ChooseLanguageDialogL(CContentProvider& aContent, CApplication& aApplication)
+ {
+ if(aContent.AvailableLanguages().Count() > 1)
+ {
+ // Since we do not know the language to use yet, we use the default!
+ TAppInfo info = aContent.DefaultLanguageAppInfoL();
+
+ CDisplayLanguage* langCmd = CDisplayLanguage::NewLC(info, aContent.AvailableLanguages());
+ UiHandler().ExecuteL(*langCmd);
+ iDisplayLanguageIndex = langCmd->ReturnResult();
+
+ CleanupStack::PopAndDestroy(langCmd);
+
+ if((iDisplayLanguageIndex < 0) || (iDisplayLanguageIndex >= aContent.AvailableLanguages().Count()))
+ {
+ // UI returned an out of bound index, abort installation please...
+ AbortL();
+ }
+ }
+ else
+ {
+ // Only one language availble, no point asking the user to select it
+ iDisplayLanguageIndex = 0;
+ }
+ aApplication.UserSelections().SetLanguage(aContent.AvailableLanguages()[iDisplayLanguageIndex]);
+ //if it's the top level controller store the appinfo for this language in the plan
+ if (iContentProvider.Controller().Info().Uid().Uid() == aContent.Controller().Info().Uid().Uid())
+ {
+ Plan().SetAppInfoL(aContent.LocalizedAppInfoL(iDisplayLanguageIndex));
+ }
+ }
+
+TLanguage CInstallationPlanner::DisplayLanguage() const
+ {
+ return (iContentProvider.AvailableLanguages()[iDisplayLanguageIndex]);
+ }
+
+
+void CInstallationPlanner::DisplayUpgradeDialogL(const TAppInfo& aCurrentAppInfo, RSisRegistryEntry& aUpgradedApp)
+ {
+ HBufC* name=aUpgradedApp.PackageNameL();
+ CleanupStack::PushL(name);
+ HBufC* vendorName=aUpgradedApp.LocalizedVendorNameL();
+ CleanupStack::PushL(vendorName);
+ TVersion version=aUpgradedApp.VersionL();
+ TAppInfo upgradedAppInfo(*name, *vendorName, version);
+
+ CDisplayUpgrade* displayUpgrade=CDisplayUpgrade::NewLC(aCurrentAppInfo, upgradedAppInfo);
+ UiHandler().ExecuteL(*displayUpgrade);
+ if (!displayUpgrade->ReturnResult())
+ {
+ User::Leave(KErrCancel); // Installation cancelled
+ }
+ CleanupStack::PopAndDestroy(3, name);
+ }
+
+/// Functions for keeping track of packages which need to be processed
+
+void CInstallationPlanner::NotePackageForProcessingL(CSisRegistryPackage& aPackage, CApplication& aApplication)
+ {
+ CPackageApplicationPair* processed=CPackageApplicationPair::NewLC(aPackage, aApplication);
+ User::LeaveIfError(iPackagesToBeProcessed.Append(processed));
+ CleanupStack::Pop(processed);
+ }
+
+void CInstallationPlanner::NotePackageProcessedL(TUid aUid)
+ {
+ // Add pacakge to processed list
+ iPackagesProcessed.AppendL(aUid);
+
+ // Remove package with UID=aUid
+ for (TInt i=0; i < iPackagesToBeProcessed.Count(); ++i)
+ {
+ if (iPackagesToBeProcessed[i]->Package().Uid()==aUid)
+ {
+ CPackageApplicationPair* pair=iPackagesToBeProcessed[i];
+ iPackagesToBeProcessed.Remove(i);
+ delete pair;
+ break;
+ }
+ }
+ }
+
+TBool CInstallationPlanner::IsPackageProcessed(TUid aUid) const
+ {
+ for (TInt i=0; i < iPackagesProcessed.Count(); ++i)
+ {
+ if (aUid == iPackagesProcessed[i])
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
+
+void CInstallationPlanner::ProcessRemainingPackagesL()
+ {
+ // The packages remaining on the list need to be uninstalled, since they were present
+ // on the device as an embedded package, but weren't present in the new install
+ // Also check that nothing depends on this before removing the package.
+ for (TInt i=0; i < iPackagesToBeProcessed.Count(); ++i)
+ {
+ CApplication* application=UninstallPackageL(iPackagesToBeProcessed[i]->Package(), EFalse);
+ CleanupStack::PushL(application);
+ iPackagesToBeProcessed[i]->Application().AddEmbeddedApplicationL(application);
+ CleanupStack::Pop(application); // ownership has been transferred
+ }
+ }
+
+
+TBool CInstallationPlanner::IsValidSaUpgradeL(RSisRegistryWritableEntry& aRegistryEntry, const TBool aIsSisNonRemovable, const TBool aControllerFlag)
+ {
+ TBool isBaseNonRemovable = !aRegistryEntry.RemovableL();
+ TBool isBaseSuSigned = aRegistryEntry.IsSignedBySuCertL();
+ TBool isBaseInRom = aRegistryEntry.IsInRomL();
+ TBool isSameNonRemovableState = (isBaseNonRemovable == aIsSisNonRemovable);
+ TBool isRuFlag = aControllerFlag & EInstFlagROMUpgrade;
+ TBool isNrFlag = aControllerFlag & EInstFlagNonRemovable;
+ if (iIsValidSystemUpgrade)
+ {
+ // SU packages can upgrade all ROM packages and non-Rom packages regardless of their state.
+ return ETrue;
+ }
+ else
+ {
+ // Non-SU packages can upgrade ROM base only if they have the RU (ROM upgrade flag) and not have the NR flag.
+ // For non-ROM packages, they cannot upgrade if and only if the base is removable and
+ // the upgrade is non-removable, or if the base is non-removable and the upgrade is removable.
+ // and also cannot upgrade if Upgrade is less trusted than the base package
+ return (isBaseInRom ? (isRuFlag && !isNrFlag) : (isSameNonRemovableState && !isBaseSuSigned));
+ }
+ }
+
+TBool CInstallationPlanner::IsValidEclipsingUpgradeL(const Sis::CController& aController, RSisRegistryWritableEntry& aRegistryEntry, const TBool aStubExistsInRom)
+ {
+ TBool paInstall = aController.Info().InstallType() == Sis::EInstPreInstalledApp;
+ __ASSERT_DEBUG(!paInstall, User::Leave(KErrNotSupported));
+
+ if (aController.Info().Uid().Uid() != aRegistryEntry.UidL())
+ {
+ return EFalse;
+ }
+
+ if (CurrentController().TrustStatus().ValidationStatus() < EValidatedToAnchor)
+ {
+ return EFalse;
+ }
+
+ TBool isBaseInRom = aRegistryEntry.IsInRomL();
+ TBool saInstall = aController.Info().InstallType() == EInstInstallation;
+ TBool romUpgradeFlag = aController.Info().InstallFlags() & EInstFlagROMUpgrade;
+ TBool romUpgradableSA = saInstall && romUpgradeFlag;
+ TBool puInstall = aController.Info().InstallType() == Sis::EInstPartialUpgrade;
+ if (isBaseInRom && !saInstall)
+ {
+ return ETrue;
+ }
+ return (aStubExistsInRom && (romUpgradableSA || puInstall));
+ }
+
+void CInstallationPlanner::SetDeviceSupportedLanguages(RArray<TInt>& aDeviceSupportedLanguages)
+ {
+ iDeviceSupportedLanguages = &aDeviceSupportedLanguages;
+ }
+
+/// Processing functions
+
+CApplication* CInstallationPlanner::ProcessControllerL(const Sis::CController& aController, TInt aCumulativeDataIndex, RPointerArray<CFileDescription>& aFilesToCapabilityCheck, TUid aParentUid)
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Skip all the chances of leaving, when the planner is in info collection mode.
+ if(!IsInInfoCollectionMode())
+ {
+ #endif
+ // Check to see that we are not trying to install a protected package
+ // uid with an untrusted controller
+ if(aController.TrustStatus().ValidationStatus() < EValidatedToAnchor
+ && SecurityCheckUtil::IsPackageUidProtected(aController.Info().Uid().Uid().iUid))
+ {
+ // Can't install a protected package Uid when the controller
+ // is untrusted
+ DisplayErrorL(EUiUIDPackageViolation, KNullDesC);
+ User::Leave(KErrSecurityError);
+ }
+
+ // If this package is signed by a DevCert that constraints SIDs,
+ // check the pUID is not in the protected range before installing.
+ // Otherwise, do not install this package, since it could be upgraded
+ if ( ! aController.CertChainConstraints()->SIDIsValid( aController.Info().Uid().Uid().iUid) )
+ {
+ // Not allowed to install a protected package when sids are constrained
+ // e.g. this can occur when a package is signed by a devcert
+ DisplayErrorL(EUiConstraintsExceeded, KNullDesC);
+ User::Leave(KErrSecurityError);
+ }
+
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // If this package is set to be 'hidden' and not trusted sufficiently,
+ // do not install this package. Notify the user and leave from here.
+ if ( (aController.Info().InstallFlags() & EInstFlagHide) &&
+ (aController.TrustStatus().ValidationStatus() < EValidatedToAnchor))
+ {
+ // Can't install a hidden package signed with a untrusted certificate chain.
+ DisplayErrorL(EUiConstraintsExceeded, KNullDesC);
+ User::Leave(KErrSecurityError);
+ }
+ }
+ #endif
+
+ NotePackageProcessedL(aController.Info().Uid().Uid());
+
+ // Reset the list of file allowed to be eclipsed and overwritten for
+ // every embedded controller in the package
+ iEclipsableRomFiles.ResetAndDestroy();
+ iOverwriteableFiles.ResetAndDestroy();
+
+ CApplication* application=CApplication::NewLC();
+ application->SetController(aController);
+
+ // Copy the set of device languages to CApplication data member
+ application->CopyDeviceSupportedLanguagesL(*iDeviceSupportedLanguages);
+
+ application->SetSisHelper(iSisHelper);
+
+ if(aController.Info().InstallFlags() & EInstFlagShutdownApps)
+ {
+ application->SetShutdownAllApps(ETrue);
+ }
+
+ if (iSisHelper.IsStubL())
+ {
+ CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
+
+ if (!(iSisHelper.IsSisFileReadOnlyL()) && securityPolicy->DeletePreinstalledFilesOnUninstall())
+ {
+ application->SetDeletablePreinstalled(ETrue);
+ }
+
+ iIsStub = ETrue;
+ iIsPropagated = !((aController.Info().InstallType() == EInstPreInstalledPatch) || (aController.Info().InstallType() == EInstPreInstalledApp));
+ application->SetStub(iIsPropagated);
+ }
+
+ Sis::TInstallType type = application->ControllerL().Info().InstallType();
+ Sis::TInstallFlags flag = application->ControllerL().Info().InstallFlags();
+ TBool ruFlag = (flag & EInstFlagROMUpgrade);
+ TBool rejectedType = ( (type == EInstPreInstalledApp ) || (type == EInstPreInstalledPatch ));
+
+ if ( ruFlag && rejectedType && aController.IsSignedBySuCert())
+ {
+ // reject PA or PP with RU flag System Upgrade packages ( signed by SU cert)
+ DEBUG_PRINTF(_L8("Attempt made to install/preinstall/propagate System Upgrade package with RU flag"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+
+ iIsValidSystemUpgrade = IsValidSystemUpgradeL(*application);
+
+ if (iIsValidSystemUpgrade)
+ {
+ application->SetInstallSuCertBased();
+ }
+
+ // Check to see if there is a package installed with this UID
+ RSisRegistryWritableSession registrySession;
+ User::LeaveIfError(registrySession.Connect());
+ CleanupClosePushL(registrySession);
+
+ RSisRegistryWritableEntry registryEntry;
+ TInt error=registryEntry.Open(registrySession, aController.Info().Uid().Uid());
+ CleanupClosePushL(registryEntry);
+
+ TBool isSisNonRemovable = ((aController.Info().InstallFlags() & EInstFlagNonRemovable) == EInstFlagNonRemovable);
+
+ DEBUG_PRINTF2(_L8("Planning controller of type %d for install"), aController.Info().InstallType());
+ //Index from the planned controllers for the base controller of the current controller
+ TInt baseControllerIndex = 0;
+
+ if (error == KErrNone)
+ {
+ CSisRegistryPackage* package=registryEntry.PackageL();
+ CleanupStack::PushL(package);
+ application->SetPackageL(*package);
+ CleanupStack::PopAndDestroy(package);
+
+ TBool isBaseRemovable = registryEntry.RemovableL();
+
+ if (aController.Info().InstallType() == EInstInstallation)
+ {
+ // The package is already on the device so check whether it
+ // is a valid upgrade
+ // Stub SIS files cannot be used to perform an upgrade.
+ TBool validUpgrade = IsValidSaUpgradeL(registryEntry, isSisNonRemovable, aController.Info().InstallFlags());
+ if ((iIsPropagated || !validUpgrade))
+ {
+ DEBUG_PRINTF(_L8("Invalid Upgrade: SA Attempted"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+
+ application->SetUpgrade(aController);
+
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Display the dialog only when the planner is not in info collection mode.
+ if (!IsInInfoCollectionMode())
+ {
+ #endif
+ //if it's the top level controller display a dialog box
+ if (iContentProvider.Controller().Info().Uid().Uid() == aController.Info().Uid().Uid())
+ {
+ DisplayUpgradeDialogL(Plan().AppInfoL(), registryEntry);
+ }
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+
+
+ /**
+ * Add the embedded packages to a list of packages which are yet to be processed.
+ * At the end of the processing of all the controllers this list is checked to
+ * see if theres some controllers which only need to be uninstalled, and the files
+ * to be removed are added to the plan.
+ * However this only applies when it's not a partial upgrade.
+ */
+ RPointerArray<CSisRegistryPackage> embeddedPackages;
+ CleanupResetAndDestroy<RPointerArray<CSisRegistryPackage> >::PushL(embeddedPackages);
+ registryEntry.EmbeddedPackagesL(embeddedPackages);
+
+ for (TInt i=0; i < embeddedPackages.Count(); ++i)
+ {
+ NotePackageForProcessingL(*embeddedPackages[i], *application);
+ }
+ CleanupStack::PopAndDestroy(&embeddedPackages);
+
+ }
+ else if (aController.Info().InstallType() == EInstAugmentation)
+ {
+ if (isBaseRemovable && isSisNonRemovable)
+ {
+ DEBUG_PRINTF(_L8("Invalid Upgrade: SP Attempted"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+
+ if (iIsPropagated)
+ {
+ // Treat an augmentation on a removable media stub as a
+ // preinstalled patch
+ application->SetPreInstalledPatch(aController);
+ }
+ else
+ {
+ application->SetAugmentation(aController);
+ }
+ }
+ else if (aController.Info().InstallType() == EInstPreInstalledPatch)
+ {
+ // NR patches on pre-installed media are invalid
+ if (isSisNonRemovable)
+ {
+ DEBUG_PRINTF(_L8("Invalid Upgrade: NR patches on pre-installed media are invalid"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+
+ application->SetPreInstalledPatch(aController);
+ }
+ else if (aController.Info().InstallType() == EInstPartialUpgrade)
+ {
+ // Do not allow partial upgrades to preinstalled applications
+ // BR1863.1 and BR1863.2
+ if (registryEntry.PreInstalledL())
+ {
+ User::Leave(KErrInvalidUpgrade);
+ }
+
+ // Stub SIS files cannot be used to perform an upgrade
+ if (iIsPropagated)
+ {
+ User::Leave(KErrInvalidUpgrade);
+ }
+
+ // Upgrade package is less trusted than the base package
+ if (!iIsValidSystemUpgrade && registryEntry.IsSignedBySuCertL())
+ {
+ DEBUG_PRINTF(_L8("Invalid Upgrade: PU Attempted"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+ // Partial Upgrade can only be installed to a base package of the same install flag type
+ // PU cannot change the non-removable status of a base package, i.e. a non-removable package
+ // cannot replace a removable one and visa versa. The only exception is ROM stub which is upgradable
+ // and non-removable by definition.
+ if ((isBaseRemovable == isSisNonRemovable) && !registryEntry.IsInRomL())
+ {
+ DEBUG_PRINTF(_L8("Invalid Upgrade: PU Attempted"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+
+ application->SetPartialUpgrade(aController);
+
+ // If the parent application is in ROM, set this type to
+ // be a ROM application too, so eclipsing rule
+ if (registryEntry.IsInRomL())
+ {
+ application->SetInROM();
+ }
+
+ }
+ else if (aController.Info().InstallType() == EInstPreInstalledApp)
+ {
+
+ // We can't install a preinstalled app over the top of
+ // another application.
+ User::Leave(KErrInvalidUpgrade);
+
+ }
+
+ // Preinstalled apps will have errored out by this point,
+ // regular installs will have their files removed,
+ // others will have the files added to the list of eclipsable ROM files
+ // if they satisfy the appropriate conditions.
+ PrepareEclipsableFilesListL(aController);
+
+ // Check to ensure all upgrades are sufficiently
+ // trusted to upgrade the base package
+ // non System Upgrade SP upgrades, to a System Upgrade Package shall only add files.
+ TBool nonSuPkgSpUpgradeoverSu = !iIsValidSystemUpgrade && application->IsAugmentation() && registryEntry.IsSignedBySuCertL();
+ if (!SecurityCheckUtil::IsSufficientlyTrusted(aController,
+ registryEntry.TrustStatusL().ValidationStatus()) && !nonSuPkgSpUpgradeoverSu)
+ {
+ DEBUG_PRINTF(_L8("Application not sufficiently trusted to upgrade its base"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+ }
+ else if (error == KErrNotFound)
+ {
+ // SWI cannot intall non-removable packages if the sis file not signed with the trusted certificate
+ if (isSisNonRemovable && !iIsValidSystemUpgrade)
+ {
+ DEBUG_PRINTF(_L8("Attempt made to install NR sis file which is not trusted by device"));
+ User::Leave(KErrNotSupported);
+ }
+
+ if (aController.Info().InstallType() == EInstInstallation)
+ {
+ // The application isn't on the device so an installation can proceed
+
+ if(iIsPropagated)
+ {
+ // Treat an installation inside a stub SIS file as a
+ // Pre-Installed App
+ application->SetPreInstalledApp(aController);
+ }
+ else
+ {
+ application->SetInstall(aController);
+ }
+ }
+ else if (aController.Info().InstallType() == EInstAugmentation)
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Skip all the chances of leaving, when the planner is in info collection mode.
+ if(!IsInInfoCollectionMode())
+ {
+ #endif
+ //The application isn't on the device so we have to check if the base
+ //package on the planned list. can't upgrade an augmentation in the list.
+ if(!IsPlannedControllerL(aController, baseControllerIndex, aParentUid) ||
+ IsAugmentationUpgrade(aController))
+ {
+ // we needed the base package on the device, so fail
+ DisplayErrorL(EUiMissingBasePackage, KNullDesC);
+ User::Leave(KErrMissingBasePackage);
+ }
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+
+ if (iIsPropagated)
+ {
+ // Treat an augmentation on a removable media stub as a
+ // preinstalled patch
+ application->SetPreInstalledPatch(aController);
+ }
+ else
+ {
+ application->SetAugmentation(aController);
+ }
+ }
+ else if (aController.Info().InstallType() == EInstPartialUpgrade)
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Skip all the chances of leaving, when the planner is in info collection mode.
+ if(!IsInInfoCollectionMode())
+ {
+ #endif
+ //The application isn't on the device so we have to check if the base
+ //package on the planned list
+ if(!IsPlannedControllerL(aController, baseControllerIndex, aParentUid))
+ {
+ // we needed the base package on the device, so fail
+ DisplayErrorL(EUiMissingBasePackage, KNullDesC);
+ User::Leave(KErrMissingBasePackage);
+ }
+ // Stub SIS files cannot be used to perform an upgrade
+ if (iIsPropagated)
+ {
+ User::Leave(KErrInvalidUpgrade);
+ }
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+ application->SetPartialUpgrade(aController);
+ }
+ else if (aController.Info().InstallType() == EInstPreInstalledApp)
+ {
+ // The application isn't on the device so an installation can precede
+ application->SetPreInstalledApp(aController);
+ }
+ else
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ if(!IsInInfoCollectionMode())
+ {
+ #endif
+ // we needed the base package on the device, so fail
+ DisplayErrorL(EUiMissingBasePackage, KNullDesC);
+ User::Leave(KErrMissingBasePackage);
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+ }
+
+ if ((aController.Info().InstallType() == EInstPartialUpgrade) || (aController.Info().InstallType() == EInstAugmentation))
+ {
+ TInt baseControllerNum;
+ TBool trusted = EFalse;
+ //Find the base controller for the current controller
+ if((baseControllerNum = GetControllerReference(aController.Info().Uid().Uid())) >= 0)
+ {
+ if(SecurityCheckUtil::IsSufficientlyTrusted(aController, iControllersToProcess[baseControllerNum].Controller()))
+ {
+ trusted = ETrue;
+ }
+ }
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ if(!IsInInfoCollectionMode())
+ {
+ #endif
+ if(!trusted)
+ {
+ DEBUG_PRINTF(_L8("Application not sufficiently trusted to upgrade its base"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+ }
+ }
+ else
+ {
+ User::LeaveIfError(error);
+ }
+
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Check whether the package content is DRM protected.
+ TBool isContentDrmProtected = iSisHelper.IsDrmProtectedL();
+ application->SetDrmProtected(isContentDrmProtected);
+ #endif
+
+ // Get the user selections
+ CContentProvider* content = CContentProvider::NewLC(application->ControllerL());
+
+ // If the count of Device supported languages is not equal to zero, then choose the
+ // language based on the sis supported languages and device supported languages.
+ if ( 0 != iDeviceSupportedLanguages->Count())
+ {
+ // Sets the following flags,
+ // a) iHasDeviceSupportdLanguages, indicates whether a SIS file contains the Device
+ // Language token or not.
+ // b) iHasMatchingLanguages, indicates whether there is an exact match(any one) between
+ // the languages which device supports and languages which SIS file supports.
+ SetDeviceLanguagesL(aController.InstallBlock(), *application, *content);
+
+ // If a SIS file contains Supported language token and iHasMatchingLanguages is TRUE
+ // then either current device language is used or the lowest language id supported by
+ // the SIS file will be used else if iHasMatchingLanguages is FALSE then proceed
+ // with user language selection dialog box displaying sis supported languages.
+
+ if ( application->IsDeviceSupportedLanguages())
+ {
+ TInt langIndex = 0;
+ if ( application->IsLanguageMatch() ) //exact match
+ {
+ TLanguage currentLanguage = User::Language(); // Language of the current locale
+ TBool isExactLanguageMatch = EFalse;
+
+ // Check whether the current locale is in the list of available languages
+ const RArray<TInt>& matchingLanguages = application->GetMatchingDeviceLanguages();
+ const RArray<TLanguage>& availableLanguages = content->AvailableLanguages();
+
+ TInt index = availableLanguages.Find(currentLanguage);
+ TInt currentLanguageIndex = matchingLanguages.Find(currentLanguage);
+
+ if( (index != KErrNotFound && currentLanguageIndex != KErrNotFound))
+ {
+ langIndex = index;
+ isExactLanguageMatch = ETrue;
+ }
+ else
+ {
+ TInt leastExactMatchLanguagesIndex = 0;
+ for(TInt i=0 ; i< availableLanguages.Count() ; i++)
+ {
+ TBool isFirstMatch = ETrue;
+ if((matchingLanguages.Find(availableLanguages[i])!= KErrNotFound) && ((availableLanguages[i] <= availableLanguages[leastExactMatchLanguagesIndex])||isFirstMatch))
+ {
+ isFirstMatch = EFalse;
+ leastExactMatchLanguagesIndex = i;
+ isExactLanguageMatch = ETrue;
+ }
+ }
+ if( isExactLanguageMatch )
+ {
+ langIndex = leastExactMatchLanguagesIndex;
+ }
+ else // Intersection of Matching Languages & SIS file's Language header is NULL
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Display the dialog only when the planner is not in info collection mode.
+ if (!IsInInfoCollectionMode())
+ {
+ #endif
+ ChooseLanguageDialogL(*content, *application);
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+ }
+ }
+ if( isExactLanguageMatch )
+ {
+ application->UserSelections().SetLanguage(content->AvailableLanguages()[langIndex]);
+ iDisplayLanguageIndex = langIndex;
+
+ //if it's the top level controller store the appinfo for this language in the plan
+ if (iContentProvider.Controller().Info().Uid().Uid() == content->Controller().Info().Uid().Uid())
+ {
+ Plan().SetAppInfoL(content->LocalizedAppInfoL(iDisplayLanguageIndex));
+ }
+ DEBUG_PRINTF2(_L8("current device Language id is %d"), content->AvailableLanguages()[langIndex]);
+ }
+ }
+ else // No matching language with device
+ {
+ //if no exact match is there the proceed with user language selection dialog box
+ //displaying sis supported languages.
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Display the dialog only when the planner is not in info collection mode.
+ if (!IsInInfoCollectionMode())
+ {
+ #endif
+ ChooseLanguageDialogL(*content, *application);
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+ }
+ }
+ else // No Supported Language Token in SIS file
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Display the dialog only when the planner is not in info collection mode.
+ if (!IsInInfoCollectionMode())
+ {
+ #endif
+ ChooseLanguageDialogL(*content, *application);
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+ }
+
+ }
+ else //Device Supported Languages is zero. Hence proceed with user language selection dialog box
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Display the dialog only when the planner is not in info collection mode.
+ if (!IsInInfoCollectionMode())
+ {
+ #endif
+ ChooseLanguageDialogL(*content, *application);
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+ }
+
+
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Display the dialog only when the planner is not in info collection mode.
+ if (!IsInInfoCollectionMode())
+ {
+ #endif
+ ChooseOptionsDialogL(*content, *application);
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+
+ DEBUG_PRINTF4(_L("Application for install; UID: 0x%08x, Name: %S, Vendor: %S"),
+ aController.Info().Uid().Uid().iUid, &(aController.Info().Names()[iDisplayLanguageIndex]->Data()),
+ &(aController.Info().UniqueVendorName().Data()));
+
+ // Check if this is an augmentation upgrade
+ // This must be done after the language has been selected, so that we have the localised
+ // name of the package.
+ if (error == KErrNone && IsAugmentationUpgradeL(aController, registryEntry, registrySession))
+ {
+ // We have an augmentation upgrade, check that it's OK to upgrade the previous augmentation
+ if (!SecurityCheckUtil::IsSufficientlyTrusted(aController,
+ registryEntry.TrustStatusL().ValidationStatus()))
+ {
+ DEBUG_PRINTF(_L8("Application not sufficiently trusted to upgrade its base"));
+ User::Leave(KErrInvalidUpgrade);
+ }
+
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Display the dialog only when the planner is not in info collection mode.
+ if (!IsInInfoCollectionMode())
+ {
+ #endif
+ // if this is the top level controller, display the upgrade dialog.
+ if (iContentProvider.Controller().Info().Uid().Uid() == aController.Info().Uid().Uid())
+ {
+ DisplayUpgradeDialogL(Plan().AppInfoL(), registryEntry);
+ }
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+
+ // The flags now mark this package as both an upgrade _and_ an augmentation
+ application->SetUpgrade(aController);
+ // entry has changed so change the package in the application
+ CSisRegistryPackage* package=registryEntry.PackageL();
+ CleanupStack::PushL(package);
+ application->SetPackageL(*package);
+ CleanupStack::PopAndDestroy(package);
+ }
+
+ // add files to the plan which may need to be removed.
+ if(error == KErrNone)
+ {
+ ProcessFilesToRemoveL(*application, registryEntry);
+ }
+
+ // Setup the evaluation environment for the user selections
+ SetupExpressionEnvironmentL(*application);
+
+ // If we doing any kind of upgrade we can assume the space
+ // currently used by files that will be removed will be
+ // available for use by our installation
+ ReclaimUninstallSpaceL(*application);
+
+ // Size of this controller only!!
+ TInt64 size = iContentProvider.TotalSizeL(aController.InstallBlock(), iExpressionEvaluator, EFalse);
+
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Invoke the drive selection part when the planner is not in info collection mode. Otherwise do not.
+ if (IsInInfoCollectionMode())
+ {
+ // for GetInfo purposes we select an existing system drive. We need to make sure that a valid drive is selected for installation planning, and in any case no files will get copied there,
+ application->UserSelections().SetDrive(iSystemDriveChar);
+ }
+ else
+ {
+ #endif
+ // If the package is partial upgrade, extract drive from the registry, and dont
+ // display the drive selection option except where we are upgrading a ROM stub
+ if(error == KErrNone && aController.Info().InstallType() == EInstPartialUpgrade && !registryEntry.IsInRomL())
+ {
+ TChar drive = registryEntry.SelectedDriveL();
+ if(drive == TChar(KNoDriveSelected) && IsUserDriveSelectionRequiredL(aController.InstallBlock()))
+ {
+ // Base package had hard coded file paths so we can't make
+ // any assumptions about where to install the upgrade
+ // we need to ask the user where they would like to install
+ // this upgrade
+ ChooseDriveDialogL(*content, *application, size);
+ }
+ else
+ {
+ // install partial upgrade on the same drive as base package
+ application->UserSelections().SetDrive(drive);
+ }
+ }
+ else if(error == KErrNotFound && aController.Info().InstallType() == EInstPartialUpgrade &&
+ iFilesFromPlannedControllers[baseControllerIndex]->Drive() != TChar(KNoDriveSelected))
+ {
+ //Use the base package's drive
+ application->UserSelections().SetDrive(iFilesFromPlannedControllers[baseControllerIndex]->Drive());
+ }
+ else if((aController.Info().InstallType() == EInstInstallation
+ || aController.Info().InstallType() == EInstAugmentation)
+ && iIsPropagated)
+ {
+ // This is a removable media card stub, the files must
+ // be on the same removable drive as the stub SIS file
+ application->UserSelections().SetDrive(iSisHelper.GetSisFileDriveL());
+ }
+ else if(aController.Info().InstallType() == EInstPreInstalledApp
+ || aController.Info().InstallType() == EInstPreInstalledPatch)
+ {
+ // This is a preinstalled application or patch. Installation is
+ // performed "in place" so the only drive that makes sense to
+ // select is the same one that the SIS file lives in.
+ // Note: PA/PP stub sis files can only install files on the same
+ // drive that the sis file is located on. See DEF084248
+ application->UserSelections().SetDrive(iSisHelper.GetSisFileDriveL());
+ }
+ else if (IsUserDriveSelectionRequiredL(aController.InstallBlock()))
+ {
+ // User needs to choose which drive will be used for the installation
+ ChooseDriveDialogL(*content, *application, size);
+ }
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ }
+ #endif
+ CleanupStack::PopAndDestroy(content);
+
+ // To accurately display the space avaialble for next controller
+ // we need to subtract the space used by this controller
+ TChar drive = application->UserSelections().Drive();
+ if(drive != TChar(KNoDriveSelected))
+ {
+ TInt index = iDrives.FindL(drive);
+ iDriveSpaces[index] -= size;
+ }
+
+ application->SetAbsoluteDataIndex(aCumulativeDataIndex + aController.DataIndex());
+
+ CFilesFromPlannedController* filesList = CFilesFromPlannedController::NewLC(aController.Info().Uid().Uid(), aParentUid, aController.Info().InstallType(), aController.Info().Names()[0]);
+ //Set the selected drive for the package being planned
+ filesList->SetDrive(drive);
+
+ if (aController.Logo()!= NULL)
+ {
+ const CFileDescription& aFileDescription = aController.Logo()->FileDescription();
+ ProcessFileDescriptionL(aFileDescription, *application, aFilesToCapabilityCheck, *filesList);
+ }
+
+ // Process the actual controller, then return the application
+ ProcessInstallBlockL(aController.InstallBlock(), *application, aFilesToCapabilityCheck, *filesList);
+
+ //Append planned controllers list
+ iFilesFromPlannedControllers.AppendL(filesList);
+ CleanupStack::Pop(filesList);
+
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Some files may need to be questioned of overwrite only when the planner is not in info collection mode.
+ if (!IsInInfoCollectionMode())
+ #endif
+ //Some files may need to be questioned of overwrite
+ WarnEclipseOverWriteL(*application);
+
+ // Reset the file list array for next controller use
+ iEclipsableOverwriteFiles.Reset();
+
+ ProcessPropertiesL(aController.Properties(), Plan(), *application);
+
+ CleanupStack::PopAndDestroy(2, ®istrySession); // registryEntry, registrySession
+
+ CleanupStack::Pop(application);
+ return application;
+ }
+
+
+// Prepare the eclipsable files list from the right source according to the upgrade.
+void CInstallationPlanner::PrepareEclipsableFilesListL(const Sis::CController& aController)
+ {
+ // If the package is allowed to install based on SU Cert rule, then no need to generate
+ // eclipsable file list, it can eclipse any files from rom
+ // before reaching this place, NR upgrade check already done for SA, SP and PU
+ if (iIsValidSystemUpgrade)
+ {
+ return;
+ }
+
+ RSisRegistryWritableSession registrySession;
+ User::LeaveIfError(registrySession.Connect());
+ CleanupClosePushL(registrySession);
+
+ RSisRegistryWritableEntry registryEntry;
+
+ TInt error=registryEntry.Open(registrySession, aController.Info().Uid().Uid());
+ CleanupClosePushL(registryEntry);
+ if(error != KErrNone)
+ {
+ CleanupStack::PopAndDestroy(2, ®istrySession);
+ return;
+ }
+
+
+ CSisRegistryPackage* package = registryEntry.PackageL();
+ CleanupStack::PushL(package);
+ TBool stubExistsInRom = registrySession.PackageExistsInRomL(package->Uid());
+ CleanupStack::PopAndDestroy(package);
+
+ // Break the conditions to be checked against the package in installation.
+ TBool puInstallation = aController.Info().InstallType() == EInstPartialUpgrade;
+ TBool saInstallation = aController.Info().InstallType() == EInstInstallation;
+ TBool romUpgradeFlag = aController.Info().InstallFlags() & EInstFlagROMUpgrade;
+ TBool romUpgradableSA = saInstallation && romUpgradeFlag;
+ TBool currentPkgIsInRom = registryEntry.IsInRomL();
+
+ // Standard Apps (SA) with ROM Upgrade (RU) flag,
+ // Partial upgrades, patches and preinstalled patches are all
+ // allowed to eclipse ROM files.
+
+ // When an upgrade happens over a upgrade which has already upgraded the
+ // ROM based package (i.e, an upgrade SA_RU_2 happens over ROM+SA_RU_1),
+ // don't populate the eclipsable files from the SIS registry entry which
+ // may be in-complete. So, directly populate the eclipsable files list from
+ // the corresponding stub SIS file.
+ if (IsValidEclipsingUpgradeL(aController, registryEntry, stubExistsInRom))
+ {
+ if(!currentPkgIsInRom && stubExistsInRom && (romUpgradableSA || puInstallation))
+ {
+ registrySession.GetFilesForRomApplicationL(aController.Info().Uid().Uid(), iEclipsableRomFiles);
+ }
+ // Otherwise, populate the eclipsable files list from SIS registry entry.
+ else
+ {
+ registryEntry.FilesL(iEclipsableRomFiles);
+ }
+ }
+ CleanupStack::PopAndDestroy(2, ®istrySession);
+ }
+
+void CInstallationPlanner::SetupExpressionEnvironmentL(const CApplication& aApplication)
+ {
+ delete iExpressionEnvironment;
+ iExpressionEnvironment = NULL;
+
+ delete iExpressionEvaluator;
+ iExpressionEvaluator=NULL;
+
+ iExpressionEnvironment=CSwisExpressionEnvironment::NewL(aApplication);
+ iExpressionEvaluator=CExpressionEvaluator::NewL(*iExpressionEnvironment);
+ }
+
+// Properties
+void CInstallationPlanner::ProcessPropertiesL(const Sis::CProperties& aProperties, CPlan& /*aPlan*/, CApplication& aApplication)
+ {
+ for (TInt i = 0 ; i < aProperties.Count(); ++i)
+ {
+ // Add the property to the plan
+ aApplication.AddPropertyL(CApplication::TProperty(aProperties[i].Key(), aProperties[i].Value()));
+ }
+ }
+
+TBool CInstallationPlanner::IsUserDriveSelectionRequiredL(const Sis::CInstallBlock& aInstallBlock) const
+ {
+ // process the file descriptions
+ const RPointerArray<CFileDescription>& files=aInstallBlock.FileDescriptions();
+
+ TInt i;
+ for (i = 0; i < files.Count(); ++i)
+ {
+ CFileDescription& fileDescription = *files[i];
+ if (fileDescription.Target().Data().Length() != 0)
+ {
+ // if a target file is specified check whether the
+ // target drive is hardcoded or the wildcard "!:\"
+ if(fileDescription.Target().Data()[0] == '!')
+ {
+ // Target file drive is "!:\"
+ return ETrue;
+ }
+ }
+ }
+
+ // process the expressions
+ for (i = 0 ; i < aInstallBlock.IfStatements().Count(); ++i)
+ {
+ Sis::CIf* ifBlock=aInstallBlock.IfStatements()[i];
+
+ if (!ifBlock)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ if(iExpressionEvaluator->EvaluateL(ifBlock->Expression()).BoolValueL())
+ {
+ // If the user has select the option search the install block
+ // for wildcards
+ if(IsUserDriveSelectionRequiredL(ifBlock->InstallBlock()))
+ {
+ return ETrue;
+ }
+ }
+ else
+ {
+ // else if blocks
+ const RPointerArray<CElseIf>& elseIfs = ifBlock->ElseIfs();
+
+ for (TInt j = 0 ; j < elseIfs.Count(); ++j)
+ {
+ if (!elseIfs[j])
+ {
+ User::Leave(KErrCorrupt);
+ }
+ if(iExpressionEvaluator->EvaluateL(elseIfs[j]->Expression()).BoolValueL())
+ {
+ // If the user selected this option, search the installblock
+ // for wildcards
+ if(IsUserDriveSelectionRequiredL(elseIfs[j]->InstallBlock()))
+ {
+ return ETrue;
+ }
+ }
+ }
+ }
+ }
+ // no wildcards found, all file target drives must be hardcoded
+ return EFalse;
+ }
+
+void CInstallationPlanner::SetDeviceLanguagesL(const Sis::CInstallBlock& aInstallBlock, CApplication& aApplication, const CContentProvider& aContent)
+ {
+ //Setting up the expression environment which includes setting up the values for User
+ //Options available in the sis file,which are used while prossesing the expression block.
+ SetupExpressionEnvironmentL(aApplication);
+ RPointerArray<TDesC> optionNames = aContent.LocalizedOptionsL(iDisplayLanguageIndex);
+ RArray<TBool> optionSelections;
+ CleanupClosePushL(optionNames);
+ CleanupClosePushL(optionSelections);
+ TInt opt_len = optionNames.Count();
+ TInt i = 0;
+ for ( i=0; i < opt_len; i++)
+ {
+ optionSelections.AppendL(EFalse);
+ }
+ aApplication.UserSelections().SetOptionsL(optionSelections);
+ CleanupStack::PopAndDestroy(2, &optionNames); //&optionSelections
+
+ TInt ifStmtCount = aInstallBlock.IfStatements().Count();
+ for ( i=0 ; i < ifStmtCount; ++i)
+ {
+ Sis::CIf* ifBlock=aInstallBlock.IfStatements()[i];
+
+ if (!ifBlock)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ iExpressionEvaluator->EvaluateL(ifBlock->Expression());
+ }
+ }
+
+// Functions to process files
+void CInstallationPlanner::ProcessInstallBlockL(const Sis::CInstallBlock& aInstallBlock, CApplication& aApplication, RPointerArray<CFileDescription>& aFilesToCapabilityCheck, CFilesFromPlannedController& aPlannedFiles)
+ {
+ // process the file descriptions
+ const RPointerArray<CFileDescription>& files=aInstallBlock.FileDescriptions();
+
+ TInt i;
+ for (i = 0; i < files.Count(); ++i)
+ {
+ ProcessFileDescriptionL(*files[i], aApplication, aFilesToCapabilityCheck, aPlannedFiles);
+ }
+
+ // process the expressions
+ for (i = 0 ; i < aInstallBlock.IfStatements().Count(); ++i)
+ {
+ Sis::CIf* ifBlock=aInstallBlock.IfStatements()[i];
+
+ if (!ifBlock)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // main expression
+ if ( iExpressionEvaluator->EvaluateL(ifBlock->Expression()).BoolValueL() )
+ {
+ // suppose TextSkip precedes an IF block then TS won't work
+ // since TS is only intended to work if it is immediately followed by a line that installs a file.
+ iTextSkip = EFalse;
+ ProcessInstallBlockL(ifBlock->InstallBlock(), aApplication, aFilesToCapabilityCheck, aPlannedFiles);
+ }
+ else
+ {
+ // else if blocks
+ const RPointerArray<CElseIf>& elseIfs=ifBlock->ElseIfs();
+
+ for (TInt j = 0 ; j < elseIfs.Count(); ++j)
+ {
+ if (!elseIfs[j])
+ {
+ User::Leave(KErrCorrupt);
+ }
+ if (iExpressionEvaluator->EvaluateL(elseIfs[j]->Expression()).BoolValueL())
+ {
+ iTextSkip = EFalse;
+ ProcessInstallBlockL(elseIfs[j]->InstallBlock(), aApplication, aFilesToCapabilityCheck, aPlannedFiles);
+ break; // stop processing else if blocks
+ }
+ }
+ }
+ iTextSkip = EFalse;
+ }
+
+ // Embedded controllers
+
+ for (i = 0 ; i < aInstallBlock.EmbeddedControllers().Count(); ++i)
+ {
+ if (aInstallBlock.EmbeddedControllers()[i]==NULL)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ // Add these to the list of controllers we are going to "plan" as we move the the installmachine state machine
+ // OWNERSHIP is NOT TRANSFERRED
+ iControllersToProcess.AppendL(TControllerAndParentApplication(*aInstallBlock.EmbeddedControllers()[i], &aApplication));
+ }
+ }
+
+/** This function examines the list of files we may eclipse to see if the supplied name is among them.
+ Here we have to options:
+ 1.) file is to be installed to \sys\bin therefore we have to handle adorned filenames
+ eclipsing is allowed if the filename that we are trying to install is a variant of any ROM filename
+ marked as eclipsable i.e: if we are trying to install c:\sys\bin\A{000A0001}.dll
+ and a ROM stub lists z:\sys\bin\A.dll as an eclipsable file or any z:\sys\bin\A{????????}.dll
+ then we are allowed to that so
+ 2.) file is not to be installed to sys\bin\
+ in this case we mustn't invoke special handling of adorned filenames so we are only
+ interested in if that particular file is allowed to be eclipsed i.e: z:\somedirectory\a.txt
+ Remark:
+ in this case z:\somedirectory\a.txt and z:\somedirectory\a{ABCDEFGH}.txt are considered to be different filenames
+ even if they might look to be variations of the same name
+ @param aRomFile fully qualified filename in ROM that is to be checked for eclipising (i.e: z:\sys\bin\some.dll)
+*/
+
+TBool CInstallationPlanner::IsEclipsableL(const TDesC& aRomFile)
+ {
+ // exception : SA/SP/PU sis + RU flag + signed by SU root cert can continue installation
+ if (iIsValidSystemUpgrade)
+ {
+ return ETrue;
+ }
+ TBool isEclipsable = EFalse;
+ RBuf romFileName;
+ romFileName.CreateL(aRomFile, aRomFile.Size());
+ romFileName.CleanupClosePushL();
+
+ TParsePtr parsedFileName(romFileName);
+ RBuf path;
+ path.CreateL(parsedFileName.Path().Length());
+ path.CleanupClosePushL();
+ path = parsedFileName.Path();
+ TBool goesToSysBin = (path.CompareF(KSysBin) == 0);
+ for (TInt i = 0; i < iEclipsableRomFiles.Count(); i++)
+ {
+ if (aRomFile.MatchF(*(iEclipsableRomFiles[i])) == 0)
+ {
+ isEclipsable = ETrue;
+ break;
+ }
+ else if ( goesToSysBin )
+ {
+ if(Swi::IsAdornedVariationOfL(*(iEclipsableRomFiles[i]), aRomFile))
+ {
+ isEclipsable = ETrue;
+ break;
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(2, &romFileName);
+ return isEclipsable;
+ }
+
+// This function ensures the file to be installed does not illegally
+// eclipse a file already installed on ROM.
+TBool CInstallationPlanner::ValidEclipseL(RFs& aFs, TFileName& aFileName, CApplication& aApplication)
+ {
+ DEBUG_PRINTF2(_L("CInstallationPlanner::ValidEclipseL() called aFileName='%S'"), &aFileName );
+ // check every file to be installed for a possible eclipse
+ // This is done is two steps:
+ // If installing to \sys\bin then first check for versioned (adorned name) copy of file
+ // Then check for the unadorned version
+ RArray<TFileName> eclipsableOverwriteFiles;
+ CleanupClose<RArray<TFileName> >::PushL(eclipsableOverwriteFiles);
+
+ TParsePtr parsedFileName(aFileName);
+
+ // When installing to sys\bin check for adorned names
+ RBuf searchNameUnadorned; // Holds the normalized unadorned filename (i.e. c:\sys\bin\a.exe for aFileName equal to c:\sys\bin\a{123456}.exe)
+ searchNameUnadorned.CreateL(aFileName.Length()); //fully qualified unadorned search name is never longer than original fully qualified name (i.e aFileName)
+ searchNameUnadorned.CleanupClosePushL();
+
+ //Holds all adorned file names that match the adorned filename pattern calculated out of aFileName
+ RPointerArray<HBufC> adornedFileNamesFound;
+ CleanupResetAndDestroy<RPointerArray<HBufC> >::PushL(adornedFileNamesFound);
+ RBuf path;
+ path.CreateL(parsedFileName.Path().Length());
+ path.CleanupClosePushL();
+ path = parsedFileName.Path();
+
+ if ( path.CompareF(KSysBin) == 0 )
+ {
+ // check for versioned (adorned) filenames
+ AdornedProcessingOfFileL(aFs, aFileName, searchNameUnadorned, adornedFileNamesFound);
+ }
+ else
+ {
+ searchNameUnadorned = aFileName;
+ }
+
+ // Second check for the unadorned version
+ TChar targetDisk = aFileName[0];
+ targetDisk.Fold();
+
+ // Find on which disks (if any) this file exists on
+ TDriveList driveList;
+ User::LeaveIfError(aFs.DriveList(driveList));
+
+ TBool result=ETrue;
+ TChar disk = 'a' - 1;
+ TEntry* entryPtr = new (ELeave) TEntry;
+ CleanupStack::PushL(entryPtr);
+
+ for (TInt i = 0; i < driveList.Length(); i++)
+ {
+ disk+=1;
+
+ if (driveList[i] == 0)
+ {
+ continue;
+ }
+ searchNameUnadorned[0] = disk;
+
+ // check if adorned file version found on this disk
+ TBool adornedFound = EFalse;
+ TInt nrOfAdornedFilenamesFound = adornedFileNamesFound.Count();
+ for (TInt index=0; index < nrOfAdornedFilenamesFound; ++index)
+ {
+ TChar drive((*(adornedFileNamesFound[index]))[0]);
+ drive.Fold();
+ if ( drive == disk )
+ {
+ adornedFound = ETrue;
+ break;
+ }
+ }
+
+ TBool unadornedFound = aFs.Entry(searchNameUnadorned, *entryPtr) == KErrNone;
+ TBool matchFound = unadornedFound || adornedFound;
+ if (!matchFound)
+ continue; // Nothing relevant found on this drive
+
+ TBool processEclipsingSuspectsFoundOnThisDrive = EFalse;
+
+ // The logic varies whether we found an eclipsable/overwritable file on: (1) The same disk as the one we are installing to
+ // (2) The Z drive (ROM), (3) Any other drive
+ if (disk == targetDisk) // Case (1)
+ {
+ TBool isOverwrite = aFs.Entry(aFileName, *entryPtr) == KErrNone;
+ // At this point, we have 3 possible cases: (1.1) We are correctly overwriting the already present file (a PU),
+ // (1.2) We are incorrectly overwriting the file present, (1.3) We are eclipsing the file (if one of the file names is adorned)
+ //Overwriting: it can be that we found either adorned or unadorned filenames on target drive
+ //Since we don't know wheter the target filename is adorned or unadorned we have to specifically check
+ //wheter we are trying to overwrite a file with that name or not.
+ if (isOverwrite)
+ {
+ // Case 1.1 is handled here - we'll uninstall the old file if we have the right to do it.
+ // Case 1.2 will be handled in CPostrequisitesChecker::WouldOverWriteL, as the error will be caught there
+ HandleFileOverwritingL(aFileName, aApplication);
+ }
+ else
+ {
+ //Case 1.3 is handled here:
+ //we have found a matching filename (either unadorned or adorned); add it to eclipsing suspects
+ processEclipsingSuspectsFoundOnThisDrive = ETrue;
+ }
+ }
+ else if (disk == 'z') // Case (2)
+ {
+ // we are eclipsing a rom file, check if this is authorised:
+ //see implementation of IsEclipsable()
+ if (!IsEclipsableL(searchNameUnadorned))
+ {
+ result = EFalse;
+ break;
+ }
+ }
+ else // Case (3)
+ {
+ processEclipsingSuspectsFoundOnThisDrive = ETrue;
+ }
+
+ //now we need to check whether the unadorned or the adorned filenames found on this drive have to be added to iEclipsableOverwriteFiles
+ if(processEclipsingSuspectsFoundOnThisDrive && unadornedFound && !SecurityCheckUtil::IsToBeUninstalledL(searchNameUnadorned, aApplication))
+ {
+ eclipsableOverwriteFiles.AppendL(searchNameUnadorned);
+ }
+ if(processEclipsingSuspectsFoundOnThisDrive && adornedFound)
+ {
+ nrOfAdornedFilenamesFound = adornedFileNamesFound.Count();
+ for (TInt index=0; index < nrOfAdornedFilenamesFound; ++index)
+ {
+ TChar drive((*(adornedFileNamesFound[index]))[0]);
+ drive.Fold();
+ if ( (drive == disk) && !SecurityCheckUtil::IsToBeUninstalledL(*(adornedFileNamesFound[index]), aApplication))
+ {
+ eclipsableOverwriteFiles.AppendL(*(adornedFileNamesFound[index]));
+ }
+ }
+ }
+ }//end of for (TInt i = 0; i < driveList.Length(); i++)
+
+ //Next step to remove all files from iEclipsableOverwriteFiles that we don't consider
+ //blocking files (blocking files = those that prevent this file from installing)
+ //These non blocking files are those owned by the same package UID as the current one except
+ //that filename that matches the actual filename ie: aFileName
+ //i.e: if aFileName = c:\sys\bin\a.dll and e:\sys\bin\a.dll is found and put in iEclipsableOverwriteFiles earlier or
+ //aFileName = c:\sys\bin\a{000A0004}.dll and e:\sys\bin\a{000A0004}.dll is found and put in iEclipsableOverwriteFiles
+ //then these matching filenames should not be taken out so that the installation will fail
+ //later in CInstallationPlanner::WarnEclipseOverWriteL()
+ //Reason: the installer maintains only one hash per filename, that's only one hash file is calculated for \sys\bin\a.dll and
+ //for \sys\bin\a{000A0004}.dll and not individual ones for each instances on different drives
+ //If result is FALSE there's a blocking file in ROM so no point in processing iEclipsableOverwriteFiles
+ //because the the installation will fail regardless of what iEclipsableOverwriteFiles contains
+ if (result && (eclipsableOverwriteFiles.Count() > 0) )
+ {
+ TUid uid = aApplication.ControllerL().Info().Uid().Uid();
+ //filter out all suspected files that belong to this package
+ SecurityCheckUtil::FilterNonBlockingFilesOfFilenameL(eclipsableOverwriteFiles, aFileName, aApplication.ControllerL().Info().Uid().Uid());
+ }
+ //iEclipsableOverwriteFiles will be searched through later in CInstallationPlanner::WarnEclipseOverWriteL()
+ //looking for files that are not orphaned (ie. belong to any package (SecurityCheckUtil::LookForBlockingFilesL())
+
+ for(TInt i = 0; i < eclipsableOverwriteFiles.Count(); i++)
+ {
+ iEclipsableOverwriteFiles.AppendL(eclipsableOverwriteFiles[i]);
+ }
+
+ CleanupStack::PopAndDestroy(5, &eclipsableOverwriteFiles);
+ return result;
+ }
+
+void CInstallationPlanner::WarnEclipseOverWriteL(CApplication& aApplication)
+ {
+ //Check if we need to pop up dialog to ask client for overwrite or report blocking
+ if (iEclipsableOverwriteFiles.Count()>0)
+ {
+ //See if the swi policy allow overwrite
+ CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
+ TBool allowOrphanedOverwrite = securityPolicy->AllowOrphanedOverwrite();
+ TBool allowProtectedOrphanOverwrite = securityPolicy->AllowProtectedOrphanOverwrite();
+
+ if (allowOrphanedOverwrite)
+ {
+ // check if there is any orphaned file
+ TInt index = SecurityCheckUtil::LookForBlockingFilesL(iEclipsableOverwriteFiles);
+ if (index != KErrNotFound) // if the list contains some non-orphaned file
+ {
+ DisplayErrorL(EUiBlockingEclipsingFile, iEclipsableOverwriteFiles[index]);
+ User::Leave(KErrInvalidEclipsing);
+ }
+ else
+ {
+ TInt fileNameCount=iEclipsableOverwriteFiles.Count();
+ // Question user about all the Orphaned files
+ for (TInt i=0; i<fileNameCount; i++)
+ {
+ TBool overwrite = EFalse;
+ if (! (!allowProtectedOrphanOverwrite &&
+ SecurityCheckUtil::IsProtectedDirectoryL(iEclipsableOverwriteFiles[i])))
+ {
+ CDisplayQuestion* cmd = CDisplayQuestion::NewLC(Plan().AppInfoL(), EQuestionOverwriteFile, iEclipsableOverwriteFiles[i]);
+ UiHandler().ExecuteL(*cmd);
+ if (cmd->ReturnResult())
+ {
+ // Add the file to list of files to remove in the
+ // processing stage. It should not actually be
+ // removed until after security checks validate
+ // that the target which eclipses this file is
+ // valid for this package.
+ aApplication.RemoveFileL(iEclipsableOverwriteFiles[i]);
+ Plan().AddUninstallFileForProgress();
+ overwrite = ETrue;
+ }
+ CleanupStack::PopAndDestroy(cmd);
+ }
+ if (!overwrite)
+ {
+ // User say "no" to overwrite, so blocking
+ DisplayErrorL(EUiBlockingEclipsingFile, iEclipsableOverwriteFiles[i]);
+ User::Leave(KErrInvalidEclipsing);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // policy does not not allow overwrite, error Blocking
+ DisplayErrorL(EUiBlockingEclipsingFile, iEclipsableOverwriteFiles[0]);
+ User::Leave(KErrInvalidEclipsing);
+ }
+ }
+ }
+
+// This function is used to process all files in the controllers
+
+void CInstallationPlanner::ProcessFileDescriptionL(const CFileDescription& aFileDescription, CApplication& aApplication, RPointerArray<CFileDescription>& aFilesToCapabilityCheck, CFilesFromPlannedController& aPlannedFiles)
+ {
+
+ // Check the installation path
+ if (aFileDescription.Target().Data().Length() != 0)
+ {
+ DEBUG_PRINTF2(_L("Processing file for install '%S'"), &(aFileDescription.Target().Data()));
+
+ RFs fs;
+ User::LeaveIfError(fs.Connect());
+ CleanupClosePushL(fs);
+
+ CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
+ TText selDrive = aApplication.UserSelections().Drive();
+ HBufC* targetFileName = securityPolicy->ResolveTargetFileNameLC(
+ aFileDescription.Target().Data(), selDrive);
+
+ // if it's a stub, rewrite it with the user drive selection
+ // which includes pre-installed applications or patches.
+ if (iIsStub)
+ {
+ // Previously, for PA and PP, if files to be "installed" were
+ // on a different drive to the stub SIS file, this code would
+ // leave with KErrSISInvalidTargetFile. See DEF084248/BR1857.1
+ // Now, we re-write all stub file references to the drive where
+ // the SIS file is located, as requested in INC109356. This allows
+ // SIS files with "e:\foo.txt" to install on drives F, G, H, etc.
+ // However, if the SIS file contains files which reference more
+ // than one drive letter, we refuse to install.
+ TPtr targetFileNamePtr(targetFileName->Des());
+
+ if (iStubFirstDriveLetter == KNoDriveSelected)
+ {
+ iStubFirstDriveLetter = targetFileNamePtr[0];
+ }
+
+ if (iStubFirstDriveLetter == targetFileNamePtr[0])
+ {
+ targetFileNamePtr[0] = selDrive;
+ }
+ else
+ {
+ User::Leave(KErrSISInvalidTargetFile);
+ }
+
+
+ targetFileNamePtr[0] = selDrive;
+
+ // Additional re-writing happens in CInstallationProcessor::DoStateProcessFilesL()
+ // since re-writing here is for checking in this method only
+ }
+
+ if(!SecurityCheckUtil::CheckFileName(*targetFileName, iSystemDriveChar) ||
+ SecurityCheckUtil::IsSubstedDriveL(fs, *targetFileName))
+ {
+ DisplayErrorL(EUiInvalidFileName, *targetFileName);
+ User::Leave(KErrSISInvalidTargetFile);
+ }
+
+ // For operations other than filenull we need the drive to exist
+ // and we need to check for invalid eclipsing.
+ if (aFileDescription.Operation() != EOpNull)
+ {
+ // must be writable for ValidEclipseL
+ TFileName installName = *targetFileName;
+
+ // check the target drive actually exists, and is mounted
+ TInt driveNo;
+ User::LeaveIfError(fs.CharToDrive(installName[0], driveNo));
+ TVolumeInfo volInfo;
+ if (KErrNone != fs.Volume(volInfo, driveNo))
+ {
+ DisplayErrorL(EUiDiskNotPresent, aFileDescription.Target().Data());
+ User::Leave(KErrSISInvalidTargetFile);
+ }
+
+ // Check for invalid eclipsing of files already on the device.
+ if (!ValidEclipseL(fs, installName, aApplication))
+ {
+ //The file is in ROM and not eclipsable
+ DisplayErrorL(EUiAlreadyInRom, aFileDescription.Target().Data());
+ User::Leave(KErrInvalidEclipsing);
+ }
+
+ // Check for clashes with other applications in the plan.
+ CheckFilesFromPlannedControllersL(*targetFileName, aPlannedFiles);
+
+ // Add file to list to check in subsequent applications.
+ aPlannedFiles.AppendL(targetFileName);
+ CleanupStack::Pop(targetFileName);
+
+ aFilesToCapabilityCheck.AppendL(&aFileDescription);
+
+ // check for plug-ins
+ TInt len = KPluginPath().Length();
+ if ((targetFileName->Length() >= len+2) && targetFileName->Mid(2,len).CompareF(KPluginPath) == 0)
+ {
+ Plan().SetContainsPlugins(ETrue);
+ }
+ // if it's an apparc file, record it in the plan for use later
+ AddApparcFilesToPlanL(targetFileName->Des());
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy(targetFileName);
+ }
+
+ CleanupStack::PopAndDestroy(&fs); // fs
+
+ // it's a file to copy, add it to the current application
+ if (!iTextSkip || aFileDescription.Operation() == EOpNull)
+ {
+ aApplication.AddFileL(aFileDescription, aApplication.UserSelections().Drive());
+ Plan().AddInstallFileForProgress(aFileDescription.UncompressedLength());
+ }
+ else
+ {
+ aApplication.SkipFileOnInstallL(aFileDescription, aApplication.UserSelections().Drive());
+ }
+ }
+
+
+ //Add to files to run if we need to
+ if (aFileDescription.Operation() == EOpRun)
+ {
+#ifdef SYMBIAN_SWI_RUN_ON_INSTALL_COMPLETE
+
+ // Can't run at install AND after install with the same file. FILEMIME compiles to FM,RI
+ // we must block this or you can't get just (RUNAFTERINSTALL, FM) and this is the more
+ // common usecase.
+ if (aFileDescription.OperationOptions() & EInstFileRunOptionAfterInstall)
+ {
+ Plan().RunFileAfterInstallL(aFileDescription, aApplication.UserSelections().Drive(), aApplication.IsStub());
+ }
+ else if (aFileDescription.OperationOptions() & EInstFileRunOptionInstall)
+ {
+ aApplication.RunFileOnInstallL(aFileDescription, aApplication.UserSelections().Drive());
+ // running the app will force SWI to notify Apparc in advance so the current list
+ // of files have already been processed.
+ Plan().ResetAppArcRegFiles();
+ }
+#else
+ if (aFileDescription.OperationOptions() & EInstFileRunOptionInstall)
+ {
+ aApplication.RunFileOnInstallL(aFileDescription, aApplication.UserSelections().Drive());
+ // running the app will force SWI to notify Apparc in advance so the current list
+ // of files have already been processed.
+ Plan().ResetAppArcRegFiles();
+ }
+#endif // SYMBIAN_SWI_RUN_ON_INSTALL_COMPLETE
+ }
+ // Files to display
+ else if (aFileDescription.Operation() == EOpText)
+ {
+ if ( !aApplication.IsStub() )
+ aApplication.DisplayFileOnInstallL(aFileDescription, aApplication.UserSelections().Drive());
+ }
+
+ // Reset the iTextskip value as this is applicable for the next one file only.
+ iTextSkip = EFalse;
+ if (aFileDescription.OperationOptions() & EInstFileTextOptionSkipIfNo)
+ {
+ iTextSkip = ETrue;
+ }
+ }
+
+void CInstallationPlanner::AddApparcFilesToPlanL(const TDesC& aTargetFileName)
+ {
+ _LIT(KApparcRegDir, "\\private\\10003a3f\\import\\apps\\");
+ TParsePtrC filename(aTargetFileName);
+ if (filename.Path().Left(KApparcRegDir().Length()).CompareF(KApparcRegDir) == 0)
+ {
+ // we're installing a reg file so add it to our list.
+ Plan().AddAppArcRegFileL(aTargetFileName);
+ }
+ }
+
+void CInstallationPlanner::ProcessFilesToRemoveL(CApplication& aApplication, RSisRegistryWritableEntry& aRegistryEntry)
+ {
+ TBool romBasedFile(EFalse);
+ if (aApplication.IsUpgrade() || aApplication.IsPartialUpgrade())
+ {
+ // There may be files to remove as part of the plan
+
+ RPointerArray<CSisRegistryFileDescription> fileDescriptions;
+ CleanupResetAndDestroy<RPointerArray<CSisRegistryFileDescription> >::PushL(fileDescriptions);
+ aRegistryEntry.FileDescriptionsL(fileDescriptions);
+
+ TInt count(fileDescriptions.Count());
+ for (TInt i=0;i < count; ++i)
+ {
+ //Consider only non-ROM based files.
+ CSisRegistryFileDescription* description = fileDescriptions[i];
+ romBasedFile = ((description->Target().Mid(0,1) == _L("z")) ||
+ (description->Target().Mid(0,1) == _L("Z")));
+ // Skip filenull cases.
+ if ((description->Operation() != EOpNull) && !romBasedFile)
+ {
+ // If this is either an SA upgrade or if its a PU
+ // where the file is to be replaced, remove it first.
+ if (aApplication.IsUpgrade())
+ {
+ DEBUG_PRINTF2(_L("Planning file for removal '%S'"), &(description->Target()));
+ aApplication.RemoveFileL(*description);
+ Plan().AddUninstallFileForProgress();
+ }
+ else
+ {
+ DEBUG_PRINTF2(_L("File '%S' may be legally overwritten"), &(description->Target()));
+ // create a new copy and append it to the array
+ CSisRegistryFileDescription* desc = CSisRegistryFileDescription::NewL(*description);
+ CleanupStack::PushL(desc);
+ iOverwriteableFiles.AppendL(desc);
+ CleanupStack::Pop(desc);
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(&fileDescriptions);
+
+ }
+ }
+
+// find the application is allowed to install based on SU Cert Rules if
+// 1. if the sis file is signed by certificate trusted by the device (SU Cert)
+// 2. if the sis file is of type SA/SP/PU with RU/RU+NR flag
+// 3. the sis file validation status is trusted
+TBool CInstallationPlanner::IsValidSystemUpgradeL(const CApplication& aApplication)
+ {
+ Sis::TInstallType type = aApplication.ControllerL().Info().InstallType();
+ Sis::TInstallFlags flag = aApplication.ControllerL().Info().InstallFlags();
+ TBool allowedType = (type == EInstInstallation || (type == EInstAugmentation) || type == EInstPartialUpgrade );
+ TBool allowedFlag = (flag & EInstFlagROMUpgrade);
+ // PA and PP is not allowed
+ // Treat an SA/SP/PU on a removable media stub as a preinstalled apps/patch
+
+ return (aApplication.ControllerL().IsSignedBySuCert() && allowedType && allowedFlag &&
+ aApplication.ControllerL().TrustStatus().ValidationStatus()
+ >= EValidatedToAnchor);
+ }
+
+
+// CInstallationPair::TUidApplicationPair functions
+
+CInstallationPlanner::CPackageApplicationPair::CPackageApplicationPair(CApplication& aApplication)
+ : iApplication(aApplication)
+ {
+ }
+
+void CInstallationPlanner::CPackageApplicationPair::ConstructL(CSisRegistryPackage& aPackage)
+ {
+ iPackage=CSisRegistryPackage::NewL(aPackage);
+ }
+
+CInstallationPlanner::CPackageApplicationPair::~CPackageApplicationPair()
+ {
+ delete iPackage;
+ }
+
+CSisRegistryPackage& CInstallationPlanner::CPackageApplicationPair::Package() const
+ {
+ return *iPackage;
+ }
+
+CApplication& CInstallationPlanner::CPackageApplicationPair::Application()
+ {
+ return iApplication;
+ }
+
+CInstallationPlanner::CPackageApplicationPair* CInstallationPlanner::CPackageApplicationPair::NewLC(CSisRegistryPackage& aPackage, CApplication& aApplication)
+ {
+ CPackageApplicationPair* self=new(ELeave) CPackageApplicationPair(aApplication);
+ CleanupStack::PushL(self);
+ self->ConstructL(aPackage);
+ return self;
+ }
+
+//CFilesFromPlannedController class functions
+CInstallationPlanner::CFilesFromPlannedController::CFilesFromPlannedController(TUid aUid, TUid aParentUid, Sis::TInstallType aInstallType, Sis::CString* aName)
+ :iUid(aUid),iParentUid(aParentUid),iCount(0),iInstallType(aInstallType),iName(aName)
+ {
+ }
+
+CInstallationPlanner::CFilesFromPlannedController::~CFilesFromPlannedController()
+ {
+ iFileNames.ResetAndDestroy();
+ }
+
+CInstallationPlanner::CFilesFromPlannedController* CInstallationPlanner::CFilesFromPlannedController::NewLC(TUid aUid, TUid aParentUid, Sis::TInstallType aInstallType, Sis::CString* aName)
+ {
+ CFilesFromPlannedController* self = new (ELeave) CFilesFromPlannedController(aUid, aParentUid, aInstallType, aName);
+ CleanupStack::PushL(self);
+ return self;
+ }
+
+void CInstallationPlanner::CFilesFromPlannedController::AppendL(HBufC* aFileName)
+ {
+ iFileNames.AppendL(aFileName);
+ ++iCount;
+ }
+
+TUid CInstallationPlanner::CFilesFromPlannedController::Uid()
+ {
+ return iUid;
+ }
+
+TUid CInstallationPlanner::CFilesFromPlannedController::ParentUid()
+ {
+ return iParentUid;
+ }
+
+TInt CInstallationPlanner::CFilesFromPlannedController::Count()
+ {
+ return iCount;
+ }
+
+TChar CInstallationPlanner::CFilesFromPlannedController::Drive()
+ {
+ return iDrive;
+ }
+
+void CInstallationPlanner::CFilesFromPlannedController::SetDrive(TChar& aDrive)
+ {
+ iDrive = aDrive;
+ }
+
+Sis::CString* CInstallationPlanner::CFilesFromPlannedController::Name()
+ {
+ return iName;
+ }
+
+Sis::TInstallType CInstallationPlanner::CFilesFromPlannedController::InstallType()
+ {
+ return iInstallType;
+ }
+
+TBool CInstallationPlanner::CFilesFromPlannedController::IsMatched(const TDesC& aFileName)
+ {
+ TBool match = EFalse;
+ TInt count = iFileNames.Count();
+ for(TInt i=0; i<count; ++i)
+ {
+ if(!aFileName.CompareF(*iFileNames[i]))
+ {
+ match = ETrue;
+ break;
+ }
+ }
+ return match;
+ }
+
+TBool CInstallationPlanner::CFilesFromPlannedController::IsEclipsed(const TDesC& aFileName)
+ {
+ TBool eclipse = EFalse;
+ TInt count = iFileNames.Count();
+ for(TInt i=0; i<count; ++i)
+ {
+ if(aFileName.Mid(1).CompareF((*iFileNames[i]).Mid(1)) == 0)
+ {
+ eclipse = ETrue;
+ break;
+ }
+ }
+ return eclipse;
+ }
+
+const CController& CInstallationPlanner::CurrentController()
+ {
+ return iControllersToProcess[iCurrentController].Controller();
+ }
+
+const Sis::CController& CInstallationPlanner::MainController()
+ {
+ return iControllersToProcess[0].Controller();
+ }
+
+TInt CInstallationPlanner::GetControllerReference(TUid aUid)
+ {
+ TInt count = iControllersToProcess.Count();
+ for(TInt i=0; i<count; ++i)
+ {
+ if(aUid == iControllersToProcess[i].Controller().Info().Uid().Uid())
+ {
+ return i;
+ }
+ }
+ return KErrNotFound;
+ }
+
+void CInstallationPlanner::PlanCurrentControllerL(RPointerArray<CFileDescription>& aFilesToCapabilityCheck)
+ {
+ if(!iMainApplication)
+ {
+ // Plan main controller
+ iMainApplication = ProcessControllerL(CurrentController(), 0, aFilesToCapabilityCheck, CurrentController().Info().Uid().Uid()); // Top-level controller has embedded data index of 0
+ }
+ else
+ {
+ CApplication* parentApplication = iControllersToProcess[iCurrentController].ParentApplication();
+ User::LeaveIfNull(parentApplication);
+
+ CApplication* application=ProcessControllerL(CurrentController(), parentApplication->AbsoluteDataIndex(), aFilesToCapabilityCheck, parentApplication->ControllerL().Info().Uid().Uid());
+ CleanupStack::PushL(application);
+ parentApplication->AddEmbeddedApplicationL(application); // ownership transferred
+ CleanupStack::Pop(application);
+ }
+ }
+
+TBool CInstallationPlanner::GetNextController()
+ {
+ // Find the next controller in our list of controllers
+ if(++iCurrentController < iControllersToProcess.Count())
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+void CInstallationPlanner::DisplayErrorL(TErrorDialog aType, const TDesC& aParam)
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Display the error message only when the planner is not in info collection mode.
+ if(!IsInInfoCollectionMode())
+ {
+ CDisplayError* displayError=CDisplayError::NewLC(Plan().AppInfoL(), aType, aParam);
+ UiHandler().ExecuteL(*displayError);
+ CleanupStack::PopAndDestroy(displayError);
+ }
+ #else
+ CDisplayError* displayError=CDisplayError::NewLC(Plan().AppInfoL(), aType, aParam);
+ UiHandler().ExecuteL(*displayError);
+ CleanupStack::PopAndDestroy(displayError);
+ #endif
+ }
+
+void CInstallationPlanner::CheckFilesFromPlannedControllersL(const TDesC& aFileName, CFilesFromPlannedController& aPlannedFiles) const
+ {
+ TBool check = EFalse;
+
+ // Check all files from already planned controllers to see if this file
+ // will overwrite or eclipse. Note that the array may contain files from
+ // the current controller beyond the last index checked here; a single
+ // package is allowed to overwrite or eclipse its own target files.
+ TInt count = iFilesFromPlannedControllers.Count();
+ for(TInt i=0; i<count; ++i)
+ {
+ check = EFalse;
+
+ if(aPlannedFiles.Uid() != iFilesFromPlannedControllers[i]->Uid())
+ {//This is a different package so we should check files
+ check = ETrue;
+ }
+ else
+ {
+ //Do not allow that two packages with the same UID are embedded by different base packages
+ if(aPlannedFiles.ParentUid() != iFilesFromPlannedControllers[i]->ParentUid())
+ {
+ User::Leave(KErrAlreadyExists);
+ }
+ else
+ {
+ Sis::TInstallType plannedType = iFilesFromPlannedControllers[i]->InstallType();
+ Sis::TInstallType currentType = aPlannedFiles.InstallType();
+
+ if(currentType != plannedType)
+ {
+ //Augmentations can't overwrite files from the base package or its PU
+ if((currentType == EInstAugmentation) || (plannedType == EInstAugmentation))
+ {
+ check = ETrue;
+ }
+ }
+ else
+ {
+ //SA packages delivered within the embedding package can not be SA
+ //upgraded from within the same package
+ if(currentType == EInstInstallation)
+ {
+ User::Leave(KErrAlreadyExists);
+ }
+ //multiple partial upgrades to the base are supported
+ //multiple separate augmentations are supported
+ }
+ }
+ }
+
+ if(check)
+ {
+ if(iFilesFromPlannedControllers[i]->IsMatched(aFileName))
+ {
+ // File exactly matches one from another controller already
+ // processed in this plan.
+ User::Leave(KErrAlreadyExists);
+ }
+ else if(iFilesFromPlannedControllers[i]->IsEclipsed(aFileName))
+ {
+ // File would eclipse one from another controller already
+ // processed in this plan.
+ User::Leave(KErrInvalidEclipsing);
+ }
+ }
+ }
+ }
+
+TBool CInstallationPlanner::IsAugmentationUpgradeL(const Sis::CController& aController, RSisRegistryEntry& aRegistryEntry,
+ RSisRegistrySession& aRegistrySession)
+ {
+ TBool ret = EFalse;
+ if (aController.Info().InstallType() == Sis::EInstAugmentation)
+ {
+ CSisRegistryPackage* package = CSisRegistryPackage::NewLC(aController.Info().Uid().Uid(),
+ aController.Info().Names()[iDisplayLanguageIndex]->Data(),
+ aController.Info().UniqueVendorName().Data());
+
+ // first check this isn't exactly the same package name...
+ CSisRegistryPackage* base = aRegistryEntry.PackageL();
+ CleanupStack::PushL(base);
+ if ((base->Uid() == package->Uid()) && (base->Name() == package->Name()))
+ {
+ // cannot upgrade a base package with an augmentation!
+ User::Leave(KErrInvalidUpgrade);
+ }
+ CleanupStack::PopAndDestroy(base);
+
+ // See if we can find this package in the augmentations to this entry
+ RPointerArray<CSisRegistryPackage> augmentations;
+ CleanupResetAndDestroyPushL(augmentations);
+ aRegistryEntry.AugmentationsL(augmentations);
+
+ TInt count(augmentations.Count());
+ for (TInt i = 0; i < count; ++i)
+ {
+ if ((package->Uid() == augmentations[i]->Uid()) &&
+ (package->Name() == augmentations[i]->Name()))
+ {
+ // close and reopen the registry entry as that for the augmentation
+ aRegistryEntry.Close();
+ aRegistryEntry.OpenL(aRegistrySession, *augmentations[i]);
+
+ ret = ETrue;
+ break;
+ }
+ }
+ CleanupStack::PopAndDestroy(2, package); // augmentations
+ }
+
+ return ret;
+ }
+
+TBool CInstallationPlanner::IsAugmentationUpgrade(const Sis::CController& aController)
+ {
+ TBool isUpgrade = EFalse;
+ TInt count = iFilesFromPlannedControllers.Count();
+ for(TInt i=0; i<count; i++)
+ {
+ if((aController.Info().Uid().Uid() == iFilesFromPlannedControllers[i]->Uid())
+ && (iFilesFromPlannedControllers[i]->InstallType() == EInstAugmentation))
+ {
+ //If augmentation has the same name with another augmentation in the list, it's a upgrade
+ if(!iFilesFromPlannedControllers[i]->Name()->Data().CompareF(aController.Info().Names()[0]->Data()))
+ {
+ isUpgrade = ETrue;
+ }
+ }
+ }
+
+ return isUpgrade;
+ }
+
+//Checks whether an SP/PU package's base package has already been planned
+TBool CInstallationPlanner::IsPlannedControllerL(const Sis::CController& aController, TInt& aIndex, TUid aParentUid)
+ {
+ TBool inList = EFalse;
+ TInt i;
+ for(i=0; i<iFilesFromPlannedControllers.Count(); i++)
+ {
+ if(aController.Info().Uid().Uid() == iFilesFromPlannedControllers[i]->Uid())
+ {
+ if(aController.Info().InstallType() == EInstAugmentation)
+ {
+ //If augmentation has the same name with the base package in the list, it's an invalid upgrade
+ if(!iFilesFromPlannedControllers[i]->Name()->Data().CompareF(aController.Info().Names()[0]->Data())
+ && (iFilesFromPlannedControllers[i]->InstallType() == EInstInstallation))
+ {
+ User::Leave(KErrInvalidUpgrade);
+ }
+ }
+ //Augmentations or partial upgrades must be embedded by the same base pacakge
+ if(aParentUid == iFilesFromPlannedControllers[i]->ParentUid())
+ {
+ inList = ETrue;
+ break;
+ }
+ }
+ }
+ aIndex = i;
+ return inList;
+ }
+
+/** This function takes a fully qualified name and searches the filesystem through for all possible adorned filename matches.
+ * Besides that it calculates the unadorned version of the input filename as well and return it through the corresponding given
+ * input reference variable.
+ * @param aFs A valid file server session handle
+ * @param aFileName The fully qualified filename (full path and name)
+ * @param aUnadornedName The calulated unadorned name is returned through this variable(full path and unadorned name calculated from aFileName)
+ * @param aAdornedFileNamesFound All the found adorned name matches are returned through this pointer array to descriptors
+ */
+void CInstallationPlanner::AdornedProcessingOfFileL(RFs& aFs, TDesC& aFileName, TDes& aUnadornedName, RPointerArray<HBufC>& aAdornedFileNamesFound)
+ {
+ TParsePtrC parsedFileName(aFileName);
+ TInt originalNameAndExtLength = parsedFileName.NameAndExt().Length();
+ RBuf searchNameWild;
+ searchNameWild.CreateL(originalNameAndExtLength+Swi::FileNameUnadornedPartLength); //searchname wild is max 10 chars longer than original filename+ext
+ searchNameWild.CleanupClosePushL();
+ RBuf unadornedName;
+ unadornedName.CreateL(originalNameAndExtLength); //unadorned name is never longer than original name
+ unadornedName.CleanupClosePushL();
+
+ Swi::GetUnadornedFileName(parsedFileName.NameAndExt(), unadornedName);
+ aUnadornedName = parsedFileName.DriveAndPath();
+ aUnadornedName.Append(unadornedName);
+ Swi::GenerateSearchNameWildL(parsedFileName.NameAndExt(), searchNameWild);
+ Swi::FindAllAdornedVariantsL(aFs, searchNameWild, parsedFileName.Path(), aAdornedFileNamesFound);
+ CleanupStack::PopAndDestroy(2, &searchNameWild);
+ }
+
+/** This function handles overwriting situation (i.e: we are trying to install c:\somedir\somename.ext however it already exist)
+ * In this case we have two possible scenarios:
+ * 1.) We are correctly overwriting the already present file (a PU)
+ * 2.) We are incorrectly overwriting the file present (in this case the error will be caught later in CPostrequisitesChecker::WouldOverWriteL)
+ * @param aFileName The fully qualified filename (full path and name)
+ * @param aApplication installation plan
+ */
+void CInstallationPlanner::HandleFileOverwritingL(TDesC& aFileName, CApplication& aApplication)
+ {
+ // Case 1.1 is handled here - we'll uninstall the old file if we have the right to do it.
+ // Case 1.2 will be handled in CPostrequisitesChecker::WouldOverWriteL, as the error will be caught there
+
+
+ // sis file allowed to install based on SU Cert Rules and not of SP type
+ // are allowed to overwrite files owned by other packages. Add it to the plan for removal
+ // Files are not removed at install time if is a propagation.
+ TBool spInstall = (aApplication.ControllerL().Info().InstallType() == Sis::EInstAugmentation);
+ if (iIsValidSystemUpgrade && !spInstall && !iIsPropagated)
+ {
+ aApplication.RemoveFileL(aFileName);
+ Plan().AddUninstallFileForProgress();
+ }
+
+ TInt count(iOverwriteableFiles.Count());
+ for (TInt i = 0; i < count; i++)
+ {
+ CSisRegistryFileDescription* description = iOverwriteableFiles[i];
+ if (aFileName.CompareF(description->Target()) == 0 && (description->Operation() != EOpNull))
+ {
+ aApplication.RemoveFileL(*description);
+ Plan().AddUninstallFileForProgress();
+ }
+ }
+ }
+
+// store references to supplied Controller and application
+TControllerAndParentApplication::TControllerAndParentApplication(
+ const CController& aController, CApplication* aParentApplication) :
+ iController(aController), iParentApplication(aParentApplication)
+ {
+
+ }
+
+const CController& TControllerAndParentApplication::Controller()
+ {
+ return iController;
+ }
+
+CApplication* TControllerAndParentApplication::ParentApplication()
+ {
+ return iParentApplication;
+ }
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+void CInstallationPlanner::SetInInfoCollectionMode(TBool aMode)
+ {
+ iIsInInfoCollectionMode = aMode;
+ }
+
+TBool CInstallationPlanner::IsInInfoCollectionMode()
+ {
+ return iIsInInfoCollectionMode;
+ }
+#endif