libraries/qr3/src/sandbox.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 37 534b01198c2d
parent 0 7f656887cf89
permissions -rw-r--r--
Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase. Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.

// sandbox.cpp
// 
// Copyright (c) 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include <e32base.h>
#include "sandbox.h"
#include <APMREC.H>
#include <fshell/memoryaccess.h>

enum TMsg
	{
	EGetRecog,
	EGetRecog2,
	ECloseServer,
	EGetVTablePtr,
	EMaxArgs,
	};

#ifndef SERVER


class RSandboxSession : public RSessionBase
	{
public:
	TInt Connect(const TDesC& aServerName)
		{
		return CreateSession(aServerName, TVersion(0,0,0));
		}

	TInt GetRecogniserInfo(TUid aImplementationUid, RArray<TDataType>& aMimeTypes)
		{
		TInt size = SendReceive(EGetRecog, TIpcArgs(aImplementationUid.iUid));
		if (size < 0) return size;
		TInt err = aMimeTypes.Reserve(size/sizeof(TDataType));
		if (err) return err;
		RBuf8 buf;
		err = buf.Create(size);
		if (err) return err;
		err = SendReceive(EGetRecog2, TIpcArgs(&buf));
		if (err) { buf.Close(); return err; }

		const TDataType* ptr = (const TDataType*)buf.Ptr();
		for (TInt i = 0; i < size/sizeof(TDataType); i++)
			{
			err = aMimeTypes.Append(ptr[i]);
			if (err) break;
			}
		buf.Close();
		return err;
		}

	TInt GetVTablePtrFromEcomUid(TUid aUid, TAny*& vtablePtr)
		{
		TPckgBuf<TAny*> pkg(NULL);
		TInt err = SendReceive(EGetVTablePtr, TIpcArgs(aUid.iUid, &pkg));
		if (err) return err;
		vtablePtr = pkg();
		return KErrNone;
		}

	void Byebye()
		{
		SendReceive(ECloseServer);
		}
	};

#define GETSESSIONL(process, session)										\
	RProcess process;														\
	User::LeaveIfError(process.Create(_L("QR3Sandbox.exe"), KNullDesC));	\
	TRequestStatus stat;													\
	process.Rendezvous(stat);												\
	process.Resume();														\
	User::WaitForRequest(stat);												\
																			\
	RSandboxSession session;												\
	User::LeaveIfError(session.Connect(sandbox.FullName()));


void Sandbox::GetRecogniserInfoL(TUid aImplementationUid, RArray<TDataType>& aMimeTypes)
	{
	GETSESSIONL(sandbox, sess);

	User::LeaveIfError(sess.GetRecogniserInfo(aImplementationUid, aMimeTypes));

	sess.Byebye();
	sandbox.Close();
	}

void Sandbox::GetDllNameFromEcomUidL(RMemoryAccess& aMemAccess, TUid aUid, TFileName& aFileName)
	{
	// Try and instanciate object and figure out what DLL it belongs to by looking up its vtable pointer
	// We do the instanciation in a separate process so as to avoid worrying about cleanup or side-effects of instanciation

	GETSESSIONL(sandbox, sess);

	TAny* vtablePtr = NULL;
	TInt err = sess.GetVTablePtrFromEcomUid(aUid, vtablePtr);

	TFullName8 dllName;
	if (!err)
		{
		err = aMemAccess.FindAddressInCodeSegments(dllName, vtablePtr);
		}
	sess.Byebye(); // We have to call FindAddressInCodeSegments before sandbox exits, because when it does the code segment will most likely be unloaded!
	sandbox.Close();
	User::LeaveIfError(err);
	
	aFileName.Copy(dllName);
	}


#else

#include <e32property.h>
#include <ecom/ecom.h>

void GoL();

class CSandboxSession : public CSession2
	{
	void ServiceL(const RMessage2 &aMessage);
	RBuf8 iBuf;
	};

class CSandboxServer : public CServer2
	{
public:
	CSandboxServer() : CServer2(0,ESharableSessions) {}

protected:
	CSession2* NewSessionL(const TVersion& /*aVersion*/, const RMessage2& /*aMessage*/) const
		{
		return new(ELeave) CSandboxSession();
		}
	};


TInt E32Main()
	{
	User::SetJustInTime(EFalse); // Don't want to debug problems in the sandbox

	CTrapCleanup* cleanup=CTrapCleanup::New();
	TRAPD(err, GoL());
	return err;
	}

void GoL()
	{
	CActiveScheduler* s=new(ELeave) CActiveScheduler;
	CActiveScheduler::Install(s);
	CSandboxServer* server = new(ELeave) CSandboxServer();
	// Scope the TFullName
		{
		TFullName serverName = RProcess().FullName();
		server->StartL(serverName);
		}
	RProcess::Rendezvous(KErrNone);
	CActiveScheduler::Start();
	}

void CSandboxSession::ServiceL(const RMessage2 &aMessage)
	{
	if (aMessage.Function() >= EMaxArgs)
		{
		aMessage.Complete(KErrArgument);
		return;
		}

	if (aMessage.Function() == EGetRecog2)
		{
		aMessage.WriteL(0, iBuf);
		iBuf.Close();
		aMessage.Complete(KErrNone);
		}
	else if (aMessage.Function() == EGetRecog)
		{
		if (iBuf.MaxLength() == 0)
			{
			iBuf.ReAllocL(1024); // Must be > sizeof(TDataType) otherwise the reallocating logic below is flawed
			}
		TUid uid = TUid::Uid(aMessage.Int0());
		TUid destructorKey;
		CApaDataRecognizerType* rec = static_cast<CApaDataRecognizerType*>(REComSession::CreateImplementationL(uid, destructorKey));
		TInt count = rec->MimeTypesCount();
		for (TInt j = 0; j < count; j++)
			{
			TDataType type = rec->SupportedDataTypeL(j);
			TPckg<TDataType> buf(type);
			if (iBuf.Length() + buf.Length() >= iBuf.MaxLength())
				{
				iBuf.ReAllocL(iBuf.MaxLength() * 2);
				}
			iBuf.Append(buf);
			}

		aMessage.Complete(iBuf.Size());
		}
	else if (aMessage.Function() == ECloseServer)
		{
		aMessage.Complete(KErrNone);
		CActiveScheduler::Stop();
		}
	else if (aMessage.Function() == EGetVTablePtr)
		{
		TUid destructorKey;
		TAny* obj = NULL;
		obj = REComSession::CreateImplementationL(TUid::Uid(aMessage.Int0()), destructorKey);
		TAny* vtablePtr = *((TAny**)obj);	
		TPckg<TAny*> res(vtablePtr);
		aMessage.WriteL(1, res);
		aMessage.Complete(KErrNone);
		}
	else
		{
		ASSERT(0);
		}
	}

#endif