--- /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