diff -r 000000000000 -r ba25891c3a9e installationservices/swi/source/sishelper/sishelper.cpp --- /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 +#include +#include +#include +#include // 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( + const_cast(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 driveLetters; + CleanupClosePushL(driveLetters); + RArray 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(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(aMessage.Int0()); + + TRAPD(err, iDataProvider.OpenDrmContentL(intent)); + aMessage.Complete(err); + break; + } + + case ESisHelperExecuteDrmIntent: + { + ContentAccess::TIntent intent + = static_cast(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 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 stubPckg(stub); + aMessage.WriteL(0, stubPckg); + } + +void CSisHelperSession::GetSisFileDriveL(const RMessage2& aMessage) + { + TChar drive; + User::LeaveIfError(RFs::DriveToChar(Server().GetSisFileDrive(), drive)); + TPckg drivePckg(drive); + aMessage.WriteL(0, drivePckg); + } + +void CSisHelperSession::IsSisFileReadOnlyL(const RMessage2& aMessage) + { + TBool readOnly = Server().IsSisFileReadOnly(); + TPckg 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 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& aDriveLetters, + RArray& 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, ®istrySession); + 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(&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(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(&iDataProvider); + TBool isProtected = cafDataProvider->IsContentProtected(); + TPckgBuf 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(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(equivalentLangs[i])); + } + + outs.CommitL(); + aMessage.WriteL(0, *buf); + + CleanupStack::PopAndDestroy(2,buf); //outs,buf + } + + +} // namespace Swi