/*
* Copyright (c) 1997-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:
* SWIS implementation
*
*/
/**
@file
*/
#include "installserver.h"
#include "installclientserver.h"
#include "installmachine.h"
#include "uninstallmachine.h"
#include "swispubsubdefs.h"
#include "restoremachine.h"
#include "log.h"
#include "packageremover.h"
#include <connect/sbdefs.h>
#include <swi/pkgremover.h>
namespace Swi
{
/**
* Local function to panic an offending client
* @internalTechnology
* @released
*/
static void PanicClient(const RMessagePtr2& aMessage,
TInstallServerPanic aPanic)
{
aMessage.Panic(KInstallServerName, aPanic);
}
//
// CInstallSession
//
// 2nd phase construction, called by the server framework
void CInstallSession::CreateL()
{
Server().AddSession();
#ifdef __WINSCW__
// For 2 minutes after initial boot, DLLs are not unloaded. If we are doing an
// install/uninstall/restore, we need to make sure any pending unloadeds are actioned,
// otherwise a previously loaded DLL could cause the rollback to fail on windows (on
// arm it is legal to delete a loaded DLL/EXE, whilst on windows it is not).
RLoader loader;
TInt r = loader.Connect();
if(r == KErrNone)
{
(void)loader.CancelLazyDllUnload();
loader.Close();
}
#endif
}
CInstallSession::~CInstallSession()
{
delete iMachine;
delete iRestoreMachine;
delete iRemover;
Server().ListRemoveInProgress(EFalse);
RProperty::Set(KUidSystemCategory, KUidSoftwareInstallKey, ESwisNone);
Server().DropSession();
}
CInstallServer& CInstallSession::Server()
{
return *static_cast<CInstallServer*>(const_cast<CServer2*>(
CSession2::Server()));
}
// Handle a client request. Leaving is handled by ServiceError() which reports
// the error code to the client
void CInstallSession::ServiceL(const RMessage2& aMessage)
{
// Handle the cancel message first
if (aMessage.Function()==ECancel)
{
DEBUG_PRINTF(_L8("CInstallSession::ServiceL() cancel function called"));
// Set status as aborted
TInt property;
if (RProperty::Get(KUidSystemCategory, KUidSoftwareInstallKey, property) == KErrNone)
{
RProperty::Set(KUidSystemCategory, KUidSoftwareInstallKey, property | ESwisStatusAborted);
}
if (iMachine)
{
iMachine->CancelInstallation();
}
aMessage.Complete(KErrNone);
return;
}
TInt property = 0;
TInt err = RProperty::Get(KUidSystemCategory, conn::KUidBackupRestoreKey, property);
if (err != KErrNone && err != KErrNotFound)
{
User::Leave(err);
}
if (iMachine != NULL)
{
DEBUG_PRINTF2(_L8("Install Server Message %d refused. Install/Uninstall in progress"), aMessage.Function());
aMessage.Complete(KErrInUse);
}
/*
* We must return KErrInUse if:
* 1) The Connect P&S property indicates we are doing a backup/restore
* 2) We are not servicing that restore operation with this request
* 3) A list/remove operation is in progress
*
*/
else if ((iRemover != NULL) || Server().IsListRemoveInProgress())
{
// Remove operation in progress
DEBUG_PRINTF2(_L8("Install Server Message '%d' refused. List/Remove in progress"), aMessage.Function());
aMessage.Complete(KErrInUse);
}
else if (err != KErrNotFound && (property & (conn::KBURPartTypeMask^conn::EBURNormal))
&& aMessage.Function() != ERestore && !iRestoreMachine)
{
DEBUG_PRINTF2(_L8("Install Server Message '%d' refused. Backup/Restore in progress"), aMessage.Function());
aMessage.Complete(KErrInUse);
}
else
{
switch (aMessage.Function())
{
case EInstall:
{
DEBUG_PRINTF(_L8("CInstallSession::ServiceL() install function called"));
err = RProperty::Set(KUidSystemCategory, KUidSoftwareInstallKey, ESwisInstall);
User::LeaveIfError(err);
iMachine=CInstallMachine::NewL(aMessage);
User::LeaveIfError(iMachine->Start());
// The state machine will complete the client once the work
// is done.
break;
}
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
case EGetComponentInfo:
{
DEBUG_PRINTF(_L8("CInstallSession::ServiceL() get component info function called"));
iMachine=CInstallMachine::NewL(aMessage, ETrue);
// Set the install machine to run on comp info collection mode.
User::LeaveIfError(iMachine->Start());
// The state machine will complete the client once the work
// is done.
break;
}
#endif
case EUninstall:
{
DEBUG_PRINTF(_L8("CInstallSession::ServiceL() uninstall function called"));
err = RProperty::Set(KUidSystemCategory, KUidSoftwareInstallKey, ESwisUninstall);
User::LeaveIfError(err);
iMachine=CUninstallMachine::NewL(aMessage);
User::LeaveIfError(iMachine->Start());
// The state machine will complete the client once the work
// is done.
break;
}
case ERestore:
{
DEBUG_PRINTF(_L8("CInstallSession::ServiceL() restore function called"));
err = RProperty::Set(KUidSystemCategory, KUidSoftwareInstallKey, ESwisRestore);
User::LeaveIfError(err);
if (iRestoreMachine && !iRestoreMachine->IsComplete())
{
aMessage.Complete(KErrInUse);
}
if (iRestoreMachine)
{
delete iRestoreMachine;
iRestoreMachine = NULL;
}
iRestoreMachine = CRestoreMachine::NewL(aMessage);
break;
}
case ERestoreFile:
{
DEBUG_PRINTF(_L8("CInstallSession::ServiceL() restore file function called"));
if (iRestoreMachine == NULL)
{
// Should never be reached
aMessage.Panic(KInstallServerName, KErrNotReady);
}
else
{
iRestoreMachine->ServiceFileRequestL(aMessage);
}
break;
}
case ERestoreCommit:
{
DEBUG_PRINTF(_L8("CInstallSession::ServiceL() commit function called"));
if (iRestoreMachine == NULL)
{
// Should never be reached
aMessage.Panic(KInstallServerName, KErrNotReady);
}
else
{
iRestoreMachine->ServiceCommitRequestL(aMessage);
}
break;
}
case EListUnInstalledPkgs:
{
Server().ListRemoveInProgress(ETrue);
iRemover = CPackageRemover::NewL(aMessage);
iRemover->ListL();
// The state will complete the client once the work
// is done.
break;
}
case ERemoveUnInstalledPkg:
{
Server().ListRemoveInProgress(ETrue);
iRemover = CPackageRemover::NewL(aMessage);
iRemover->RemoveL();
// The state will complete the client once the work
// is done.
break;
}
default:
{
DEBUG_PRINTF2(_L8("CInstallSession::ServiceL() unknown function called (%d)"), aMessage.Function());
PanicClient(aMessage, Swi::EPanicInstallServerIllegalFunction);
break;
}
}
}
}
// Handle an error from ServiceL(). A bad descriptor error implies a badly
// programmed client, so panic it. Otherwise use the default handling (report
// the error to the client).
void CInstallSession::ServiceError(const RMessage2& aMessage, TInt aError)
{
// set the pubsub flag to aborted status
TInt property = 0;
TInt err = RProperty::Get(KUidSystemCategory, KUidSoftwareInstallKey, property);
if (err == KErrNone)
{
RProperty::Set(KUidSystemCategory, KUidSoftwareInstallKey, property | ESwisStatusAborted);
}
if (aError==KErrBadDescriptor)
PanicClient(aMessage, EPanicInstallServerBadDescriptor);
CSession2::ServiceError(aMessage, aError);
}
//
// CInstallServerShutdown
//
inline CInstallServerShutdown::CInstallServerShutdown()
: CTimer(-1)
{
CActiveScheduler::Add(this);
}
CInstallServerShutdown::~CInstallServerShutdown()
{
Cancel();
}
inline void CInstallServerShutdown::ConstructL()
{
CTimer::ConstructL();
}
inline void CInstallServerShutdown::Start()
{
After(KShutdownDelay);
}
// Initiate server exit when the timer expires
void CInstallServerShutdown::RunL()
{
CActiveScheduler::Stop();
}
//
// CInstallServer
//
// All functions require TrustedUI capability
const TInt CInstallServer::iRanges[iRangeCount] =
{
0 // All connect attempts
};
const TUint8 CInstallServer::iElementsIndex[iRangeCount] =
{
CPolicyServer::ECustomCheck // Custom check polices for TrustedUI or SID from connect.
};
const CPolicyServer::TPolicy CInstallServer::iPolicy =
{
CPolicyServer::ECustomCheck, // specifies all connect attempts
iRangeCount,
iRanges,
iElementsIndex,
NULL,
};
CInstallServer* CInstallServer::NewLC()
{
CInstallServer* self = new(ELeave) CInstallServer();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CInstallServer::~CInstallServer()
{
DEBUG_PRINTF(_L8("Install Server Shutdown"));
CSecurityPolicy::ReleaseResource();
delete iShutdown;
iShutdown = NULL; //required in case the server dies before the session
}
// This server does not offer sharable sessions
CInstallServer::CInstallServer()
: CPolicyServer(EPriorityMore, iPolicy, EUnsharableSessions),
iListRemoveInProgress(EFalse)
{
}
// Ensure the timer and server objects are running
void CInstallServer::ConstructL()
{
DEBUG_PRINTF(_L8("Install Server Created"));
StartL(KInstallServerName);
iShutdown = new(ELeave) CInstallServerShutdown;
iShutdown->ConstructL();
// Ensure that the server still exits even if the 1st client fails to
// connect
iShutdown->Start();
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
// Create the property used to publish SWI Progress Bar Value. Since this property is not needed
// if the SWI component doesn't exist, it is created here.
TInt err = RProperty::Define(KUidInstallServerCategory, KUidSwiProgressBarValueKey, RProperty::EInt);
if (err != KErrNone && err != KErrAlreadyExists)
{
DEBUG_PRINTF2(_L8("Progress Bar Property couldn't be created. Error=%d."), err);
User::Leave(err);
}
#endif
}
CPolicyServer::TCustomResult CInstallServer::CustomSecurityCheckL(const RMessage2& aMsg,
TInt& /*aAction*/, TSecurityInfo& aMissing)
{
_LIT_SECURE_ID(secureBackupClientSID, 0x10202D56);
if (aMsg.SecureId().iId == secureBackupClientSID.iId)
{
return CPolicyServer::EPass;
}
else if (aMsg.HasCapability(ECapabilityTrustedUI,
__PLATSEC_DIAGNOSTIC_STRING("CInstallServer::CustomSecurityTest client process does not have Trusted UI Capability")))
{
// Check additional capability for listing and removing "uninstalled" packages
if ((aMsg.Function() == EListUnInstalledPkgs) && !aMsg.HasCapability(ECapabilityReadDeviceData,
__PLATSEC_DIAGNOSTIC_STRING("CInstallServer::CustomSecurityTest client process does not have ReadDeviceData Capability")))
{
aMissing.iCaps.Set(ECapabilityReadDeviceData);
return CPolicyServer::EFail;
}
if ((aMsg.Function() == ERemoveUnInstalledPkg) && !aMsg.HasCapability(ECapabilityWriteDeviceData,
__PLATSEC_DIAGNOSTIC_STRING("CInstallServer::CustomSecurityTest client process does not have WriteDeviceData Capability")))
{
aMissing.iCaps.Set(ECapabilityWriteDeviceData);
return CPolicyServer::EFail;
}
return CPolicyServer::EPass;
}
else
{
// Missing connect SID or TrustedUI capability, cannot complete connection
aMissing.iCaps.Set(ECapabilityTrustedUI);
return CPolicyServer::EFail;
}
}
CSession2* CInstallServer::NewSessionL(const TVersion& aClientVersion,
const RMessage2&) const
{
// Currently there is only one version of the InstallServer
const TVersion serverVersion(KInstallServerVersionMajor,KInstallServerVersionMinor,KInstallServerVersionBuild);
// Check that the version of the server requested is not greater than
// that available.
if (!User::QueryVersionSupported(serverVersion, aClientVersion))
{
User::Leave(KErrNotSupported);
}
return new(ELeave) CInstallSession();
}
void CInstallServer::AddSession()
{
++iSessionCount;
DEBUG_PRINTF2(_L8("Install Server Session Created (%d sessions active)"), iSessionCount);
iShutdown->Cancel();
}
void CInstallServer::DropSession()
{
// if last session is dropped and server still alive start shutdown timer
if (--iSessionCount==0 && iShutdown)
{
iShutdown->Start();
DEBUG_PRINTF(_L8("Install Server Starting Shutdown Timer"));
}
DEBUG_PRINTF2(_L8("Install Server Session Destroyed (%d sessions active)"), iSessionCount);
}
} // namespace Swi