libraries/clogger/src/CloggerClient.cpp
changeset 0 7f656887cf89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libraries/clogger/src/CloggerClient.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,822 @@
+// CloggerClient.cpp
+// 
+// Copyright (c) 2006 - 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 "clogger.h"
+#include "cliserv.h"
+#include "SensibleClient_Internals.h"
+#include "common.h"
+#include <badesca.h>
+#include <s32mem.h>
+#include <e32property.h>
+
+#define KFlagsMask 0x0FFFFFFF
+#define KTestTagEnabled 0x10000000
+#define KNoLogMask 0x80000000 // This is the log mask used internally if you call an overload which doesn't specify one
+
+#define iBody (*reinterpret_cast<RCloggerBody*>(&iPimpl))
+
+#ifndef PERFORMANCE_CRITICAL
+
+// declares RClogger* clogger
+#define CheckConnected()                                       \
+	RClogger _cloggerHandle;                                   \
+	RClogger* clogger = &_cloggerHandle;                       \
+	GetTls(clogger, ETrue);                                    \
+	if (!clogger) return
+
+#define GetTlsOrConnect(aTag)                                  \
+	RClogger _cloggerHandle;                                   \
+	RClogger* clogger = &_cloggerHandle;                       \
+	TInt err;                                                  \
+	TBool isHandle = GetTls(clogger, ETrue, &aTag, &err)
+
+#define GetTlsOrNull()                                         \
+	RClogger _cloggerHandle;                                   \
+	RClogger* clogger = &_cloggerHandle;                       \
+	TBool isHandle = GetTls(clogger, EFalse)
+
+TBool RClogger::GetTls(RClogger*& aClogger, TBool aAutoConnect, const TDesC* aTag, TInt* aError)
+	{
+	TAny* tls = Dll::Tls();
+	if ((TUint)tls & 1)
+		{
+		// Then it's a handle
+		aClogger->SetHandle((TInt)((TUint)tls >> 1));
+		return ETrue;
+		}
+	else if (tls)
+		{
+		// Then it's a pointer
+		aClogger = (RClogger*)tls;
+		return EFalse;
+		}
+	else if (aAutoConnect)
+		{
+		TInt err = aClogger->Connect(aTag ? *aTag : KNullDesC);
+		aClogger->iFlags &= ~EUseHeapBuffer; // Don't (by default) use a buffer for static connections because we can't track it without upgrading TLS
+		if (err)
+			{
+			if (aError) *aError = err;
+			aClogger = NULL;
+			return ETrue;
+			}
+		__ASSERT_DEBUG((aClogger->Handle() & 0x80000000) == 0, User::Panic(_L("HandleTooBig"), 0));
+
+		err = Dll::SetTls((TAny*) ((aClogger->Handle() << 1) | 1));
+		if (err)
+			{
+			aClogger->Close();
+			if (aError) *aError = err;
+			aClogger = NULL;
+			}
+		return ETrue;
+		}
+	else
+		{
+		aClogger = NULL;
+		return ETrue;
+		}
+	}
+
+#endif // PERFORMANCE_CRITICAL
+
+NONSHARABLE_CLASS(RCloggerBody) : public RSensibleSessionBody
+	{
+public:
+	RCloggerBody(RClogger& aSession);
+	TInt DoCreateSession(const TDesC &aServer, const TVersion &aVersion, TInt aAsyncMessageSlots);
+	TInt DoSendReceive(TInt aFunction, const TIpcArgs &aArgs) const;
+	void DoSendReceive(TInt aFunction, const TIpcArgs &aArgs, TRequestStatus& aStatus) const;
+	void ServerDiedL();
+	void DispatchCallbackL(TServerCallback& aCallback, TCallbackParser& aParser);
+
+private:
+	friend class RClogger;
+	//RClogger& iSession; // No need to store this, we can calculate it from our this pointer since we know we are always embedded in an RClogger
+	};
+
+#define iSession (*(RClogger*)((TUint8*)this - _FOFF(RClogger, iPimpl)))
+
+RCloggerBody::RCloggerBody(RClogger& /*aSession*/)
+	: RSensibleSessionBody() //, iSession(aSession)
+	{}
+
+TInt RCloggerBody::DoCreateSession(const TDesC &aServer, const TVersion &aVersion, TInt aAsyncMessageSlots)
+	{
+	return iSession.CreateSession(aServer, aVersion, aAsyncMessageSlots);
+	}
+
+TInt RCloggerBody::DoSendReceive(TInt aFunction, const TIpcArgs &aArgs) const
+	{
+	return iSession.SendReceive(aFunction, aArgs);
+	}
+
+void RCloggerBody::DoSendReceive(TInt aFunction, const TIpcArgs &aArgs, TRequestStatus& aStatus) const
+	{
+	iSession.SendReceive(aFunction, aArgs, aStatus);
+	}
+
+EXPORT_C RClogger::RClogger()
+	: iFlags(0), iEnabled(EAllEnabled), iBuf(), iSequence(0)
+	{
+	__ASSERT_COMPILE(sizeof(iPimpl) >= sizeof(RCloggerBody));
+	__ASSERT_COMPILE(sizeof(RClogger) == 10*4); // This is the size we've published, it CANNOT change
+
+	// Initialise the body using placement new
+	new(iPimpl) RCloggerBody(*this);
+	}
+
+EXPORT_C RClogger::RClogger(TAny* aTls)
+	: iFlags(0), iEnabled(EAllEnabled), iBuf(), iSequence(0)
+	{
+	// This overload is only ever supposed to be used by the TlsLog inline functions, hence why it's private but still
+	// exported.
+	new(iPimpl) RCloggerBody(*this);
+	SetHandle(reinterpret_cast<TInt>(aTls));
+	}
+
+EXPORT_C TInt RClogger::Connect()
+	{
+	return Connect(KNullDesC);
+	}
+
+EXPORT_C TInt RClogger::Connect(const TDesC& aTag)
+	{
+	iFlags |= EUseHeapBuffer; // Set by default
+
+	TInt err = iBody.Connect(1, EFalse); // Only need 1 slot as we only have one async function (which is hidden within RSensibleSession)
+	if (!err)
+		{
+		err = ShareAuto();
+		}
+	if (!err)
+		{
+		TPckg<TUint32> enabledPkg(iEnabled);
+		TInt res = SendReceive(ESetTag, TIpcArgs(&aTag, NULL, &enabledPkg));
+		if (res >= 0)
+			{
+			iSequence = res;
+			}
+		else
+			{
+			err = res;
+			}
+		}
+	if (err)
+		{
+		Close();
+		}
+	return err;
+	}
+
+EXPORT_C TInt RClogger::StaticConnect()
+	{
+	return StaticConnect(KNullDesC);
+	}
+
+#ifndef PERFORMANCE_CRITICAL
+
+EXPORT_C TInt RClogger::StaticConnect(const TDesC& aTag)
+	{
+	GetTlsOrConnect(aTag);
+	if (clogger) return KErrNone;
+	else return err;
+	}
+
+EXPORT_C void RClogger::StaticClose()
+	{
+	GetTlsOrNull();
+	if (clogger)
+		{
+		clogger->Close();
+		if (!isHandle)
+			{
+			delete clogger;
+			}
+		Dll::SetTls(NULL);
+		Dll::FreeTls();
+		}
+	}
+
+#endif // PERFORMANCE_CRITICAL
+
+
+EXPORT_C void RClogger::Log(TRefByValue<const TDesC> aFmt, ...)
+	{
+	VA_LIST args;
+	VA_START(args, aFmt);
+	LogList(KNoLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Log(TUint32 aLogMask, TRefByValue<const TDesC> aFmt, ...)
+	{
+	VA_LIST args;
+	VA_START(args, aFmt);
+	LogList(aLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Log(TRefByValue<const TDesC8> aFmt, ...)
+	{
+	VA_LIST args;
+	VA_START(args, aFmt);
+	LogList(KNoLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Log(TUint32 aLogMask, TRefByValue<const TDesC8> aFmt, ...)
+	{
+	VA_LIST args;
+	VA_START(args, aFmt);
+	LogList(aLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Log(const char* aFmt, ...)
+	{
+	VA_LIST args;
+	VA_START(args, aFmt);
+	LogList(KNoLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Log(TUint32 aLogMask, const char* aFmt, ...)
+	{
+	VA_LIST args;
+	VA_START(args, aFmt);
+	LogList(aLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::LogList(TRefByValue<const TDesC> aFmt, VA_LIST aList)
+	{
+	LogList(KNoLogMask, aFmt, aList);
+	}
+
+EXPORT_C void RClogger::LogList(TUint32 aLogMask, TRefByValue<const TDesC> aFmt, VA_LIST aList)
+	{
+	if (!Enabled(aLogMask)) return;
+	TUint32 tickCount = User::NTickCount();
+
+	TPtrC fmt(aFmt);
+	if (iFlags & ETrimTrailingNewlines)
+		{
+		TInt len = fmt.Length();
+		if (len && fmt[len-1] == '\n') fmt.Set(fmt.Left(len-1));
+		len = fmt.Length();
+		if (len && fmt[len-1] == '\r') fmt.Set(fmt.Left(len-1));
+		}
+	#define SF_FORMAT fmt
+	#define SF_LIST aList
+	#define SF_BUF iBuf
+	#define SF_ACTION(buf) SendReceive(ELog8, TIpcArgs(&buf, tickCount, aLogMask))
+	#define SF_WIDE
+	#define SF_STACKONLY (!(iFlags & EUseHeapBuffer))
+	#include "SensibleFormat.h"
+
+	//if (!(iFlags&ECacheClientBuffers)) iBuf.Close();
+	}
+
+EXPORT_C void RClogger::LogList(TRefByValue<const TDesC8> aFmt, VA_LIST aList)
+	{
+	LogList(KNoLogMask, aFmt, aList);
+	}
+
+EXPORT_C void RClogger::LogList(TUint32 aLogMask, TRefByValue<const TDesC8> aFmt, VA_LIST aList)
+	{
+	if (!Enabled(aLogMask)) return;
+	TUint32 tickCount = User::NTickCount();
+
+	TPtrC8 fmt(aFmt);
+	if (iFlags & ETrimTrailingNewlines)
+		{
+		TInt len = fmt.Length();
+		if (len && fmt[len-1] == '\n') fmt.Set(fmt.Left(len-1));
+		len = fmt.Length();
+		if (len && fmt[len-1] == '\r') fmt.Set(fmt.Left(len-1));
+		}
+	#define SF_FORMAT fmt
+	#define SF_LIST aList
+	#define SF_BUF iBuf
+	#define SF_ACTION(buf) SendReceive(ELog8, TIpcArgs(&buf, tickCount, aLogMask))
+	#define SF_STACKONLY (!(iFlags & EUseHeapBuffer))
+	#include "SensibleFormat.h"
+
+	//if (!(iFlags&ECacheClientBuffers)) iBuf.Close();
+	}
+
+EXPORT_C void RClogger::LogList(const char* aFmt, VA_LIST aList)
+	{
+	TPtrC8 ptr((const TUint8*)aFmt);
+	LogList(KNoLogMask, ptr, aList);
+	}
+
+EXPORT_C void RClogger::LogList(TUint32 aLogMask, const char* aFmt, VA_LIST aList)
+	{
+	TPtrC8 ptr((const TUint8*)aFmt);
+	LogList(aLogMask, ptr, aList);
+	}
+
+#ifndef PERFORMANCE_CRITICAL
+
+EXPORT_C void RClogger::Slog(TUint32 aLogMask, TRefByValue<const TDesC> aFmt, ...)
+	{
+	CheckConnected();
+	VA_LIST args;
+	VA_START(args, aFmt);
+	clogger->LogList(aLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Slog(TUint32 aLogMask, TRefByValue<const TDesC8> aFmt, ...)
+	{
+	CheckConnected();
+	VA_LIST args;
+	VA_START(args, aFmt);
+	clogger->LogList(aLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Slog(TUint32 aLogMask, const char* aFmt, ...)
+	{
+	CheckConnected();
+	VA_LIST args;
+	VA_START(args, aFmt);
+	clogger->LogList(aLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Slog(TRefByValue<const TDesC> aFmt, ...)
+	{
+	CheckConnected();
+	VA_LIST args;
+	VA_START(args, aFmt);
+	clogger->LogList(KNoLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Slog(TRefByValue<const TDesC8> aFmt, ...)
+	{
+	CheckConnected();
+	VA_LIST args;
+	VA_START(args, aFmt);
+	clogger->LogList(KNoLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::Slog(const char* aFmt, ...)
+	{
+	CheckConnected();
+	VA_LIST args;
+	VA_START(args, aFmt);
+	clogger->LogList(KNoLogMask, aFmt, args);
+	VA_END(args);
+	}
+
+EXPORT_C void RClogger::SlogList(TUint32 aLogMask, TRefByValue<const TDesC> aFmt, VA_LIST aList)
+	{
+	CheckConnected();
+	clogger->LogList(aLogMask, aFmt, aList);
+	}
+
+EXPORT_C void RClogger::SlogList(TUint32 aLogMask, TRefByValue<const TDesC8> aFmt, VA_LIST aList)
+	{
+	CheckConnected();
+	clogger->LogList(aLogMask, aFmt, aList);
+	}
+
+EXPORT_C void RClogger::SlogList(TUint32 aLogMask, const char* aFmt, VA_LIST aList)
+	{
+	CheckConnected();
+	clogger->LogList(aLogMask, aFmt, aList);
+	}
+
+EXPORT_C void RClogger::SlogList(TRefByValue<const TDesC> aFmt, VA_LIST aList)
+	{
+	CheckConnected();
+	clogger->LogList(KNoLogMask, aFmt, aList);
+	}
+
+EXPORT_C void RClogger::SlogList(TRefByValue<const TDesC8> aFmt, VA_LIST aList)
+	{
+	CheckConnected();
+	clogger->LogList(KNoLogMask, aFmt, aList);
+	}
+
+EXPORT_C void RClogger::SlogList(const char* aFmt, VA_LIST aList)
+	{
+	CheckConnected();
+	clogger->LogList(KNoLogMask, aFmt, aList);
+	}
+
+EXPORT_C void RClogger::SetStaticLogBehaviour(TUint aLogBehaviour)
+	{
+	GetTlsOrConnect(KNullDesC);
+	if (isHandle && (aLogBehaviour != 0))
+		{
+		// Then we need to upgrade from handle to pointer
+		TInt err = KErrNoMemory;
+		RClogger* ptr = new RClogger();
+		if (ptr)
+			{
+			ptr->SetHandle(clogger->Handle());
+			err = Dll::SetTls(ptr);
+			if (err) delete ptr;
+			}
+		if (err)
+			{
+			// Then log it.
+			_LIT(KErr, "RClogger couldn't upgrade handle to pointer, err %i");
+			clogger->Log(KErr(), err);
+
+			aLogBehaviour = 0; // Don't update flags if we failed to honour them
+			}
+		else
+			{
+			clogger = ptr;
+			}
+		}
+
+	clogger->SetLogBehaviour(aLogBehaviour);
+	}
+
+#endif // PERFORMANCE_CRITICAL
+
+EXPORT_C void RClogger::SetLogBehaviour(TUint aLogBehaviour)
+	{
+	iFlags = (iFlags & ~KFlagsMask) | (aLogBehaviour & KFlagsMask);
+
+	if (!(iFlags & EUseHeapBuffer)) iBuf.Close();
+	
+	/* This is not needed any more
+	if (iFlags & EMonitorTagState)
+		{
+		iBody.StartCallbackDispatcher();
+		}
+	else
+		{
+		iBody.StopCallbackDispatcher();
+		}
+	*/
+	}
+
+EXPORT_C TInt RClogger::SetEnabled(const TDesC& aTag, TUint32 aEnabledMask)
+	{
+	return SendReceive(ESetEnabled, TIpcArgs(&aTag, aEnabledMask));
+	}
+
+EXPORT_C TUint32 RClogger::IsEnabled(const TDesC& aTag)
+	{
+	TPckgBuf<TUint32> logMask;
+	TInt res = SendReceive(EIsEnabled, TIpcArgs(&aTag, &logMask));
+	return res < 0 ? EFalse : logMask();
+	}
+
+/*
+EXPORT_C void RClogger::TailLogFile(TInt aNumberOfChars)
+	{
+	SendReceive(ETailLogToRDebug, TIpcArgs(aNumberOfChars));
+	}
+
+EXPORT_C void RClogger::TailLogFile(TDes8& aBuf)
+	{
+	SendReceive(ETailLogToBuf, TIpcArgs(&aBuf));
+	}
+*/
+
+EXPORT_C void RClogger::SetGlobalOptions(TUint aGlobalOptions)
+	{
+	SendReceive(ESetGlobalOptions, TIpcArgs(aGlobalOptions));
+	}
+
+EXPORT_C TUint RClogger::GetGlobalOptions()
+	{
+	return SendReceive(EGetGlobalOptions, TIpcArgs());
+	}
+
+EXPORT_C TInt RClogger::GetRamBufferSize(TInt* aNumberOfBuffers)
+	{
+	TBuf8<8> buf;
+	buf.SetLength(8);
+	SendReceive(EGetRamBufferSize, TIpcArgs(&buf));
+	TInt* ptr = (TInt*)buf.Ptr();
+	TInt size = ptr[0];
+	if (aNumberOfBuffers)
+		{
+		*aNumberOfBuffers = ptr[1];
+		}
+	return size;
+	}
+
+EXPORT_C void RClogger::SetRamBufferSize(TInt aSize, TInt aNum)
+	{
+	SendReceive(ESetRamBufferSize, TIpcArgs(aSize, aNum));
+	}
+
+EXPORT_C TInt RClogger::Rotate()
+	{
+	return SendReceive(ERotate, TIpcArgs());
+	}
+
+EXPORT_C TInt RClogger::Rotate(TDes& aFileName)
+	{
+	aFileName.Zero();
+	return SendReceive(ERotate, TIpcArgs(&aFileName));
+	}
+
+EXPORT_C void RClogger::SetRotateBehaviour(TInt aNumberOfOldLogsToKeep, TUint aRotateBehaviour)
+	{
+	SendReceive(ESetRotateBehaviour, TIpcArgs(aNumberOfOldLogsToKeep, aRotateBehaviour));
+	}
+
+EXPORT_C TUint RClogger::GetRotateBehaviour(TInt* aNumberOfOldLogsToKeep)
+	{
+	TBuf8<8> buf;
+	buf.SetLength(8);
+	SendReceive(EGetRotateBehaviour, TIpcArgs(&buf));
+	TInt* ptr = (TInt*)buf.Ptr();
+	TUint behav = ptr[0];
+	if (aNumberOfOldLogsToKeep)
+		{
+		*aNumberOfOldLogsToKeep = ptr[1];
+		}
+	return behav;
+	}
+
+EXPORT_C void RClogger::PersistSettings()
+	{
+	SendReceive(EPersistSettings, TIpcArgs());
+	}
+
+EXPORT_C void RClogger::ResetSettings()
+	{
+	SendReceive(EResetSettings, TIpcArgs());
+	}
+
+EXPORT_C void RClogger::Close()
+	{
+	iBuf.Close();
+	iBody.Close();
+	RSessionBase::Close();
+	}
+
+void RCloggerBody::DispatchCallbackL(TServerCallback& aCallback, TCallbackParser& aParser)
+	{
+	switch (aCallback.iCode)
+		{
+		case ETagEnabledChanged:
+			{
+			iSession.iEnabled = aParser.NextUint();
+
+			/*
+			if (iSession.iFlags & KTestTagEnabled)
+				{
+				iSession.iFlags &= ~KTestTagEnabled;
+				CActiveScheduler::Stop();
+				}
+			*/
+			break;
+			}
+		}
+	}
+
+void RCloggerBody::ServerDiedL()
+	{
+	}
+
+EXPORT_C void RClogger::GetTagStatesL(CDesCArray*& aTagNames, RBuf8& aEnabled)
+	{
+	aTagNames = NULL;
+	aEnabled.Close();
+
+	TServerCallback cb;
+	TPckg<TServerCallback> cbPkg(cb);
+	User::LeaveIfError(SendReceive(EGetTagStates1, TIpcArgs(&cbPkg)));
+	
+	RBuf8 context;
+	CleanupClosePushL(context);
+	if (cb.iContextLength)
+		{
+		context.CreateL(cb.iContextLength);
+		User::LeaveIfError(SendReceive(EGetTagStates2, TIpcArgs(&context)));
+		}
+	TCallbackParser parser(cb);
+	parser.SetContext(context);
+
+	TPtrC8 enabledBuf = parser.NextDesC8();
+	TInt numTags = enabledBuf.Length() / 4; // 32 bits per tag
+
+	CDesCArrayFlat* tags = new(ELeave) CDesCArrayFlat(numTags);
+	CleanupStack::PushL(tags);
+	while (numTags--)
+		{
+		tags->AppendL(parser.NextDesC());
+		}
+	
+	aEnabled.CreateL(enabledBuf);
+	CleanupStack::Pop(tags);
+	CleanupStack::PopAndDestroy(&context);
+	aTagNames = tags;
+	}
+
+EXPORT_C void RClogger::SetTagStatesL(const CDesCArray* aTagNames, const TDesC8& aEnabled)
+	{
+	__ASSERT_ALWAYS(aTagNames, User::Leave(KErrArgument));
+	TInt count = aTagNames->MdcaCount();
+	__ASSERT_ALWAYS(count * 4 == aEnabled.Size(), User::Leave(KErrArgument)); // Number of tags must equal the number of 4-byte entries in aEnabled
+
+	CBufFlat* buf = CBufFlat::NewL(4096);
+	CleanupStack::PushL(buf);
+	RBufWriteStream stream(*buf);
+	CleanupClosePushL(stream);
+	stream.WriteInt32L(count);
+	//stream.WriteL(aEnabled);
+	stream << aEnabled;
+	for (TInt i = 0; i < count; i++)
+		{
+		const TPtrC name = aTagNames->MdcaPoint(i);
+		stream << name;
+		}
+	CleanupStack::PopAndDestroy(&stream); // Calls close, flushes buffer (probably not necessary with a RBufWriteStream)
+	TPtrC8 bufPtr = buf->Ptr(0);
+	User::LeaveIfError(SendReceive(ESetTagStates, TIpcArgs(&bufPtr)));
+	CleanupStack::PopAndDestroy(buf);
+	}
+
+EXPORT_C TInt RClogger::Reserved(TInt aCode, TAny*& aArg, TAny* aArg2)
+	{
+	TInt res = KErrNone;
+	if (aCode == 0xF10C10)
+		{
+		res = iBody.Connect(2, EFalse); // Used by flogger shim to access internals of clogger that would otherwise be hidden to it
+		}
+	else if (aCode == 0xC0FFEE)
+		{
+		RChunk*& chunk = reinterpret_cast<RChunk*&>(aArg);
+		TInt size = reinterpret_cast<TInt>(aArg2);
+		res = SendReceive(ECreatePerformanceLoggingChunk, TIpcArgs(size));
+		if (res > 0)
+			{
+			chunk->SetHandle(res);
+			res = KErrNone;
+			}
+		if (res == KErrNotSupported)
+			{
+			// Getting the chunk from the server is only possible if the debug router LDD is included, because there's no API
+			// to pass a chunk from a server to a client (without doing it kernel side). So if the LDD isn't present, we need
+			// to fall back to constructing it on our side and passing it to the server.
+			res = chunk->CreateGlobal(KNullDesC, size, size);
+			if (res == KErrNone)
+				{
+				res = SendReceive(ERegisterPerformanceLoggingChunk, TIpcArgs(*chunk));
+				}
+			}
+		}
+	else if (aCode == 0x5e55)
+		{
+		res = SendReceive(EStartSessionWriterServer);
+		}
+	else
+		{
+		User::Panic(_L("CloggerClient"), 0);
+		}
+	return res;
+	}
+
+EXPORT_C TInt RClogger::StaticReserved(TInt aCode, TAny*& aArg, TAny* aArg2)
+	{
+	TInt res = KErrNone;
+	if (aCode == 0xD0715)
+		{
+		RClogger clogger;
+		res = clogger.Connect(*reinterpret_cast<const TDesC*>(aArg2));
+		if (res == KErrNone)
+			{
+			aArg = reinterpret_cast<TAny*>(clogger.Handle());
+			}
+		}
+	else
+		{
+		User::Panic(_L("CloggerClient"), 0);
+		}
+	return res;
+	}
+
+EXPORT_C void RClogger::HexDump(TUint32 aLogMask, const TDesC8& aHeader, const TDesC8& aData)
+	{
+	if (!(iEnabled & aLogMask)) return;
+
+	SendReceive(EHexDump, TIpcArgs(&aHeader, &aData, User::NTickCount(), aLogMask));
+	}
+
+EXPORT_C void RClogger::HexDump(const TDesC8& aHeader, const TDesC8& aData)
+	{
+	HexDump(KNoLogMask, aHeader, aData);
+	}
+
+#ifndef PERFORMANCE_CRITICAL
+
+EXPORT_C void RClogger::StaticHexDump(TUint32 aLogMask, const TDesC8& aHeader, const TDesC8& aData)
+	{
+	CheckConnected();
+	clogger->HexDump(aLogMask, aHeader, aData);
+	}
+
+EXPORT_C void RClogger::StaticHexDump(const TDesC8& aHeader, const TDesC8& aData)
+	{
+	CheckConnected();
+	clogger->HexDump(KNoLogMask, aHeader, aData);
+	}
+
+#endif // PERFORMANCE_CRITICAL
+
+inline TBool RClogger::Enabled(TUint32 aMask)
+	{
+	// First check if anything's changed 
+	TInt seq = 0;
+	TInt err = RProperty::Get(KCloggerUid, ESequenceNumber, seq);
+	if (err == KErrNone && seq > iSequence)
+		{
+		UpdateEnabled(seq);
+		}
+
+	if (!(iEnabled & aMask)) return EFalse;
+
+	return ETrue;
+	}
+
+void RClogger::UpdateEnabled(TInt aSequence)
+	{
+	iSequence = aSequence;
+	TPckg<TUint32> buf(iEnabled);
+	SendReceive(EUpdateEnabledMask, TIpcArgs(&buf));
+	iFlags &= ~KTestTagEnabled;
+	}
+
+EXPORT_C RCloggerLogConsumer::RCloggerLogConsumer()
+	: iResultBufferPtr(NULL, 0)
+	{
+	}
+
+EXPORT_C TInt RCloggerLogConsumer::Connect()
+	{
+	RClogger clogger;
+	TInt res = clogger.Connect();
+	if (res) return res;
+
+	TAny* arg1 = NULL;
+	res = clogger.Reserved(0x5E55, arg1, NULL); // This requests clogger to start the session writer server
+	clogger.Close();
+	if (res != KErrNone && res != KErrAlreadyExists)
+		{
+		return res;
+		}
+
+	res = CreateSession(KSessionLogServer, TVersion(0,0,0), 2);
+	if (res) return res;
+
+	res = SendReceive(ERegisterForLogMessages);
+	if (res < 0) return res;
+	iSharedChunk.SetHandle(res);
+	return KErrNone;
+	}
+
+EXPORT_C void RCloggerLogConsumer::GetNextLog(TRequestStatus& aStatus, TPtrC8& aResultBuffer)
+	{
+	// Server will update aResultBuffer to point to the appropriate location in iSharedChunk.
+	// It can do this because we pass in effectively TPckg<TPtrC8>(aResultBuffer) and tell the server
+	// what the shared chunk's Base address is in our address space. The server then computes what
+	// aResultBuffer should look like and writes it back
+	iResultBufferPtr.Set((TUint8*)&aResultBuffer, sizeof(TPtrC8), sizeof(TPtrC8));
+	SendReceive(EGetNextLog, TIpcArgs(&iResultBufferPtr, iSharedChunk.Base()), aStatus);
+	}
+
+EXPORT_C void RCloggerLogConsumer::CancelGetNextLog()
+	{
+	SendReceive(ECancelGetNextLog);
+	}
+
+EXPORT_C void RCloggerLogConsumer::Close()
+	{
+	iSharedChunk.Close();
+	RSessionBase::Close();
+	}
+
+EXPORT_C void Clogger_Slog(const char* aFmt, ...)
+	{
+	VA_LIST list;
+	VA_START(list, aFmt);
+	TPtrC8 fmt((const TUint8*)aFmt);
+	RClogger::SlogList(fmt, list);
+	VA_END(list);
+	}