installationservices/swi/source/pkgremover/pkgremover.cpp
changeset 0 ba25891c3a9e
child 17 741e5bba2bd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/pkgremover/pkgremover.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,463 @@
+/*
+* Copyright (c) 2007-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: 
+*
+*/
+
+
+#include <f32file.h>
+#include <e32property.h>
+#include <swi/pkgremovererrors.h>
+#include <swi/swispubsubdefs.h>
+#include "sishelper.h"
+#include "log.h"
+#include "installclientserver.h"
+#include <swi/pkgremover.h>
+#include <connect/sbdefs.h>
+
+// Maximum buffer size
+const TInt KMaxBufferSize = 1024;
+
+namespace Swi
+{
+
+// Forward declarations
+TInt StartSisHelper(RThread& aServer);
+TInt SisHelperThreadFunction(TAny* );
+void StopSisHelper(TAny* aServer);
+TBool IsSWISBusy();
+TInt StartSwi();
+TInt FilterErrors(TInt aError);
+
+/*static*/
+EXPORT_C void UninstalledSisPackages::ListL(TDriveNumber aDrive, RPointerArray<CUninstalledPackageEntry>& aPackageList)
+	{
+	aPackageList.ResetAndDestroy();
+
+	// Check if SWIS is busy
+	if (IsSWISBusy())
+		{
+		User::Leave(KErrServerBusy);
+		}
+
+	RThread server;
+
+	// Ensure SisHelper is stopped in the event of a leave
+	CleanupStack::PushL(TCleanupItem(StopSisHelper, &server));
+	User::LeaveIfError(StartSisHelper(server));
+
+	// Connect to SWIS and issue request
+	RUninstalledPkgsSession uninstalledPkgSession;
+	User::LeaveIfError(uninstalledPkgSession.Connect());
+	CleanupClosePushL(uninstalledPkgSession);
+
+	HBufC8* output = HBufC8::NewLC(KMaxBufferSize);
+	
+	TPtr8 pOutput(output->Des());
+	TInt result = uninstalledPkgSession.RequestUnInstalledPkgsList(TIpcArgs(aDrive, &pOutput));
+
+	if (result == KErrOverflow)
+		{
+		TInt sizeNeeded = 0;
+		TPckg<TInt> sizeNeededPackage(sizeNeeded);
+		sizeNeededPackage.Copy(*output);
+
+		// Shutdown 
+		CleanupStack::PopAndDestroy(3, &server); //InstallServer , SisHelper and output
+
+		// Check if SWIS is busy
+		if (IsSWISBusy())
+			{
+			User::Leave(KErrServerBusy);
+			}
+
+		// Restart sishelper and ReConnect to SWIS to issue request
+		// Ensure SisHelper is stopped in the event of a leave
+		CleanupStack::PushL(TCleanupItem(StopSisHelper, &server));
+		User::LeaveIfError(StartSisHelper(server));
+		User::LeaveIfError(uninstalledPkgSession.Connect());
+		CleanupClosePushL(uninstalledPkgSession);
+
+		// Re-allocate buffer
+		output = HBufC8::NewLC(sizeNeeded);
+		pOutput.Set(output->Des());
+	
+		result = uninstalledPkgSession.RequestUnInstalledPkgsList(TIpcArgs(aDrive, &pOutput));
+		}
+	User::LeaveIfError(FilterErrors(result));
+
+	// Internalise the pointer array  
+	RDesReadStream readStream(pOutput);
+	CleanupClosePushL(readStream);
+
+	// read in the attribute values from the buffer
+	TInt count = readStream.ReadInt32L();
+	for (TInt i = 0; i < count; i++)
+		{
+		TInt uidValue = readStream.ReadInt32L();
+		TUid uid = TUid::Uid(uidValue);
+		
+		// Read the package name
+		TInt size = readStream.ReadInt32L();
+		HBufC* pName = HBufC::NewLC(size);
+		TPtr pPtr(pName->Des());
+		readStream.ReadL(pPtr, size);
+					
+		// Read the vendor name
+		size = readStream.ReadInt32L();
+		HBufC* vName = HBufC::NewLC(size);
+		TPtr vPtr(vName->Des());
+		readStream.ReadL(vPtr, size);
+		
+		TInt major = readStream.ReadInt32L();
+		TInt minor = readStream.ReadInt32L();
+		TInt build = readStream.ReadInt32L();
+		TVersion version(major,minor,build);
+		
+		// Read the package type
+		CUninstalledPackageEntry::TPackageType pkgType = CUninstalledPackageEntry::TPackageType(readStream.ReadInt32L());
+
+		// Read the file name
+		size = readStream.ReadInt32L();
+		HBufC* fName = HBufC::NewLC(size);
+		TPtr fPtr(fName->Des());
+		readStream.ReadL(fPtr, size);
+
+		// Read the associated stub file 
+		size = readStream.ReadInt32L();
+		HBufC* aName = HBufC::NewLC(size);
+		TPtr aPtr(aName->Des());
+		readStream.ReadL(aPtr, size);
+		
+		CUninstalledPackageEntry* PkgEntry = CUninstalledPackageEntry::NewLC(uid,
+		*pName, *vName, version, pkgType, *fName, *aName);
+		aPackageList.AppendL(PkgEntry);
+		CleanupStack::Pop(PkgEntry); 			// PkgEntry
+		CleanupStack::PopAndDestroy(4, pName); 	// aName, fName, vName, pName
+		}
+	CleanupStack::PopAndDestroy(2, output); 	// readStream, output
+
+	// Shutdown InstallServer and SisHelper
+	CleanupStack::PopAndDestroy(2, &server);
+	}
+
+/*static*/
+EXPORT_C void UninstalledSisPackages::RemoveL(const CUninstalledPackageEntry& aPackage)
+	{
+	// Check if SWIS is busy
+	if (IsSWISBusy())
+		{
+		User::Leave(KErrServerBusy);
+		}
+
+	// Get the filename
+	RThread server;
+	// Ensure SisHelper is stopped in the event of a leave
+	CleanupStack::PushL(TCleanupItem(StopSisHelper, &server));
+	User::LeaveIfError(StartSisHelper(server));
+
+	// Connect to SWIS and issue request
+	RUninstalledPkgsSession uninstalledPkgSession;
+	User::LeaveIfError(uninstalledPkgSession.Connect());
+	CleanupClosePushL(uninstalledPkgSession);
+	TIpcArgs args;
+	args.Set(0, &aPackage.PackageFile());
+	args.Set(1, &aPackage.AssociatedStubSisFile());
+	User::LeaveIfError(FilterErrors(uninstalledPkgSession.RemoveUnInstalledPkg(args)));
+
+	// Shutdown InstallServer and SisHelper
+	CleanupStack::PopAndDestroy(2, &server);
+	}
+
+CUninstalledPackageEntry* CUninstalledPackageEntry::NewLC(const TUid& aUid, const TDesC& aPackageName,
+		const TDesC& aVendorName, const TVersion& aVersion, const TPackageType aPackageType,
+		const TDesC& aPackageFile, const TDesC& aAssocStubSisFile)
+ 	{
+ 	CUninstalledPackageEntry* self = new(ELeave) CUninstalledPackageEntry();
+ 	CleanupStack::PushL(self);
+ 	self->ConstructL(aUid, aPackageName, aVendorName, aVersion, aPackageType, aPackageFile, aAssocStubSisFile);
+ 	return self;
+ 	}
+
+CUninstalledPackageEntry::CUninstalledPackageEntry()
+	{
+	}
+
+CUninstalledPackageEntry::~CUninstalledPackageEntry()
+	{
+	delete iVendorName;
+	delete iPackageName;
+	delete iPackageFile;
+	delete iAssocStubSisFile;
+	}
+
+// Constructs the objects using the property values
+void CUninstalledPackageEntry::ConstructL(const TUid& aUid, const TDesC& aPackageName,
+		const TDesC& aVendorName, const TVersion& aVersion, const TPackageType aPackageType, 
+		const TDesC& aPackageFile, const TDesC& aAssocStubSisFile)
+	{
+	iUid = aUid;
+	iPackageName = aPackageName.AllocL();
+	iVendorName = aVendorName.AllocL();
+	iVersion = aVersion;
+	iType = aPackageType;
+	iPackageFile = aPackageFile.AllocL();
+	iAssocStubSisFile = aAssocStubSisFile.AllocL();	
+	}
+
+// Get methods
+EXPORT_C const TUid& CUninstalledPackageEntry::Uid() const
+	{
+	return iUid;
+	}
+
+EXPORT_C const TDesC& CUninstalledPackageEntry::Name() const
+	{
+	return *iPackageName;
+	}
+
+EXPORT_C const TDesC& CUninstalledPackageEntry::Vendor() const
+	{
+	return *iVendorName;
+	}
+
+EXPORT_C const TVersion& CUninstalledPackageEntry::Version() const
+	{
+	return iVersion;
+	}
+
+EXPORT_C const CUninstalledPackageEntry::TPackageType& CUninstalledPackageEntry::PackageType() const
+	{
+	return iType;
+	}
+
+const TDesC& CUninstalledPackageEntry::PackageFile() const
+	{
+	return *iPackageFile;
+	}
+
+const TDesC& CUninstalledPackageEntry::AssociatedStubSisFile() const
+	{
+	return *iAssocStubSisFile;
+	}
+
+// Client-side session implementation
+TInt RUninstalledPkgsSession::Connect()
+	{
+	TInt retry = 2;
+	for(;;)
+		{
+		TInt err = CreateSession(Swi::KInstallServerName, 
+		    TVersion(KInstallServerVersionMajor, KInstallServerVersionMinor, KInstallServerVersionBuild));
+		if (err != KErrNotFound && err != KErrServerTerminated)
+			{
+			return err;
+			}
+		if (--retry == 0)
+			{
+			return err;
+			}
+		err = StartSwi();
+		if (err != KErrNone && err != KErrAlreadyExists)
+			{
+			return err;
+			}
+		}
+	}
+
+void RUninstalledPkgsSession::Close()
+	{
+	RSessionBase::Close();
+	}
+
+TInt RUninstalledPkgsSession::RequestUnInstalledPkgsList(const TIpcArgs& aArgs)
+	{
+	return SendReceive(Swi::EListUnInstalledPkgs, aArgs);
+	}
+
+TInt RUninstalledPkgsSession::RemoveUnInstalledPkg(const TIpcArgs& aArgs)
+	{
+	return SendReceive(Swi::ERemoveUnInstalledPkg, aArgs);
+	}
+
+// Starts SISHelper in a new thread
+TInt StartSisHelper(RThread& aServer)
+	{
+	// We might be trying to restart a server, in which case we could
+	// get a thread name clash. We could make the name unique/random,
+	// but the server name would still clash...
+
+	const TInt KSisHelperServerStackSize = 0x2000;
+	TInt err = KErrNone;
+	for (TInt retry = 0; retry < 2; ++retry)
+		{
+		err = aServer.Create(KSisHelperServerName, SisHelperThreadFunction, 
+					   		KSisHelperServerStackSize, NULL, NULL, EOwnerThread);
+
+		if (err == KErrAlreadyExists || err == KErrInUse)
+			{
+			User::After(80000);
+			}
+		else
+			{
+			break;
+			}
+		}
+
+	if ((err == KErrAlreadyExists) || (err == KErrInUse))
+		{
+		return KErrServerBusy;
+		}
+
+	if (err != KErrNone)
+		{
+		return err;
+		}
+
+	// The following code is the same whether the server runs in a new thread 
+	// or process
+	TRequestStatus stat;
+	aServer.Rendezvous(stat);
+	if (stat != KRequestPending)
+		{
+		aServer.Kill(0); // abort startup
+		}
+	else
+		{
+		aServer.Resume(); // logon OK, start the server
+		}
+
+	User::WaitForRequest(stat); // wait for start or death
+
+	// we can't use the 'exit reason' if the server panicked as this is the 
+	// panic 'reason' and may be 0 which cannot be distinguished from KErrNone
+	err = (aServer.ExitType() == EExitPanic) ? KErrGeneral : stat.Int();
+	//We don't close aServer here. If asynchlauncher called, it will be closed
+	//in the RunL() method of uissclienthandler to make sure that SISHelper has been 
+	//disconnected by SWISInstaller. Otherwise, just after this function call.
+	return err;
+	}
+
+// Stops SISHelper
+void StopSisHelper(TAny* aServer)
+	{
+	RThread* rServer = static_cast<RThread*> (aServer);
+	if(rServer->Handle() > 0)
+		{
+		TRequestStatus reqStatus;
+		rServer->Logon(reqStatus);
+		User::WaitForRequest(reqStatus);
+		rServer->Close();
+		}
+	}
+
+// Entry point for the thread the SISHelper runs in
+TInt SisHelperThreadFunction(TAny* )
+	{
+	CTrapCleanup* cleanup = CTrapCleanup::New(); // get clean-up stack
+	if (!cleanup)
+		{
+		return KErrNoMemory;
+		}
+		
+	CActiveScheduler* scheduler = new CActiveScheduler;
+	if (!scheduler)
+		{
+		delete cleanup;
+		return KErrNoMemory;
+		}
+
+	DEBUG_PRINTF(_L8("Sis Helper - Starting Server"));
+
+	CActiveScheduler::Install(scheduler);
+
+	TSisHelperStartParams params;
+	CSisHelperServer* server = static_cast<CSisHelperServer*>(NULL);
+	TRAPD(err, server = CSisHelperServer::NewL(params));
+
+	if (err == KErrNone)
+		{
+		// only continue launching the server if no error
+		RThread::Rendezvous(KErrNone);
+		scheduler->Start();
+		}
+
+	DEBUG_PRINTF(_L8("Sis Helper - Stopping Server"));
+
+	CActiveScheduler::Install(NULL);
+	delete server;
+	delete scheduler;
+	delete cleanup; // destroy clean-up stack
+
+	return err;
+	}
+
+// Starts SWIS in a new process
+TInt StartSwi()
+	{
+	const TUidType serverUid(KNullUid, KNullUid, Swi::KInstallServerUid3);
+	RProcess server;
+
+	TInt err = server.Create(Swi::KInstallServerImage, KNullDesC, serverUid);
+	if (err != KErrNone)
+		{
+		return err;
+		}
+	TRequestStatus stat;
+	server.Rendezvous(stat);
+	if (stat != KRequestPending)
+		{
+		server.Kill(0); // abort startup
+		}
+	else
+		{
+		server.Resume(); // logon OK, start the server
+		}
+
+	User::WaitForRequest(stat); // wait for start or death
+
+	// We can't use the 'exit reason' if the server panicked as this is the
+	// panic 'reason' and may be 0 which cannot be distinguished from KErrNone.
+	err = (server.ExitType() == EExitPanic) ? KErrGeneral : stat.Int();
+	server.Close();
+	return err;
+	}
+
+TBool IsSWISBusy()
+	{
+	// Check for Install/Uninstall operation
+	TInt property = 0;
+	TInt err = RProperty::Get(KUidSystemCategory, KUidSoftwareInstallKey, property);
+	if ((err != KErrNotFound) && ((property & KSwisOperationMask) != ESwisNone))
+		{
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+// Filter the error codes returned by the List and Remove API
+TInt FilterErrors(TInt aError)
+	{
+	TInt outError = aError;
+	// If the error is in SWI range (publishedPartner) then return a publishedAll equivalent
+	// for some of them
+	if (aError > KErrNotRemovable && aError <= KErrSISFieldIdMissing)	// Range is -10280 to -10100
+		{
+		outError = KErrPackageFileCorrupt;
+		}
+
+	return outError;
+	}
+
+} // namespace Swi