/*
* 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;
}