installationservices/swi/source/sishelper/sishelper.cpp
changeset 0 ba25891c3a9e
child 34 741e5bba2bd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/sishelper/sishelper.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1063 @@
+/*
+* 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: 
+* SISHelper is a layer between a client (EpocInstall, Installer UI, or Control
+* Panel applet) that starts [un]installation.
+*
+*/
+
+
+#include <s32mem.h>
+#include <caf/caf.h>
+#include <ecom/ecom.h>
+#include <bautils.h>
+#include <e32math.h> // for Math::Random()
+
+#include "swi/launcher.h"
+#include "sishelper.h"
+#include "filesisdataprovider.h"
+#include "log.h"
+#include "swi/sisparser.h"
+#include "swi/siscontents.h"
+#include "securitypolicy.h"
+#include "cafsisdataprovider.h"
+#include "sisregistrypackage.h"
+#include "sisregistrysession.h"
+#include "sisregistryentry.h"
+
+
+namespace Swi
+{
+
+// RMessagePtr2::Panic() also completes the message. This is 
+// (a) important for efficient cleanup within the kernel
+// (b) a problem if the message is completed the second time
+void PanicClient(const RMessagePtr2& aMessage, TSisHelperPanic aPanic)
+	{
+	aMessage.Panic(KSisHelperServerName, aPanic);
+	}
+
+//
+// Swi::CSisHelperShutdown helper class implementation
+//
+
+inline CSisHelperShutdown::CSisHelperShutdown() : CTimer(-1)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CSisHelperShutdown::~CSisHelperShutdown()
+	{
+	Deque();
+	}
+
+inline void CSisHelperShutdown::ConstructL()
+	{
+	CTimer::ConstructL();
+	}
+
+inline void CSisHelperShutdown::Start()
+	{
+	After(KShutdownDelay);
+	}
+
+// Initiate server exit when the timer expires
+void CSisHelperShutdown::RunL()
+	{
+	CActiveScheduler::Stop();
+	}
+
+//
+// CSisHelperSession
+//
+
+inline CSisHelperSession::CSisHelperSession(MSisDataProvider& aDataProvider)
+:	iDataProvider(aDataProvider)
+	{
+	}
+
+inline CSisHelperServer& CSisHelperSession::Server()
+	{
+	return *static_cast<CSisHelperServer*>(
+		const_cast<CServer2*>(CSession2::Server()));
+	}
+
+inline TBool CSisHelperSession::ReceivePending() const
+	{
+	return !iReceiveMsg.IsNull();
+	}
+
+// Second phase constructor, called by CServer2 framework
+void CSisHelperSession::CreateL()
+	{
+	Server().AddSession();
+	}
+
+CSisHelperSession::~CSisHelperSession()
+	{
+	delete iCurrentContents;
+	// Ignore any leave codes from CleanupAsyncExtractionL -
+	// they can't really be handled from the destructor.
+	TRAP_IGNORE(CleanupAsyncExtractionL());
+
+	Server().DropSession();
+	CSecurityPolicy::ReleaseResource();
+	}
+
+
+// Handle a client request. Leaving is handled by 
+// CSisHelperServer::ServiceError() which reports the error code to the client
+void CSisHelperSession::ServiceL(const RMessage2& aMessage)
+	{
+	DEBUG_PRINTF2(_L8("Sis Helper - Servicing Message Type %d."), aMessage.Function());
+	
+	TInt err = KErrNone;
+	switch (aMessage.Function())
+		{
+		case ESisHelperGetController:
+			{
+			TRAP(err, GetControllerL(aMessage));
+			if (err != KErrNone)
+				{
+				// Map unexpected KErrOverflow errors to KErrCorrupt; otherwise,
+				// sishelperclient will interpret this as a signal to resize the request
+				// buffer
+				aMessage.Complete((err == KErrOverflow ? KErrCorrupt : err));
+				}
+			break;
+			}
+			
+		case ESisHelperExtractFile:
+			{
+			TRAP(err, ExtractFileL(aMessage));
+			aMessage.Complete(err);
+			break;
+			}
+			
+		case ESisHelperFillDrivesAndSpaces:
+			{
+			// calculate the likely size of the data transfer buffer
+			const TInt KMaxBufSize=
+				sizeof(TInt)+                 // number of entries
+				KMaxDrives*sizeof(TUint)+  // drive letters stored as TUints
+				KMaxDrives*sizeof(TInt64); // drive free spaces
+			
+			// allocate buffer for the returned arrays
+			HBufC8* buf=HBufC8::NewMaxLC(KMaxBufSize);
+			
+			// create stream on the buffer
+			TPtr8 des=buf->Des();
+			RDesWriteStream outs(des);
+			CleanupClosePushL(outs);
+			
+			// get drive letter and free space information
+			RArray<TChar> driveLetters;
+			CleanupClosePushL(driveLetters);
+			RArray<TInt64> driveSpaces;
+			CleanupClosePushL(driveSpaces);
+			FillDrivesAndSpacesL(driveLetters, driveSpaces);
+			
+			// externalise the arrays
+			TInt count=driveLetters.Count();
+			outs.WriteInt32L(count);
+			TInt i;
+			for (i = 0; i < count; ++i)
+				{
+				outs.WriteInt32L(static_cast<TUint>(driveLetters[i]));
+				}
+			
+			for (i = 0; i < count; ++i)
+				{
+				outs.WriteInt32L(I64LOW(driveSpaces[i]));
+				outs.WriteInt32L(I64HIGH(driveSpaces[i]));
+				}
+			
+			// write the buffer to the passed buffer
+			outs.CommitL();
+			aMessage.WriteL(0, *buf);
+			
+			// cleanup
+			// driveSpaces, driveLetters, outs, buf
+			CleanupStack::PopAndDestroy(4, buf);
+			aMessage.Complete(KErrNone);
+			break;
+			}
+
+		case ESisHelperOpenDrmContent:
+			{
+			ContentAccess::TIntent intent
+				= static_cast<ContentAccess::TIntent>(aMessage.Int0());
+			
+			TRAPD(err, iDataProvider.OpenDrmContentL(intent));
+			aMessage.Complete(err);
+			break;
+			}
+		
+		case ESisHelperExecuteDrmIntent:
+			{
+			ContentAccess::TIntent intent
+				= static_cast<ContentAccess::TIntent>(aMessage.Int0());
+	
+			aMessage.Complete(iDataProvider.ExecuteDrmIntent(intent));
+			break;
+			}
+		
+		case ESisHelperSetupAsyncExtraction:
+			SetupAsyncExtractionL(aMessage);
+			break;
+			
+		case ESisHelperAsyncExtraction:
+			AsyncExtractionL(aMessage);
+			break;
+			
+		case ESisHelperEndAsyncExtraction:
+			EndAsyncExtractionL(aMessage);
+			break;
+
+		case ESisHelperCreateSisStub:
+			{
+			// write stub
+			TRAPD(err, CreateSisStubL(aMessage));
+			
+			// cleanup
+			aMessage.Complete(err);
+			break;
+			}
+		case ESisHelperIsStub:
+			{	
+			TRAPD(err,IsStubL(aMessage));
+			aMessage.Complete(err);
+			break;
+			}
+		case ESisHelperGetSisFileDrive:
+			{
+			TRAPD(err,GetSisFileDriveL(aMessage));	
+			aMessage.Complete(err);
+			break;
+			}
+		case ESisHelperIsSisFileReadOnly:
+			{
+			TRAPD(err,IsSisFileReadOnlyL(aMessage));	
+			aMessage.Complete(err);
+			break;
+			}
+		case ESisHelperGetSisFileName:
+			{
+			TRAP(err, GetSisFileNameL(aMessage));
+			aMessage.Complete(err);
+			break;
+			}			
+		case ESisHelperGetControllerFromSis:
+			{
+			TRAP(err, GetControllerFromSisL(aMessage));
+			aMessage.Complete(err);
+			break;
+			}
+		#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+		case ESisHelperIsDrmProtected:
+			{
+			TRAP(err, IsDrmProtectedL(aMessage));
+			aMessage.Complete(err);
+			break;
+			}
+		#endif
+		case ESisHelperGetEquivalentLanguages:
+			{
+			TRAP(err, GetEquivalentLanguagesL(aMessage));
+			aMessage.Complete(err);
+			break;
+			}	
+		default:
+			{
+			DEBUG_PRINTF(_L8("Sis Helper - Illegal Message Type."));
+			PanicClient(aMessage, EPanicIllegalFunction);
+			break;
+			}
+		}
+	}
+
+void CSisHelperSession::GetControllerL(const RMessage2& aMessage)
+	{
+	// Extract raw controller data into a buffer
+	HBufC8* controllerData = CurrentContentsL().ReadControllerL();
+	CleanupStack::PushL(controllerData);
+
+	// Get the data to the client using the standard overflow protocol
+	// - get the size of the supplied descriptor (parameter 0)
+	TInt size=aMessage.GetDesMaxLengthL(0);
+	// - see if we have enough space on the client
+	if (size < controllerData->Size())
+		{
+		// not enough space, complete with KErrOverflow and encode the
+		// required size into the passed descriptor
+		TPckgC<TInt> sizePckg(controllerData->Size());
+
+		// is there enough space for an integer?
+		if (size >= sizePckg.Size())
+			{
+			aMessage.WriteL(0, sizePckg);
+			}
+		// complete the message with KErrOverflow when resizing requires
+		aMessage.Complete(KErrOverflow);
+		}
+	else
+		{
+		// enough space, write the controller to the supplied buffer
+		aMessage.WriteL(0, *controllerData);
+		//Everything went fine so complete the message with KErrNone.
+		aMessage.Complete(KErrNone);
+		}
+	CleanupStack::PopAndDestroy(controllerData); // controllerData				
+	}
+
+void CSisHelperSession::ExtractFileL(const RMessage2& aMessage)
+	{
+	RFile file;
+	file.AdoptFromClient(aMessage, 0, 1);			
+	CleanupClosePushL(file);
+	TInt fileIndex = aMessage.Int2();
+	TInt dataUnit = aMessage.Int3();
+
+	CurrentContentsL().ReadDataL(file, fileIndex, dataUnit);
+	User::LeaveIfError(file.Flush());
+	CleanupStack::PopAndDestroy(&file); // file
+	}
+
+void CSisHelperSession::IsStubL(const RMessage2& aMessage)
+	{
+	TBool stub = CurrentContentsL().IsStub();	
+	TPckg<TBool> stubPckg(stub);
+	aMessage.WriteL(0, stubPckg);
+	}
+
+void CSisHelperSession::GetSisFileDriveL(const RMessage2& aMessage)
+	{
+	TChar drive;
+	User::LeaveIfError(RFs::DriveToChar(Server().GetSisFileDrive(), drive));
+	TPckg<TChar> drivePckg(drive);
+	aMessage.WriteL(0, drivePckg);
+	}
+
+void CSisHelperSession::IsSisFileReadOnlyL(const RMessage2& aMessage)
+	{
+	TBool readOnly = Server().IsSisFileReadOnly();
+	TPckg<TBool> readOnlyPckg(readOnly);
+	aMessage.WriteL(0, readOnlyPckg);
+	}
+
+void CSisHelperSession::GetSisFileNameL(const RMessage2& aMessage)
+	{
+	TInt clientDesLength = aMessage.GetDesMaxLengthL(0);
+	TPtrC filename = Server().GetSisFileNameL();
+	if (clientDesLength < filename.Length())
+		{
+		User::Leave(KErrOverflow);
+		}
+	if (filename.Length() == 0)
+		{
+		User::Leave(KErrNotFound);
+		}
+	aMessage.WriteL(0, filename);
+	}
+
+void CSisHelperSession::GetControllerFromSisL(const RMessage2& aMessage)
+	{
+	// Get the file handle
+	RFile file;
+	// Adopt the file using the RFs handle from message slot 1 and the RFile handle from slot 2
+	User::LeaveIfError(file.AdoptFromClient(aMessage, 1, 2));          
+	CleanupClosePushL(file);
+
+	// Create a file data provider
+	MSisDataProvider* dataProvider = NULL;
+	CSecurityPolicy* securityPolicy = CSecurityPolicy::GetSecurityPolicyL();
+	TBool drmEnabled = securityPolicy->DrmEnabled();
+	securityPolicy->ReleaseResource();
+	if (drmEnabled)
+		{
+		dataProvider = CCafSisDataProvider::NewLC(file);
+		dataProvider->OpenDrmContentL(ContentAccess::EInstall);
+		User::LeaveIfError(dataProvider->ExecuteDrmIntent(ContentAccess::EUnknown));
+		}
+	else
+		{
+		dataProvider = CFileSisDataProvider::NewLC(file);
+		}
+
+	// Extract raw controller data into a buffer
+	TInt64 pos(0);
+	User::LeaveIfError(dataProvider->Seek(ESeekStart, pos));
+	Sis::CContents *contents = Sis::Parser::ContentsL(*dataProvider);
+	CleanupStack::PushL(contents);
+	HBufC8* controllerData = NULL;
+	TRAPD(err, controllerData = contents->ReadControllerL());
+	if(err == KErrOverflow)
+   		{
+   		User::Leave(KErrCorrupt);			
+   		}
+	User::LeaveIfError(err);
+	CleanupStack::PushL(controllerData);
+
+	// Get the data to the client using the standard overflow protocol
+	// - get the size of the supplied descriptor (parameter 0)
+	TInt size = aMessage.GetDesMaxLengthL(0);
+	// - see if we have enough space on the client
+	if (size < controllerData->Size())
+		{
+		// Not enough space, complete with KErrOverflow and encode the
+		// required size into the passed descriptor
+		TPckgC<TInt> sizePckg(controllerData->Size());
+
+		// Is there enough space for an integer?
+		if (size >= sizePckg.Size())
+			{
+			aMessage.WriteL(0, sizePckg);
+			}
+		// complete the message with KErrOverflow when resizing requires
+		User::Leave(KErrOverflow);
+		}
+	else
+		{
+		// Enough space, write the controller to the supplied buffer
+		aMessage.WriteL(0, *controllerData);
+		}
+	CleanupStack::PopAndDestroy(4, &file); // dataProvider, contents, controllerData
+	}
+
+
+	// Functions for asynchronous extraction
+void CSisHelperSession::SetupAsyncExtractionL(const RMessage2& aMessage)
+	{
+	// We only support extracting one file at once currently
+	if (iInAsyncExtraction)
+		{
+		aMessage.Complete(KErrInUse);
+		}
+	else
+		{
+		// Get file and session handles
+		User::LeaveIfError(iAsyncFs.Open(aMessage, 0));
+
+		// Adopt the filehandle;
+		User::LeaveIfError(iAsyncFile.Adopt(iAsyncFs, aMessage.Int1()));
+	
+		iAsyncFileIndex=aMessage.Int2();
+		iAsyncDataUnit=aMessage.Int3();
+	
+		iInAsyncExtraction=ETrue;
+		aMessage.Complete(KErrNone);
+		}
+	}
+
+void CSisHelperSession::AsyncExtractionL(const RMessage2& aMessage)
+	{
+	TInt lengthHigh=aMessage.Int0();
+	TInt lengthLow=aMessage.Int1();
+	TInt64 length= lengthHigh;
+	length=( length << 32) + lengthLow;
+				
+	CurrentContentsL().ReadDataL(iAsyncFile, iAsyncFileIndex, iAsyncDataUnit, length);
+	TInt err = iAsyncFile.Flush();
+
+	aMessage.Complete(err);
+	}
+
+void CSisHelperSession::EndAsyncExtractionL(const RMessage2& aMessage)
+	{
+	if (!iInAsyncExtraction)
+		{
+		aMessage.Complete(KErrArgument);
+		}
+	else
+		{
+		CleanupAsyncExtractionL();
+		aMessage.Complete(KErrNone);
+		}
+	}
+
+void CSisHelperSession::CleanupAsyncExtractionL()
+	{
+	if (iInAsyncExtraction)
+		{
+		iAsyncFile.Close();
+		iAsyncFs.Close();
+		iInAsyncExtraction=EFalse;
+		}
+	}
+
+// Handle an error from CSisHelperSession::ServiceL(). A bad descriptor 
+// error implies a badly programmed client, so panic it; otherwise use the
+// default handling (report error to the client)
+void CSisHelperSession::ServiceError(const RMessage2& aMessage, TInt aError)
+	{
+	if (aError==KErrBadDescriptor)
+		{
+		PanicClient(aMessage, EPanicBadDescriptor);
+		}
+	CSession2::ServiceError(aMessage, aError);
+	}
+
+void CSisHelperSession::FillDrivesAndSpacesL(RArray<TChar>& aDriveLetters, 
+					                        RArray<TInt64>& aDriveSpaces)
+	{
+	// This is the LFSS free space threshold
+	TInt freeSpaceAdjustment = 1024 * 128;    // Bytes	
+
+    // get information about drives
+    TDriveList driveList;
+    RFs fs;
+    User::LeaveIfError(fs.Connect());
+    CleanupClosePushL(fs);
+    
+    // List all drives in the system
+    User::LeaveIfError(fs.DriveList(driveList));
+
+	// Check all drives
+    for (TInt driveNumber=EDriveA; driveNumber<=EDriveZ; driveNumber++)
+        {
+        if (!driveList[driveNumber])
+ 			{
+ 			// Not a recognised drive
+            continue;
+			}
+			
+    	TVolumeInfo volInfo;
+        if (fs.Volume(volInfo, driveNumber) != KErrNone)
+			{
+			// The volume is not usable (e.g. no media card inserted)
+            continue;
+			}
+
+        if (volInfo.iDrive.iType==EMediaNotPresent || 
+            volInfo.iDrive.iType==EMediaRom || 
+            volInfo.iDrive.iType==EMediaRemote)
+			{
+			// Exclude drives not suitable for installation
+            continue;
+			}
+			
+        // Do not list read only and substituted drives as an option to install to
+        if (volInfo.iDrive.iDriveAtt & KDriveAttRom || 
+         	volInfo.iDrive.iDriveAtt & KDriveAttSubsted) 
+			{
+            continue;
+			}
+
+        TInt64 volSpace = volInfo.iFree - freeSpaceAdjustment;  // bytes
+        if (volSpace < 0)
+			{
+            volSpace = 0;
+			}
+			
+		TChar aDrive;
+		User::LeaveIfError(fs.DriveToChar(driveNumber, aDrive));
+		User::LeaveIfError(aDriveLetters.Append(TChar(aDrive)));
+        User::LeaveIfError(aDriveSpaces.Append(volSpace));
+        }
+    CleanupStack::PopAndDestroy(&fs);
+	}
+
+
+void CSisHelperSession::CreateSisStubL(const RMessage2& aMessage)
+	{
+	RFile file;
+	file.AdoptFromClient(aMessage, 0, 1);			
+	CleanupClosePushL(file);
+		
+	// rewind the data provider
+	TInt64 pos(0);
+	User::LeaveIfError(iDataProvider.Seek(ESeekStart, pos));
+	
+	Sis::Parser::CreateSisStubL(file, iDataProvider);	
+	CleanupStack::PopAndDestroy(&file);  //close
+	}
+
+//
+// CSisHelperServer implementation
+//
+
+// All functions can only be accessed by SWIS
+const TInt CSisHelperServer::iRanges[iRangeCount] = 
+                {
+                0 // All connect attempts
+                };
+
+const TUint8 CSisHelperServer::iElementsIndex[iRangeCount] = 
+                {
+                0 //Only SWIS can use sishelper. This is policed by the SID of SWIS
+                };
+
+const CPolicyServer::TPolicyElement CSisHelperServer::iPolicyElements[2] = 
+                {
+                {_INIT_SECURITY_POLICY_S0(0x101F7295), //SWIS' SID = 0x101F7295
+                	CPolicyServer::EFailClient},		
+                
+                              
+   
+                };
+
+const CPolicyServer::TPolicy CSisHelperServer::iPolicy =
+                {
+                0,					//specifies all connect attempts need SWIS' SID
+                iRangeCount,
+                iRanges,
+                iElementsIndex,
+                iPolicyElements,
+                };
+
+// Construction, the result is on the cleanup stack
+EXPORT_C CSisHelperServer* CSisHelperServer::NewLC(TSisHelperStartParams& aParams)
+	{
+	CSisHelperServer* self=new(ELeave) CSisHelperServer;
+	CleanupStack::PushL(self);
+	self->ConstructL(aParams);
+	return self;
+	}
+
+// Construction
+EXPORT_C CSisHelperServer* CSisHelperServer::NewL(TSisHelperStartParams& aParams)
+	{
+	CSisHelperServer* self=NewLC(aParams);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+// 2nd phase constructor; ensure the timer and server objects are running
+void CSisHelperServer::ConstructL(TSisHelperStartParams& aParams)
+	{
+	// See what kind of startup information is passed to the server
+	switch (aParams.iType)
+		{
+		case TSisHelperStartParams::ETypeFileName:
+			{
+			// Create a file data provider
+			User::LeaveIfError(iFs.Connect());
+			iSessionConnected=ETrue;
+
+			CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
+			
+			_LIT(KDriveSeparator, ":\\");
+			TPtrC sisFileName(*aParams.iFileName);	
+			if (sisFileName.Find(KDriveSeparator) != 1)
+				{
+				// The full path (inc. drive letter) has not been specified
+				TEntry* fileExits = new(ELeave) TEntry;
+				CleanupStack::PushL(fileExits);
+				TInt err = iFs.Entry(sisFileName, *fileExits);
+				if (err == KErrNone)
+					{
+					// Found it, must be /xxxxx.sis. Fill in the missing
+					// drive path
+					TParse* sisFileWithDrv = new(ELeave) TParse;
+					CleanupStack::PushL(sisFileWithDrv);
+					iFs.Parse(sisFileName, *sisFileWithDrv);
+					// Get the SIS file name
+					iSisFileName = sisFileWithDrv->FullName().AllocL();
+					User::LeaveIfError(RFs::CharToDrive(sisFileWithDrv->Drive()[0], iSisFileDrive));
+					CleanupStack::PopAndDestroy(sisFileWithDrv);				
+					}
+				CleanupStack::PopAndDestroy(fileExits);		
+				}
+			else
+				{
+				// figure out which drive this SIS file came from
+				TParsePtrC parser(sisFileName);
+				User::LeaveIfError(RFs::CharToDrive(parser.Drive()[0], iSisFileDrive));
+				// Get the SIS file name
+				iSisFileName = sisFileName.AllocL();
+				}
+			
+			if (securityPolicy->DrmEnabled())
+				{
+				iDataProvider=CCafSisDataProvider::NewL(sisFileName);
+				}
+			else
+				{
+				iDataProvider=CFileSisDataProvider::NewL(iFs, sisFileName);
+				}	
+
+			iDeleteDataProvider=ETrue;
+
+			// Figure out whether the sis file is read only or the drive is
+			// write-protected or ROM.
+			TDriveInfo driveInfo;
+			User::LeaveIfError(iFs.Drive(driveInfo,iSisFileDrive));
+			if (!((driveInfo.iMediaAtt & KMediaAttWriteProtected) ||
+				(driveInfo.iDriveAtt & KDriveAttRom)))
+				{
+				TEntry entry;
+				User::LeaveIfError(iFs.Entry(sisFileName, entry));
+				iSisFileReadOnly = entry.IsReadOnly();
+				}
+			}
+			break;
+
+		case TSisHelperStartParams::ETypeFileHandle:
+			{
+			CSecurityPolicy* securityPolicy=CSecurityPolicy::GetSecurityPolicyL();
+
+			if (securityPolicy->DrmEnabled())
+				{
+				iDataProvider=CCafSisDataProvider::NewL(*aParams.iFileHandle);
+				}
+			else
+				{
+				iDataProvider=CFileSisDataProvider::NewL(*aParams.iFileHandle);
+				}	
+
+			iDeleteDataProvider=ETrue;
+			
+			// figure out which drive this SIS file came from
+			TDriveInfo driveInfo;
+			User::LeaveIfError(aParams.iFileHandle->Drive(iSisFileDrive, driveInfo));
+
+			// Figure out whether the sis file is read only or the drive is
+			// write-protected or ROM.
+			if (!((driveInfo.iMediaAtt & KMediaAttWriteProtected) ||
+				(driveInfo.iDriveAtt & KDriveAttRom)))
+				{
+				TUint attributes;
+				User::LeaveIfError(aParams.iFileHandle->Att(attributes));
+				iSisFileReadOnly = (attributes & KEntryAttReadOnly) ? ETrue : EFalse;
+				}
+
+			// Get SIS file name
+			TFileName tempFileName;
+			User::LeaveIfError(aParams.iFileHandle->FullName(tempFileName));
+			iSisFileName = tempFileName.AllocL();
+			DEBUG_PRINTF2(_L("Sis Helper - processing %S by file handle"), iSisFileName);
+			}			
+			break;			
+		case TSisHelperStartParams::ETypeDataProvider:
+			// store the pointer, assuming ownership, check for NULL
+			iDataProvider=aParams.iDataProvider;
+			iDeleteDataProvider=EFalse;
+			if (iDataProvider==NULL)
+				{
+				PanicClient(Message(), EPanicBadDataProvider);
+				}
+			break;
+		case TSisHelperStartParams::ETypeNull:
+			// For use where file is passed in later along with request
+			break;
+
+		default:
+			// panic the client
+			PanicClient(Message(), EPanicBadStartupDataType);
+			break;
+		}
+		
+	StartL(KSisHelperServerName);
+	iShutdown=new(ELeave) CSisHelperShutdown;
+	iShutdown->ConstructL();
+	
+	// ensure that the server still exists even if the 1st client fails 
+	// to connect; the server will be terminated if no one connects to it
+	iShutdown->Start();
+	}
+
+CSisHelperServer::CSisHelperServer()
+:	CPolicyServer(CActive::EPriorityStandard, iPolicy, ESharableSessions),
+	iSisFileDrive(-1),
+	iSisFileReadOnly(ETrue)
+	{
+	}
+
+// Destruction; delete a data provider since we own it whether it was 
+// transferred from outside or created in the server.
+CSisHelperServer::~CSisHelperServer()
+	{
+	delete iShutdown;
+	
+	if (iDeleteDataProvider)
+		{
+		delete iDataProvider;
+		}
+
+	if (iSessionConnected)
+		{
+		iFs.Close();
+		}
+
+	if (iSisFileName)
+		{
+		delete iSisFileName;
+		}
+	
+	// Free ECOM memory reserved in this thread
+	// for example, plugins loaded by the CAF framework	
+	REComSession::FinalClose();
+
+
+		
+	}
+
+// Create a new client session
+CSession2* CSisHelperServer::NewSessionL(const TVersion&,
+	const RMessage2& ) const
+	{
+	
+	return new(ELeave) CSisHelperSession(*iDataProvider);
+	}
+	
+// A new session is being created; cancel the shutdown timer if it was running
+void CSisHelperServer::AddSession()
+	{
+	++iSessionCount;
+	DEBUG_PRINTF2(_L8("Sis Helper - Adding Session (%d active.)"), iSessionCount);
+	// stop shutdown object once the first (and only) session is connected
+	delete iShutdown;
+	iShutdown=NULL;
+	}
+
+// A session is being destroyed; terminate server immediately
+void CSisHelperServer::DropSession()
+	{
+	if (--iSessionCount==0)
+		{
+		CActiveScheduler::Stop();
+		}
+	DEBUG_PRINTF2(_L8("Sis Helper - Dropping Session (%d active.)"), iSessionCount);
+	}
+
+CSisRegistryPackage* CSisHelperServer::MainPackageEntryL(TUid aUid)
+	{
+	RSisRegistrySession registrySession;
+	User::LeaveIfError(registrySession.Connect());
+	CleanupClosePushL(registrySession);
+
+	RSisRegistryEntry registryEntry;
+	User::LeaveIfError(registryEntry.Open(registrySession, aUid));
+	CleanupClosePushL(registryEntry);
+
+    // Get the package object associated with the entry
+    CSisRegistryPackage* package = registryEntry.PackageL();
+
+    CleanupStack::PopAndDestroy(2, &registrySession);
+	return package;
+	}
+
+//
+// Starts SISHelper in a new thread
+//
+TInt CSisHelperServer::StartSisHelper(TSisHelperStartParams& aParams, 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, static_cast<TAny*>(&aParams), 
+					   		EOwnerThread);
+					   		
+		if (err == KErrAlreadyExists || err == KErrInUse)
+			{
+			  User::After(80000);
+			}
+		else
+			{
+			break;
+			}
+		}
+
+	if (err==KErrAlreadyExists)
+		{
+		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;
+	}
+
+void CSisHelperServer::Abort()
+	{
+	TFullName fullName = RProcess().FullName();
+	fullName.Append(':');
+	fullName.Append(':');
+	fullName.Append(KSisHelperServerName);
+
+	RThread server;
+	TInt err = server.Open(fullName);
+	if (err == KErrNone)
+		{
+		server.Terminate(KErrAbort);
+		server.Close();
+		}
+	}
+
+// Entry point for the thread the SISHelper runs in
+TInt CSisHelperServer::SisHelperThreadFunction(TAny *aPtr)
+	{
+	if (aPtr==NULL)
+		{
+		return KErrArgument;
+		}
+		
+	CTrapCleanup* cleanup = CTrapCleanup::New(); // get clean-up stack
+	
+	TSisHelperStartParams* params=
+	static_cast<TSisHelperStartParams*>(aPtr);
+
+	CActiveScheduler* scheduler=new(ELeave) CActiveScheduler;
+	if (!scheduler)
+		{
+		return KErrNoMemory;
+		}
+		
+	DEBUG_PRINTF(_L8("Sis Helper - Starting Server"));
+
+	CActiveScheduler::Install(scheduler);
+	CSisHelperServer* server=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
+
+	CSecurityPolicy::ReleaseResource();
+	
+	return err;
+	}
+
+TInt CSisHelperServer::GetSisFileDrive()
+	{
+	return iSisFileDrive;
+	}
+
+TBool CSisHelperServer::IsSisFileReadOnly()
+	{
+	return iSisFileReadOnly;
+	}
+
+const TDesC& CSisHelperServer::GetSisFileNameL()
+	{
+	if (!iSisFileName)
+		{
+		User::Leave(KErrNotFound);
+		}
+	return *iSisFileName;
+	}
+
+Sis::CContents& CSisHelperSession::CurrentContentsL()
+	{
+	if(iCurrentContents == NULL)
+		{
+		TInt64 pos(0);
+		User::LeaveIfError(iDataProvider.Seek(ESeekStart, pos));
+		iCurrentContents=Sis::Parser::ContentsL(iDataProvider);
+		}
+	return *iCurrentContents;
+	}
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+void CSisHelperSession::IsDrmProtectedL(const RMessage2& aMessage)
+	{
+	// Data provider will be of CCafSisDataProvider only when DRM is enabled in SWI policy.
+	// So, check the policy before querying content protection status from the data provider.
+	CSecurityPolicy* securityPolicy = CSecurityPolicy::GetSecurityPolicyL();
+	if (securityPolicy->DrmEnabled())
+		{
+		CCafSisDataProvider* cafDataProvider = static_cast<CCafSisDataProvider*>(&iDataProvider);
+ 		TBool isProtected = cafDataProvider->IsContentProtected();	
+   		TPckgBuf<TBool> isContentProtected(isProtected);
+   		aMessage.WriteL(0, isContentProtected);
+   		securityPolicy->ReleaseResource();
+		}
+	// If DRM is NOT enabled in SWI policy, no way to query the protection status. So, set it to Fasle.
+	else
+		{
+		aMessage.WriteL(0, TPckgBuf<TBool>(EFalse));
+		}
+	}
+#endif
+
+void CSisHelperSession::GetEquivalentLanguagesL(const RMessage2& aMessage)
+	{
+	TLanguage srcLangID = (TLanguage)aMessage.Int1();
+	
+	TLanguagePath equivalentLangs;
+	BaflUtils::GetEquivalentLanguageList(srcLangID,equivalentLangs);
+	
+	// calculate the likely size of the data transfer buffer
+	const TInt KMaxBufSize=
+		sizeof(TInt)+                 // number of entries
+		(KMaxDowngradeLanguages+1)*sizeof(TLanguage);  // Languages IDs stored as TLanguage
+	
+	// allocate buffer for the array
+	HBufC8* buf=HBufC8::NewMaxLC(KMaxBufSize);
+	
+	TInt size = 1;
+	while (equivalentLangs[size++] != ELangNone){}
+		
+	TPtr8 pBuf=buf->Des();
+	RDesWriteStream outs(pBuf);
+	CleanupClosePushL(outs);
+	
+	// Since the size contains the source language ID and ELangNone, the actual size is equal to size - 2
+	outs.WriteInt32L(size-2);
+	TInt i;
+	for (i = 1; i < size-1; ++i)
+		{
+		outs.WriteInt32L(static_cast<TInt>(equivalentLangs[i]));
+		}
+	
+	outs.CommitL();
+	aMessage.WriteL(0, *buf);
+	
+	CleanupStack::PopAndDestroy(2,buf); //outs,buf
+	}
+
+
+} // namespace Swi