First submission to Symbian Foundation staging server.
// 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);
}