libraries/clogger/src/CloggerClient.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.

// 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);
	}