--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/smartinstaller/bootstrap/src/bootstrapappui.cpp Fri Feb 19 15:03:34 2010 +0530
@@ -0,0 +1,1385 @@
+/*
+* Copyright (c) 2009-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:
+* CBootstrapAppUi class implementation.
+*
+*
+*/
+
+
+// INCLUDE FILES
+#include <aknglobalnote.h>
+#include <stringloader.h>
+#include <swinstdefs.h>
+#include <swi/sisregistrysession.h>
+#include <swi/sisregistryentry.h>
+#include <swi/swispubsubdefs.h>
+#include <httpdownloadmgrcommon.h>
+#include <coeutils.h>
+#include <apgcli.h>
+
+#include <SenDomFragment.h>
+#include <SenXmlReader.h>
+#include <SenElement.h>
+
+#include <centralrepository.h> // CRepository
+#include <browseruisdkcrkeys.h> // KCRUidBrowser
+#include <httpdownloadmgrcommon.h>
+#include <es_enum.h>
+#include <rconnmon.h>
+
+#include "bootstrapapplication.h"
+#include "bootstrapappui.h"
+#include "bootstrapconst.h"
+#include "bootstrapglobalwaitnoteobserver.h"
+#include "bootstrapinstallationobserver.h"
+#include "debug.h"
+#include "globals.h"
+#include "macros.h"
+#include "config.h"
+
+// ADM binary name
+_LIT(KAdmExePath, "ADM.exe");
+
+_LIT(KDownloadFolder,"?:\\ADM\\");
+// Sis file extension
+_LIT(KSisExtn,".SIS");
+_LIT(KSisxExtn,".SISX");
+// Xml file extension
+_LIT(KXMLExtn,".XML");
+// Dep file extension
+_LIT(KDepExtn,"_DEP");
+// ADM changes file name
+_LIT8(KAdmChangesFile, "adm_changes.xml");
+
+// Logging information
+_LIT(KADMLogDir, "ADM");
+_LIT(KBootstrapLogFileName, "Bootstraplog.txt" );
+_LIT(KBootstrapLogFile, "?:\\logs\\ADM\\Bootstraplog.txt");
+
+// Private folder of SWI Daemon
+_LIT(KSWIDaemonPrivateFolder, "\\private\\10202dce\\");
+_LIT8(KForwardSlash, "/");
+
+// ADM Uid
+const TUid KUidAdm = { 0x2002CCCE };
+// Max no of connection attempts to Installer
+const TInt KMaxInstallerConnectionAttempts = 6;
+
+// ============================ MEMBER FUNCTIONS ===============================
+void CBootstrapAppUi::ConstructL()
+ {
+ // Create the log
+ INIT_DEBUG_LOG( KBootstrapLogFile(), KADMLogDir, KBootstrapLogFileName );
+
+ // Hide from application task list
+ HideApplicationFromFSW();
+
+ // Send us to background
+ SendToBackgroundL();
+
+ // Initialise app UI with standard value.
+ BaseConstructL( ENoScreenFurniture /* CAknAppUi::EAknEnableSkin */ );
+
+ StatusPane()->MakeVisible(EFalse);
+
+ // Wait for the installer to be free
+ WaitForInstallCompleteL();
+
+ // Bring us to foreground
+ SendToBackgroundL(EFalse);
+
+ // Get the Uid of the latest installed package
+ iWrapperPackageUid = GetLatestInstalledL();
+
+ // Connect to the Download Manager
+ TBool masterInstance( !iEikonEnv->StartedAsServerApp() );
+ iDownloadManager.ConnectL( KUidBootstrapApp, *this, masterInstance );
+
+ // Read the config file
+ ReadConfigurationL();
+
+ // Get the dep file and actual application name(if present)
+ TRAPD(err, SetFileNameInfoL());
+ if (err != KErrNone)
+ {
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+
+#ifdef FEATURE_BOOTSTRAP_SETIAP
+ SetIAPL();
+#endif
+
+ ShowGlobalWaitNoteL();
+
+ // Create view object
+
+ User::LeaveIfError(iLauncher.Connect());
+
+ LOG("Checking ADM presence in the device");
+ iIsAdmInstalled = IsPackagePresentL(KUidAdm, iAdmInstalledVersion);
+
+ LOG( "* State changed to EChangesDownloadState" );
+ iAppState = EChangesDownloadState;
+ DownloadL();
+ }
+
+// -----------------------------------------------------------------------------
+// CBootstrapAppUi::CBootstrapAppUi()
+// C++ default constructor can NOT contain any code, that might leave.
+// -----------------------------------------------------------------------------
+//
+CBootstrapAppUi::CBootstrapAppUi():
+ iAllowForeground(EFalse),
+ iIsAdmInstalled(EFalse),
+ iAdmChangesInfo()
+ {
+ LOG ( "SmartInstaller starts");
+ // disable possible transition effects
+ SetFullScreenApp(EFalse);
+ }
+
+// -----------------------------------------------------------------------------
+// CBootstrapAppUi::~CBootstrapAppUi()
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CBootstrapAppUi::~CBootstrapAppUi()
+ {
+ LOG( "Bootstrap App ends");
+ DELETE_IF_NONNULL( iDepFilename );
+ DELETE_IF_NONNULL( iSisFileName );
+ delete iGlobalWaitNoteObserver;
+ delete iGlobalWaitNote;
+ delete iInstallObsrv;
+ delete iConfigUrl;
+ delete iUrl;
+ delete iDownloadFileName;
+
+ iDownloadManager.DeleteAll();
+ iDownloadManager.Close();
+
+ iLauncher.Close();
+
+ CLOSE_DEBUG_LOG;
+ }
+
+void CBootstrapAppUi::HandleGlobalWaitNoteCancel(const TInt& aStatus)
+ {
+ LOG3( "+ Cancel note %d, %d", iAppState, aStatus );
+
+ // Do the cleanup based on the state
+ if (aStatus == -1)
+ {
+ iGlobalWaitNoteId = -1;
+
+ switch(iAppState)
+ {
+ case EInitialState:
+ // No CleanUp required here
+ break;
+
+ case EChangesDownloadState:
+ {
+ // Cancel download
+ iDownloadManager.ResetAll();
+ break;
+ }
+
+ case EChangesParseState:
+ {
+ // Delete the downloaded dep file
+ if (iDownloadFileName)
+ {
+ DeleteFile(*iDownloadFileName);
+ }
+ }
+ // fall-through
+
+ case EADMDownloadState:
+ {
+ // Cancel download
+ iDownloadManager.ResetAll();
+ break;
+ }
+
+ case EADMInstallState:
+ {
+ // Cancel installation
+ iLauncher.CancelAsyncRequest(SwiUI::ERequestSilentInstall);
+ // Delete the downloaded sis file.
+ if (iDownloadFileName)
+ {
+ DeleteFile(*iDownloadFileName);
+ }
+ }
+ // fall-through
+
+ case EADMLaunchState:
+ // No CleanUp required here
+ break;
+
+ default:
+ break;
+ }
+
+ TRAP_IGNORE(
+ ShowNoteL(EAknGlobalErrorNote, R_INSTALLATION_CANCELLED);
+ );
+
+ // Always delete the dep file in case of failure in
+ // bootstrap to ensure correct dep file is picked up
+ // when the outer package is installed.
+ if((KBootstrapVersion == 3)&&(iDepFilename))
+ {
+ DeleteFile(*iDepFilename);
+ }
+ else if((KBootstrapVersion == 4)&&(iSisFileName))
+ {
+ DeleteFile(*iSisFileName);
+ }
+
+ // Close the bootstrap application
+ CloseApp();
+ }
+ LOG3( "- Cancel note %d, %d", iAppState, aStatus );
+ }
+
+void CBootstrapAppUi::ParseChangesInfoL( const TDesC& aChangesFileName )
+ {
+ LOG2("+ Parse File ('%S')", &aChangesFileName);
+
+ // Initailize the parser
+ CSenXmlReader* XmlReader = CSenXmlReader::NewLC(EErrorOnUnrecognisedTags);
+ CSenDomFragment* DomFragment = CSenDomFragment::NewL();
+ CleanupStack::PushL(DomFragment);
+
+ XmlReader->SetContentHandler(*DomFragment);
+ DomFragment->SetReader(*XmlReader);
+
+ // Parse the provided changes file
+ XmlReader->ParseL(CEikonEnv::Static()->FsSession(), aChangesFileName);
+
+ // Get package version
+ CSenElement* packageElement;
+ packageElement = DomFragment->AsElement().Element(KFieldVersion);
+ if (packageElement == NULL)
+ {
+ User::Leave(EMissingVersion);
+ }
+ else
+ {
+ TPtrC8 versionPtr = packageElement->Content();
+ TVersion ver;
+ if (SetVersion(versionPtr, iAdmChangesInfo.iVersion) == EFalse)
+ {
+ User::Leave(EInvalidVersion);
+ }
+ }
+
+ // Get the ADM sis file name
+ packageElement = DomFragment->AsElement().Element(KFieldSisName);
+ if (packageElement)
+ {
+ TPtrC8 sisNamePtr = packageElement->Content();
+ iAdmChangesInfo.iSisName = sisNamePtr.AllocL();
+ }
+ else
+ {
+ User::Leave(EMissingSisFileName);
+ }
+
+ //URL read from ADM changes file is disabled.
+ //ADM.sis will be fetched from the default config url always...same as ADM_changes.xml
+#if 0
+ // Get the optional URL
+ packageElement = DomFragment->AsElement().Element(KFieldUrl);
+ if (packageElement)
+ {
+ TPtrC8 urlPtr = packageElement->Content();
+ iAdmChangesInfo.iUrl = urlPtr.AllocL();
+ }
+#endif
+
+ CleanupStack::PopAndDestroy( DomFragment ) ;
+ CleanupStack::PopAndDestroy( XmlReader ) ;
+
+ LOG( "- ParseChangesInfoL()" );
+ }
+
+#ifdef FEATURE_BOOTSTRAP_SETIAP
+void CBootstrapAppUi::SetIAPL()
+ {
+ LOG( "+ CBootstrapAppUi::SetIAPL()" );
+ // Use the browser default IAP, if available
+ CRepository *repository = CRepository::NewLC( KCRUidBrowser );
+ TInt ret, browserIAP;
+ ret = repository->Get( KBrowserDefaultAccessPoint, browserIAP );
+ CleanupStack::PopAndDestroy( repository );
+
+ LOG3("Browser IAP ID = %d, ret = %d ", browserIAP, ret);
+ if ( ( ret != KErrNone ) || ( browserIAP < 0 ) )
+ {
+
+ browserIAP = 0;
+
+ }
+
+ //No Browser default IAP. Fetch from connection monitor
+ RConnectionMonitor monitor;
+ CleanupClosePushL(monitor);
+
+ TUint count;
+ TRequestStatus status;
+
+ monitor.ConnectL();
+ monitor.GetConnectionCount( count, status );
+ LOG2("ConnMon connCount = %d", count);
+ User::WaitForRequest( status );
+ if ( status.Int() != KErrNone )
+ {
+ // error
+ LOG2("ConnMon.ConnCount() ret = %d, ignoring.", status.Int() );
+ }
+
+ // get all available IAPs
+ TConnMonIapInfoBuf iapBuf;
+
+ monitor.GetPckgAttribute( EBearerIdAll, 0, KIapAvailability, iapBuf, status );
+ User::WaitForRequest( status ) ;
+
+ if ( status.Int() != KErrNone )
+ {
+ LOG2("ConnMon.GetAttr() ret = %d, ignoring.", ret);
+ }
+ else
+ {
+ TInt countIaps = iapBuf().iCount;
+ LOG2("IAP count %d", countIaps);
+
+ // Get the IAPId of the first IAP in the buffer.
+ iIAP = iapBuf().iIap[ 0 ].iIapId;
+
+ LOG2("IAP ID[0] is %d", iIAP);
+
+ //Now check whether any IAPId matches BrowserIAP, if yes then set the browserIAP as iIAP
+ while( countIaps > 0)
+ {
+ LOG3("IAP %d: ID = %d", countIaps, iapBuf().iIap[ countIaps ].iIapId);
+ if( iapBuf().iIap[ countIaps ].iIapId == browserIAP)
+ {
+ iIAP = browserIAP;
+ break;
+ }
+ countIaps--;
+ }
+
+ LOG2("IAP ID after comparison %d", iIAP);
+ }
+
+
+
+ if ( iIAP > 0)
+ {
+#ifdef DO_LOG
+ TBuf<64> iapName;
+ monitor.GetStringAttribute( iIAP, 0, KIAPName, iapName, status );
+ User::WaitForRequest( status );
+ if ( status.Int() != KErrNone )
+ {
+ LOG2( "ConnMon.GetStrAttr() ret = %d, ignoring.", status.Int() );
+ }
+ LOG3( "Setting DownloadManager IAP to %d ('%S'). No user prompt for IAP.", iIAP, &iapName );
+#endif
+ // Set the download manager to silent mode
+ iDownloadManager.SetBoolAttribute( EDlMgrSilentMode, ETrue );
+ iDownloadManager.SetIntAttribute( EDlMgrIap, iIAP );
+ }
+ //else implies user will be prompted.
+ CleanupStack::PopAndDestroy( &monitor );
+ }
+
+ LOG( "- CBootstrapAppUi::SetIAPL()" );
+ }
+#endif
+void CBootstrapAppUi::DownloadL()
+ {
+ LOG2( "+ Download(): %d,", iAppState );
+
+ TPtrC8 filename(NULL,0);
+ HBufC8* Url = NULL;
+
+ // Set the download filename and Url based
+ // on the state.
+ switch(iAppState)
+ {
+ case EChangesDownloadState:
+ {
+ filename.Set(KAdmChangesFile);
+ Url = iConfigUrl;
+ break;
+ }
+ case EADMDownloadState:
+ {
+ User::LeaveIfNull(iAdmChangesInfo.iSisName);
+ filename.Set((iAdmChangesInfo.iSisName)->Des());
+ // If the Url is not provided as part of the changes file,
+ // take the default Url
+ Url = (iAdmChangesInfo.iUrl==NULL) ?iConfigUrl :iAdmChangesInfo.iUrl;
+ break;
+ }
+ default:
+ {
+ LOG2( "! Unexpected state: %d", iAppState );
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ }
+
+ // Create the full URL for download
+ DELETE_IF_NONNULL( iUrl);
+ iUrl = HBufC8::NewL(Url->Length() + filename.Length() + KForwardSlash().Length() );
+ *iUrl = *Url;
+ TPtr8 ptr(iUrl->Des());
+
+ // Append forward slash if that's missing
+ if (ptr.Right(1) != KForwardSlash)
+ {
+ ptr.Append(KForwardSlash);
+ }
+ ptr.Append(filename);
+
+
+ // Set download file name along with path
+ TChar systemDrive;
+ RFs::DriveToChar(RFs::GetSystemDrive(),systemDrive);
+
+ DELETE_IF_NONNULL( iDownloadFileName );
+ iDownloadFileName = HBufC::NewL(KDownloadFolder().Length() + filename.Length());
+
+ *iDownloadFileName = KDownloadFolder;
+ iDownloadFileName->Des()[0] = systemDrive;
+
+ TPtr responseFilenamePtr = iDownloadFileName->Des();
+
+ HBufC* filename16 = HBufC::NewLC(filename.Length());
+ filename16->Des().Copy(filename);
+ responseFilenamePtr.Append(*filename16);
+ CleanupStack::PopAndDestroy(filename16);
+
+ iPausable = EFalse;
+ iConnectionAttempts = 0;
+
+ // Create new download
+ LOG8_2( "Downloading from URL: '%S'", iUrl );
+ LOG2(" Download begins for '%S'", iDownloadFileName );
+ TBool isNewDl = ETrue;
+ RHttpDownload& dl = iDownloadManager.CreateDownloadL( *iUrl, isNewDl );
+
+ ConeUtils::EnsurePathExistsL(*iDownloadFileName);
+ if(isNewDl)
+ {
+ LOG2( "Response body filename is '%S'", iDownloadFileName );
+ dl.SetStringAttribute( EDlAttrDestFilename, *iDownloadFileName );
+ dl.Start();
+ }
+
+ LOG( "- Download()" );
+ }
+
+void CBootstrapAppUi::WaitForInstallCompleteL()
+ {
+ LOG( "+ WaitForInstallCompleteL()" );
+
+ // Use publish and subscribe mechanism to
+ // get notified when installer is free.
+ RProperty installComplete;
+ User::LeaveIfError( installComplete.Attach(KUidSystemCategory, Swi::KUidSoftwareInstallKey) );
+
+ TInt value;
+ if ( installComplete.Get( KUidSystemCategory, Swi::KUidSoftwareInstallKey, value ) == KErrNotFound )
+ {
+ LOG( "! Could not get installer" );
+ installComplete.Close();
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ else if ( (value & Swi::KSwisOperationMask) == Swi::ESwisNone )
+ {
+ // Installer is idle.
+ }
+ else
+ {
+ LOG( "Waiting for the Installer to finish installation" );
+ TRequestStatus status;
+ installComplete.Subscribe(status);
+ User::WaitForRequest(status);
+ }
+
+ iAllowForeground = ETrue;
+ LOG( "Installer is idle" );
+ installComplete.Close();
+ LOG( "- WaitForInstallCompleteL()" );
+ }
+
+TUint32 CBootstrapAppUi::GetLatestInstalledL()
+ {
+ LOG( "+ GetLatestInstalledL()" );
+
+ // Use publish and subscribe mechanism to
+ // get Uid of the latest installed package.
+ RProperty lastInstall;
+ User::LeaveIfError(lastInstall.Attach(KUidSystemCategory, KUidSwiLatestInstallation));
+
+ TInt value = -1;
+ if (lastInstall.Get( KUidSystemCategory, KUidSwiLatestInstallation, value ) == KErrNotFound)
+ {
+ LOG( "! Could not get installer" );
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ LOG2( "- GetLatestInstalled(): wrapper=0x%08x", value );
+ return value;
+ }
+
+void CBootstrapAppUi::ShowGlobalWaitNoteL()
+ {
+
+ // Allocate TBuf with constant length.
+ TBuf<KMaxMsgSize> text( NULL );
+
+ // Reads a resource into a descriptor.
+ CEikonEnv::Static()->ReadResource( text, R_ADM_ENV_CREATION_WAIT_TEXT );
+
+ // Create new CAknGlobalNote instance.
+ iGlobalWaitNote = CAknGlobalNote::NewL();
+
+ iGlobalWaitNoteObserver = new (ELeave) CGlobalWaitNoteObserver(this);
+ iGlobalWaitNoteObserver->iStatus = KRequestPending;
+ iGlobalWaitNoteObserver->Start();
+
+ iGlobalWaitNoteId = iGlobalWaitNote->ShowNoteL(
+ iGlobalWaitNoteObserver->iStatus,
+ EAknGlobalWaitNote,
+ text );
+ }
+
+void CBootstrapAppUi::StopGlobalWaitNoteL()
+ {
+ LOG2( "+ CBootstrapAppUi::StopGlobalWaitNoteL(): %d", iGlobalWaitNoteId );
+ if(iGlobalWaitNote && (iGlobalWaitNoteId >= 0))
+ {
+ iGlobalWaitNote->CancelNoteL(iGlobalWaitNoteId);
+ }
+ iGlobalWaitNoteId = -1;
+
+ DELETE_IF_NONNULL( iGlobalWaitNote );
+ DELETE_IF_NONNULL( iGlobalWaitNoteObserver );
+ LOG( "- CBootstrapAppUi::StopGlobalWaitNoteL()" );
+ }
+
+void CBootstrapAppUi::HandleDMgrEventL( RHttpDownload& aDownload, THttpDownloadEvent aEvent )
+ {
+ LOG3("+HandleDMgrEventL(): DlState=%d, ProgState=%d", aEvent.iDownloadState, aEvent.iProgressState);
+
+ TInt32 tmp;
+ THttpDownloadMgrError dlErrorId;
+ TInt32 sysErrorId( KErrNone );
+
+ // If DL is in final state (complete/fail), there's an error id available.
+ // TODO: Handle error condition
+ TInt sysErr = aDownload.GetIntAttribute( EDlAttrGlobalErrorId ,sysErrorId );
+ TInt dlErr = aDownload.GetIntAttribute( EDlAttrErrorId ,tmp );
+ dlErrorId = (THttpDownloadMgrError)tmp;
+
+ //TODO: Include Log5
+ //LOG5( "SysErrId=%d, DlErrId=%d. DlSize=%d, CntSize=%d.", sysErrorId, dlErrorId, downloadedsize, contentsize );
+
+ switch ( aEvent.iDownloadState )
+ {
+ case EHttpDlCreated:
+ {
+ break;
+ }
+ case EHttpDlInprogress:
+ {
+ switch ( aEvent.iProgressState)
+ {
+ case EHttpProgCreatingConnection:
+ {
+ break;
+ }
+ case EHttpProgConnected:
+ {
+ break;
+ }
+ case EHttpProgConnectionSuspended:
+ case EHttpProgDisconnected:
+ {
+ // Try to reconnect if:
+ // 1. No of connection attempts is less than KMaxDlConnectionAttempts
+ // 2. IAP selection dialog is not cancelled.
+ if ((iConnectionAttempts < KMaxDlConnectionAttempts)
+ && !(dlErrorId == EConnectionFailed && sysErrorId == KErrCancel))
+ {
+ ++iConnectionAttempts;
+ LOG2("Restart attempt is '%d'",iConnectionAttempts);
+ aDownload.Start();
+ }
+ break;
+ }
+ case EHttpProgDownloadStarted:
+ {
+ break;
+ }
+ case EHttpContentTypeRequested:
+ {
+ break;
+ }
+ case EHttpProgResponseHeaderReceived:
+ {
+ break;
+ }
+ case EHttpProgResponseBodyReceived:
+ {
+ break;
+ }
+ default :
+ break;
+ }
+ break;
+ }
+ case EHttpDlPausable:
+ {
+ iPausable = ETrue;
+ break;
+ }
+ case EHttpDlNonPausable:
+ {
+ iPausable = EFalse;
+ break;
+ }
+ case EHttpDlCompleted:
+ {
+ iDownloadManager.GetIntAttribute( EDlMgrIap, iIAP );
+ LOG2("IAP set to %d", iIAP);
+
+ HandleHttpFetchCompleteL(EFalse);
+ break;
+ }
+ case EHttpDlPaused:
+ {
+ if((dlErrorId == EConnectionFailed) && (sysErrorId == KErrCancel))
+ {
+ isIapCancelled = 1;
+ }
+
+ // Continue dowload if paused in EHttpContentTypeReceived
+ if(aEvent.iProgressState == EHttpContentTypeReceived)
+ {
+ aDownload.Start();
+ }
+ // Try to reconnect if:
+ // 1. No of connection attempts is less than KMaxDlConnectionAttempts
+ // 2. IAP selection dialog is not cancelled.
+ else if((iConnectionAttempts < KMaxDlConnectionAttempts)
+ && (!isIapCancelled))
+ {
+ aDownload.Start();
+ }
+ else if(iPausable)
+ {
+ aDownload.Start();
+ }
+ else
+ {
+ HandleHttpFetchCompleteL(ETrue);
+ }
+ break;
+ }
+ case EHttpDlFailed:
+ {
+ if((dlErrorId == EConnectionFailed) && (sysErrorId == KErrCancel))
+ {
+ isIapCancelled = 1;
+ }
+
+ HandleHttpFetchCompleteL(ETrue);
+ break;
+ }
+ case EHttpDlDeleting:
+ {
+ break;
+ }
+ case EHttpDlDeleted:
+ {
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+
+void CBootstrapAppUi::HandleHttpFetchCompleteL(const TBool& aStatus)
+ {
+ LOG3( "+ Fetch(): s=%d, a=%d", aStatus, iAppState );
+
+ User::LeaveIfNull(iDownloadFileName);
+
+ if (aStatus == EFalse)
+ {
+ switch(iAppState)
+ {
+ case EChangesDownloadState:
+ {
+ // Parse downloaded changes file
+ iAppState = EChangesParseState;
+ LOG("* State changed to EChangesParseState");
+
+ TRAPD(err, ParseChangesInfoL(*iDownloadFileName));
+ LOG2( "Changes file parsing completed with status: %d", err);
+
+ // Delete no longer required changes file
+ DeleteFile(*iDownloadFileName);
+
+ // 1. Install ADM if not already present
+ // 2. Upgrade ADM if higher version is available
+ // 3. If the upgrade fails, launch the current version
+ // of ADM in device.
+ TBool isAdmDownloadRequired = CompareVersions(iAdmInstalledVersion, iAdmChangesInfo.iVersion)
+ == EGreaterSecondVersion;
+
+ if ((err==KErrNone) && isAdmDownloadRequired)
+ {
+ LOG( "* Changing state to EADMDownloadState" );
+ iAppState = EADMDownloadState;
+ DownloadL();
+ }
+ else if (iIsAdmInstalled)
+ {
+ LOG( "* Changing state to EADMLaunchState" );
+ iAppState = EADMLaunchState;
+ TRAPD( err, LaunchAdmL() );
+ if (err != KErrNone)
+ {
+ LOG2( "ADM launch fail %d", err );
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ LOG( "ADM launched OK, exiting! 1" );
+ TRAP_IGNORE( StopGlobalWaitNoteL() );
+ CloseApp();
+ }
+ else
+ {
+ // Adm changes file parse error
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ break;
+ }
+
+ case EADMDownloadState:
+ {
+ LOG2( "ADM downloaded OK: '%S'", iDownloadFileName);
+
+ iAppState = EADMInstallState;
+ LOG( "* State changed to EADMInstallState" );
+ AsyncInstallPackageL(*iDownloadFileName);
+ break;
+ }
+
+ default:
+ {
+ LOG2( "Unexpected state %d", iAppState );
+ // Unexpected State
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ }
+ }
+ else
+ {
+ // Launch existing version of ADM (if present) in device
+ // in case of download failure.
+ if (iIsAdmInstalled && (!isIapCancelled))
+ {
+ LOG( "* Changing state to EADMLaunchState" );
+ iAppState = EADMLaunchState;
+ TRAPD(err, LaunchAdmL());
+ if (err != KErrNone)
+ {
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ LOG( "ADM launched OK, exiting! 2" );
+ TRAP_IGNORE( StopGlobalWaitNoteL() );
+ CloseApp();
+ }
+ else
+ {
+ LOG( "! ADM download failed!" );
+ ExitWithError(R_HTTP_TRANSACTION_ERR);
+ }
+ }
+
+ LOG( "- Fetch complete ");
+ }
+
+void CBootstrapAppUi::SetFileNameInfoL()
+ {
+ LOG( "+ SetFileNameInfoL()" );
+ LOG2( "Bootstrap version: %d", KBootstrapVersion);
+
+ if(KBootstrapVersion<1 && KBootstrapVersion>4)
+ {
+ // Unsupported Bootstrap version
+ User::Leave(KErrNotSupported);
+ }
+
+ // Connect to SisRegistry to fetch Package info
+ Swi::RSisRegistrySession registrySession;
+ User::LeaveIfError(registrySession.Connect());
+ CleanupClosePushL(registrySession);
+
+ Swi::RSisRegistryEntry entry;
+
+ // Open registry entry
+ User::LeaveIfError(entry.Open(registrySession, TUid::Uid(iWrapperPackageUid)));
+ CleanupClosePushL(entry);
+
+ RPointerArray<HBufC> packageFiles;
+ entry.FilesL(packageFiles);
+ const TInt filesCount(packageFiles.Count());
+
+ // look into the files installed as part of the package,
+ // to find the dep file name and actuall application file name.
+ for (TInt i=0; i<filesCount; i++)
+ {
+ TParse parse;
+ TInt err = parse.Set(packageFiles[i]->Des(), NULL, NULL);
+ if (err != KErrNone)
+ {
+ continue;
+ }
+ TPtrC orgExtn = parse.Ext();
+
+ if (orgExtn.Length() == 0)
+ {
+ continue;
+ }
+
+ HBufC* extn = orgExtn.AllocLC();
+ TPtr extnPtr = extn->Des();
+ extnPtr.UpperCase();
+
+ if(KBootstrapVersion != 3)
+ {
+ if ((extnPtr.Compare(KSisExtn) == 0)||(extnPtr.Compare(KSisxExtn) == 0))
+ {
+ TPtrC privatePath( KNullDesC );
+ const TInt driveLength = 2;
+ if (packageFiles[i]->Length() > (KSWIDaemonPrivateFolder().Length() + driveLength))
+ {
+ privatePath.Set( packageFiles[i]->Des().Mid( driveLength ) );
+ privatePath.Set( privatePath.Left( KSWIDaemonPrivateFolder().Length() ) );
+ }
+
+ // Ignore if its a Stub Sis file
+ if(privatePath.CompareF(KSWIDaemonPrivateFolder))
+ {
+ if (iSisFileName == NULL)
+ {
+ iSisFileName = packageFiles[i]->AllocL();
+ LOG2( "Actual application name is '%S'", iSisFileName);
+ }
+ else
+ // More than one sis present in the Wrapper Pkg
+ {
+ LOG2( "! More than one sis file present: '%S'. LEAVE.", packageFiles[i] );
+
+ User::Leave(KErrNotSupported);
+ }
+ }
+ }//end of sis extension
+ }//end of Bootstrapversion 2
+ if (KBootstrapVersion != 4)
+ {
+ if(extnPtr.Compare(KXMLExtn) == 0)
+ {
+ TPtrC orgName = parse.Name();
+ const TInt namelength = orgName.Length();
+ const TInt depSuffixlength = KDepExtn().Length();
+
+ if (namelength > depSuffixlength)
+ {
+ TPtrC depSuffix = orgName.Mid((namelength-depSuffixlength), depSuffixlength);
+
+ HBufC* name = depSuffix.AllocLC();
+ TPtr namePtr = name->Des();
+ namePtr.UpperCase();
+
+ if (namePtr.Compare(KDepExtn) == 0)
+ {
+ if (iDepFilename == NULL)
+ {
+ iDepFilename = packageFiles[i]->AllocL();
+ LOG2( "Dep file name is '%S'", iDepFilename);
+ }
+ else
+ // More than one dep file present in the Wrapper Pkg
+ {
+ LOG2( "! More than one dep file present: '%S'. LEAVE.", packageFiles[i] );
+ User::Leave(KErrNotSupported);
+ }
+ }
+ CleanupStack::PopAndDestroy(name);
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(extn);
+ }
+
+ packageFiles.ResetAndDestroy();
+ packageFiles.Close();
+
+ if(KBootstrapVersion != 3)
+ {
+ User::LeaveIfNull(iSisFileName);
+ if (!(ConeUtils::FileExists(*iSisFileName)))
+ {
+ User::Leave(KErrNotFound);
+ }
+ }
+ if(KBootstrapVersion != 4)
+ {
+ User::LeaveIfNull(iDepFilename);
+ }
+
+ CleanupStack::PopAndDestroy(&entry);
+ CleanupStack::PopAndDestroy(®istrySession);
+
+ LOG( "- SetFileNameInfoL()" );
+ }
+
+TInt CBootstrapAppUi::LaunchAdmL()
+ {
+ LOG( "+ LaunchAdmL()" );
+
+ // In case of approach 3 , cleanup of only BootStrap
+ // is required.
+ if (KBootstrapVersion == 3)
+ {
+ iWrapperPackageUid = KUidBootstrapApp.iUid;
+ }
+
+#ifdef __USE_RAPA
+ HBufC *processArgs = HBufC::NewLC(iDepFilename->Length() + iSisFileName->Length() + 10 + 3 + 2);
+ TPtr cmdLineParams = processArgs->Des();
+ cmdLineParams.Append(iDepFilename->Des());
+ cmdLineParams.Append(' ');
+ cmdLineParams.Append(iSisFileName->Des());
+ cmdLineParams.Append(' ');
+ cmdLineParams.AppendNum(iWrapperPackageUid);
+ cmdLineParams.Append(' ');
+ cmdLineParams.AppendNum(iIAP);
+ HBufC *tmp = HBufC::NewLC( cmdLineParams.Length() );
+ tmp->Des().Copy( cmdLineParams );
+ LOG2( "cmdLineParams '%S'", tmp );
+ CleanupStack::PopAndDestroy(tmp);
+ TApaAppInfo appInfo;
+ RProcess process;
+ RApaLsSession appArcSession;
+ User::LeaveIfError( appArcSession.Connect() );
+ LOG("RApaLsSession.Connect() OK");
+ CleanupClosePushL<RProcess>( process );
+ CleanupClosePushL<RApaLsSession>( appArcSession );
+ User::LeaveIfError( appArcSession.GetAppInfo( appInfo, KUidAdm ) );
+ LOG("RApaLsSession.GetAppInfo() OK");
+ TFileName appName = appInfo.iFullName;
+ LOG2("RApaLsSession: iFullName='%S'", &appName);
+ User::LeaveIfError( process.Create( appName, processArgs->Des() ) );
+ HBufC8 *tail = HBufC8::NewLC( processArgs->Length() );
+ tail->Des().Copy(processArgs->Des());
+ CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
+ cmdLine->SetExecutableNameL( appName );
+ cmdLine->SetCommandL( EApaCommandBackground );
+ cmdLine->SetTailEndL( tail->Des() );
+ cmdLine->SetProcessEnvironmentL( process );
+ LOG("RApaLsSession: going to launch");
+ User::LeaveIfError( appArcSession.StartApp( *cmdLine ) );
+ process.Resume();
+ CleanupStack::PopAndDestroy( cmdLine );
+ CleanupStack::PopAndDestroy( tail );
+ CleanupStack::PopAndDestroy( &appArcSession );
+ CleanupStack::PopAndDestroy( &process );
+ CleanupStack::PopAndDestroy( processArgs );
+ LOG("launch OK");
+#else
+ // Create ADM command line:
+ // adm.exe dependency_filename sis_filename uid_in_dec
+ //
+ // Size of 32-bit Bootstrap Version Value is 10 characters
+ // Size of 32-bit UID when converted to numeric string is 10 characters (4294967295)
+ // Max size of iIAP(TInt) when converted to numeric string is 10 characters
+ // Size of 2 spaces is 2 characters
+ const TInt mandatoryOptionsLength = 10+ 10+ 10+ 2;
+ TBufC<mandatoryOptionsLength> mandatoryOptions;
+ TPtr mandatoryOptionsPtr = mandatoryOptions.Des();
+
+ mandatoryOptionsPtr.AppendNum(KBootstrapVersion);
+ mandatoryOptionsPtr.Append(' ');
+ mandatoryOptionsPtr.AppendNum(iWrapperPackageUid);
+ mandatoryOptionsPtr.Append(' ');
+ mandatoryOptionsPtr.AppendNum(iIAP);
+
+ HBufC *processArgs = NULL;
+
+ switch (KBootstrapVersion)
+ {
+ case 1:
+ case 2:
+ {
+ User::LeaveIfNull(iSisFileName);
+ User::LeaveIfNull(iDepFilename);
+ // Size of 2 spaces is 2 characters
+ processArgs = HBufC::NewLC(
+ mandatoryOptionsLength +
+ iDepFilename->Length() +
+ iSisFileName->Length() +
+ 2);
+ TPtr cmdLine = processArgs->Des();
+ cmdLine.Append(mandatoryOptionsPtr);
+ cmdLine.Append(' ');
+ cmdLine.Append(*iDepFilename);
+ cmdLine.Append(' ');
+ cmdLine.Append(*iSisFileName);
+ break;
+ }
+ case 3:
+ {
+ User::LeaveIfNull(iDepFilename);
+ // Size of 1 spaces is 1 characters
+ processArgs = HBufC::NewLC(
+ mandatoryOptionsLength +
+ iDepFilename->Length() +
+ 1);
+ TPtr cmdLine = processArgs->Des();
+ cmdLine.Append(mandatoryOptionsPtr);
+ cmdLine.Append(' ');
+ cmdLine.Append(*iDepFilename);
+ break;
+ }
+ case 4:
+ {
+ User::LeaveIfNull(iSisFileName);
+ // Size of 1 spaces is 1 characters
+ processArgs = HBufC::NewLC(
+ mandatoryOptionsLength +
+ iSisFileName->Length() +
+ 1);
+ TPtr cmdLine = processArgs->Des();
+ cmdLine.Append(mandatoryOptionsPtr);
+ cmdLine.Append(' ');
+ cmdLine.Append(*iSisFileName);
+ break;
+ }
+ default:
+ // Unsupported Bootstrap Version
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ break;
+ }
+
+ // Launch ADM
+ LOG3( "Launching %S '%S'", &KAdmExePath, processArgs);
+
+ RProcess process;
+ CleanupClosePushL<RProcess>( process );
+
+ const TInt err = process.Create( KAdmExePath, processArgs->Des() );
+ if (err != KErrNone)
+ {
+ LOG2( "ADM launch failed with error: %d", err );
+ CleanupStack::PopAndDestroy( &process );
+ CleanupStack::PopAndDestroy( processArgs );
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+
+ process.SetPriority( EPriorityBackground );
+ process.Resume();
+#if 0
+ const TInt type = process.ExitType();
+ const TInt reason = process.ExitReason();
+ TExitCategoryName cat = process.ExitCategory();
+ LOG4( "Exit type %d, reason %d, cat '%S'", type, reason, &cat);
+#endif
+ CleanupStack::PopAndDestroy( &process );
+ CleanupStack::PopAndDestroy( processArgs );
+
+#endif // if __USE_RAPA
+ LOG2( "- LaunchAdmL(): %d", err );
+ return KErrNone;
+ }
+
+void CBootstrapAppUi::AsyncInstallPackageL(const TDesC& aResponseFilename)
+ {
+ SwiUI::TInstallOptions Options;
+
+ Options.iUpgrade = SwiUI::EPolicyAllowed;
+ Options.iOCSP = SwiUI::EPolicyNotAllowed;
+ Options.iDrive = 'c';
+ Options.iUntrusted = SwiUI::EPolicyNotAllowed;
+ Options.iCapabilities = SwiUI::EPolicyNotAllowed;
+ Options.iOverwrite = SwiUI::EPolicyAllowed;
+
+ iOptionsPckg = Options;
+
+ if (iInstallObsrv == NULL)
+ {
+ iInstallObsrv = new (ELeave) CInstallObserver(this);
+ }
+ iInstallObsrv->iStatus = KRequestPending;
+ iInstallObsrv->Start();
+ // Start asynchronous installation
+ iLauncher.SilentInstall(iInstallObsrv->iStatus, aResponseFilename, iOptionsPckg);
+ }
+
+void CBootstrapAppUi::HandleInstallCompleteL(const TInt& aStatus)
+ {
+ LOG2("+ HandleInstallCompleteL(%d)", aStatus);
+ User::LeaveIfNull(iDownloadFileName);
+
+ // If the install server is busy , try connecting multiple times.
+ if (aStatus == SwiUI::KSWInstErrBusy && ((++iInstallAttempt) <= KMaxInstallerConnectionAttempts))
+ {
+ LOG2( "Retrying installation %d", aStatus );
+ AsyncInstallPackageL(*iDownloadFileName);
+ }
+ else
+ {
+ LOG2("ADM installation status: %d", aStatus);
+
+ LOG("Deleting ADM sis file");
+ // Delete no longer required sis file.
+ DeleteFile(*iDownloadFileName);
+
+ if (aStatus == KErrNone || iIsAdmInstalled)
+ {
+ iAppState = EADMLaunchState;
+ TRAPD( err, LaunchAdmL() );
+ if ( err != KErrNone )
+ {
+ LOG2( "ADM launch failed %d", err );
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ LOG2( "ADM launched OK %d", err );
+ TRAP_IGNORE( StopGlobalWaitNoteL() );
+ CloseApp();
+ }
+ else
+ {
+ ExitWithError(R_INSTALLATION_FAILURE_ERR);
+ }
+ }
+ LOG("- HandleInstallCompleteL()");
+ }
+
+TBool CBootstrapAppUi::IsPackagePresentL(const TUid& aUid, TVersion& aVersion)
+ {
+ LOG( "+ ADMPresent()");
+
+ // Connect to SisRegistry to find if the package is
+ // already installed.
+ Swi::RSisRegistrySession registrySession;
+
+ User::LeaveIfError(registrySession.Connect());
+ CleanupClosePushL(registrySession);
+
+ const TBool isPkgInstalled = registrySession.IsInstalledL(aUid);
+
+ if (isPkgInstalled)
+ {
+ Swi::RSisRegistryEntry entry;
+
+ // Open registry entry
+ User::LeaveIfError(entry.Open(registrySession, aUid));
+ CleanupClosePushL(entry);
+ aVersion = entry.VersionL();
+
+ CleanupStack::PopAndDestroy(&entry);
+ }
+
+ CleanupStack::PopAndDestroy(®istrySession);
+
+ LOG3( "- ADMPresent(): 0x%x = %d", aUid.iUid, isPkgInstalled );
+
+ return isPkgInstalled;
+ }
+
+void CBootstrapAppUi::DeleteFile(const TDesC& aFileName)
+ {
+ CCoeEnv::Static()->FsSession().Delete(aFileName);
+ }
+
+void CBootstrapAppUi::ShowNoteL( const TAknGlobalNoteType& aType , const TInt& aResourceId )
+ {
+ // Allocate TBuf with constant length.
+ TBuf<KMaxMsgSize> text;
+
+ // Reads a resource into a descriptor.
+ CEikonEnv::Static()->ReadResource( text, aResourceId );
+
+ // Create new CAknGlobalNote instance.
+ CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
+ globalNote->ShowNoteL( aType , text );
+ CleanupStack::PopAndDestroy(globalNote);
+ }
+
+void CBootstrapAppUi::ExitWithError(const TInt& aResourceId )
+ {
+ LOG2( "+ ExitWithError(): 0x%08x", aResourceId );
+
+ // Display error message
+ TRAP_IGNORE(
+ StopGlobalWaitNoteL();
+ ShowNoteL(EAknGlobalErrorNote, aResourceId);
+ );
+
+ // Delete the dep file is present
+ if((KBootstrapVersion == 3)&&(iDepFilename))
+ {
+ DeleteFile(*iDepFilename);
+ }
+ else if((KBootstrapVersion == 4)&&(iSisFileName))
+ {
+ DeleteFile(*iSisFileName);
+ }
+
+ RunAppShutter();
+ Exit();
+
+ LOG( "- ExitWithError()" );
+ }
+
+void CBootstrapAppUi::CloseApp()
+ {
+ LOG( "+ CloseApp()" );
+
+ RunAppShutter();
+ Exit();
+
+ LOG( "- CloseApp()" );
+ }
+
+void CBootstrapAppUi::HandleForegroundEventL(TBool aForeground)
+ {
+ LOG3("+ CBootstrapAppUi::HandleForegroundEventL(%d): allow=%d", aForeground, iAllowForeground);
+ CAknAppUi::HandleForegroundEventL(aForeground);
+ if (aForeground && !iAllowForeground)
+ {
+ SendToBackgroundL();
+ }
+ LOG("- CBootstrapAppUi::HandleForegroundEventL()" );
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+void CBootstrapAppUi::SendToBackgroundL(TBool aBackground)
+ {
+ LOG2( "+ SendToBackgroundL(%d)", aBackground );
+ // We have gained the focus
+ RWsSession aWsSession;
+ User::LeaveIfError( aWsSession.Connect() );
+ TApaTask task(aWsSession);
+
+ // Initialise the object with the window group id of
+ // our application (so that it represent our app)
+ task.SetWgId(CEikonEnv::Static()->RootWin().Identifier());
+ if (aBackground)
+ {
+ task.SendToBackground();
+ }
+ else
+ {
+ task.BringToForeground();
+ }
+ aWsSession.Close();
+ LOG( "- SendToBackgroundL() ");
+ }
+
+void CBootstrapAppUi::HandleCommandL(TInt aCommand)
+ {
+ switch (aCommand)
+ {
+ case EEikCmdExit:
+ case EAknSoftkeyExit:
+ Exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// CBootstrapAppUi::ReadConfigurationL
+// Leaves if runs out of memory
+//
+// @return KErrNone if configuration was read correctly, error code otherwise
+// ---------------------------------------------------------------------------
+//
+TInt CBootstrapAppUi::ReadConfigurationL()
+ {
+ TFileName configFile;
+ RArray< TPtrC > lineBuffer;
+ TInt ret( KErrNone );
+ RFs& rfs = CEikonEnv::Static()->FsSession();
+
+ // Find the configuration file from the private directory
+ ret = rfs.PrivatePath(configFile);
+ if (ret == KErrNone)
+ {
+ TBuf<2> appDrive;
+ // Insert the drive of the running application
+ appDrive.Copy(Application()->AppFullName().Left(2));
+ configFile.Insert(0, appDrive);
+ // Append the configuration file name
+ configFile.Append(KConfigFile);
+
+ LOG2( "configFile = %S", &configFile );
+
+ HBufC* buffer = ReadConfigFile(rfs, configFile, lineBuffer, ret );
+
+ if ( buffer && ret == KErrNone )
+ {
+ // Get Url from the config file
+ TPtrC urlLine = GetConfigValue( KCfgTagUrl, lineBuffer, ret );
+ if ( ret == KErrNone )
+ {
+ iConfigUrl = HBufC8::NewL(urlLine.Length());
+ iConfigUrl->Des().Copy(urlLine);
+ LOG8_2( "configUrl = %S", iConfigUrl );
+ }
+ delete buffer;
+ }
+ }
+ if ( !iConfigUrl )
+ {
+ // Error occured while reading the configuration, use default URL
+ iConfigUrl = HBufC8::NewL(KDefaultDepServerUrl().Length());
+ *iConfigUrl = KDefaultDepServerUrl;
+ LOG8_2( "configUrl = %S (default)", iConfigUrl );
+ }
+
+ lineBuffer.Close();
+
+ return ret;
+ }