libraries/clogger/src/CloggerServer.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // CloggerServer.cpp
       
     2 // 
       
     3 // Copyright (c) 2006 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include "CloggerServer.h"
       
    14 #include "Clogger.h"
       
    15 #include "cliserv.h"
       
    16 #include "common.h"
       
    17 #include <HAL.h>
       
    18 #include <centralrepository.h>
       
    19 #include <s32mem.h>
       
    20 #include "SessionWriter.h"
       
    21 #include <fshell/common.mmh>
       
    22 
       
    23 #define ClientPanic(aMsg) PanicClient(aMsg, __LINE__)
       
    24 static const TUint32 KAllEnabled = 0xFFFFFFFFu;
       
    25 
       
    26 enum TFlags {
       
    27 	EAllowCurrentBufferToBeRead,
       
    28 	EInMiddleOfLog, // so don't call Log again, you'll stamp all over the buffers! This is a debug check to guard against my carelessness, ie calling something from within Log() that tries to call Log() again. Log() is not reenterant!
       
    29 	ELogBufferOverflow, // Can't log when the overflow occurs, so remember it until the log is in an ok state to record the fact
       
    30 	EWrittenToLog, // This indicates we have got far enough through construction to have written stuff to the buffers. This is an explicit flag to guard against future changes to the startup ordering
       
    31 	ECenrepFailed, // Can't log when cenrep is accessed, so remember for when we can log it
       
    32 	ENeedToCopyCompressedLog, // Indicates we need to call CopyLogToExternalMediaL when the background compress of the log completes
       
    33 	EForceBreakpoint, // Forces a __DEBUGGER call at the start of DoServiceL(). Useful when debugging tclog
       
    34 	EUsingTempBuf, // Another check to make sure I don't do something stupid with my buffers
       
    35 	EMaxFlags
       
    36 };
       
    37 
       
    38 __ASSERT_COMPILE(EMaxFlags <= 32);
       
    39 
       
    40 #define ACQUIRE_FLAG_LOCK_OR_FAIL(aFlag, failureOperation) \
       
    41 	ASSERT(!iFlags.IsSet(aFlag)); /* Debug behaviour */ \
       
    42 	if (iFlags.IsSet(aFlag)) { failureOperation; } /* Non debug behaviour - fail gracefully */ \
       
    43 	iFlags.Set(aFlag);
       
    44 #define ACQUIRE_FLAG_LOCK(aFlag) ACQUIRE_FLAG_LOCK_OR_FAIL(aFlag, return)
       
    45 #define RELEASE_FLAG_LOCK(aFlag) iFlags.Clear(aFlag)
       
    46 
       
    47 enum TInternalLoggingMasks {
       
    48 	ELogTagChanges = 1,
       
    49 	ELogNewTags = 2,
       
    50 	ELogDisks = 4,
       
    51 	ELogNewRdebuggers = 8,
       
    52 	};
       
    53 
       
    54 enum TRDebugPrintMasks {
       
    55 	ELogRDebugPrint = 1,
       
    56 	ELogKernPrintf = 2,
       
    57 	ELogPlatSecDiagnostics = 4,
       
    58 	};
       
    59 
       
    60 _LIT8(KCloggerTag, "Clogger");
       
    61 _LIT8(KOldRDebugTag, "RDebug::Print");
       
    62 _LIT8(KRDebugTag, "RDebug");
       
    63 _LIT8(KKernPrintfTag, "Kern::Printf"); // Not used any more - keep the definition because we explicitly ignore it when loading tags from cenrep
       
    64 _LIT8(KOldFallbackTag, "**Everything else**");
       
    65 _LIT8(KFallbackTag, "DefaultForNewTags");
       
    66 _LIT(KLogDir, "\\logs\\"); // Don't include the C: because that would upset moap. Rely on RFs to default to the system drive
       
    67 _LIT(KLogFile, "clogger.txt");
       
    68 
       
    69 // Don't reorder these without also changing order they are constructed in CCloggerServer::ConstructL
       
    70 enum TWriters {
       
    71 	EFile = 0,
       
    72 	ERDebug,
       
    73 	EMessageQueue,
       
    74 	ESessionWriter,
       
    75 	// Add new writers here!
       
    76 	EMaxWriters
       
    77 	};
       
    78 
       
    79 enum TCenRep {
       
    80 	EGlobalOptions = 0,
       
    81 	EBufferSize,
       
    82 	ENumBuffers,
       
    83 	ENumRotates,
       
    84 	ERotateBehaviour,
       
    85 	EEnabledTags, // This is obsolete because we now use the partial key functionality of cenrep to store enabled tags. And that was necessary because cenrep limits binary values to 2048 bytes
       
    86 	ERepositoryVersion,
       
    87 	};
       
    88 
       
    89 // Cenrep constants
       
    90 const TUint32 KEverythingMask = 0xFF000000;
       
    91 const TUint32 KEverythingPartialKey = 0x80000000;
       
    92 const TUint32 KEnabledMask = 0xFF000001;
       
    93 const TUint32 KTagEnabledPartialKey = 0x80000000;
       
    94 enum TCenrepVersion
       
    95 	{
       
    96 	ECenrepOriginalFormat = 0,
       
    97 	ECenrepThreadNamesArePrettified = 1,
       
    98 	};
       
    99 
       
   100 const TInt KMinWriteSize = 512; // 512 bytes is a good minimum size for efficient writes to disk
       
   101 const TInt KSyncBufferIdx = -99; // Magic number given by the server to writers to mean 'the sync buffer'
       
   102 const TInt KCompressFileNameBufferIdx = -100; // Magic number given by the server to the compress sync writer, its meaning is internal to CLogCompressor and CCloggerServer
       
   103 
       
   104 /*
       
   105 Clogger AOs:
       
   106 
       
   107 EPriorityHigh + 1:
       
   108 CBtIncomingPrompt Starter - This shouldn't get starved because of writers
       
   109 
       
   110 EPriorityHigh:
       
   111 CLogWriter - emptying buffers
       
   112 CSyncWriterWrapper - emptying buffers
       
   113 CLogsDirWatcher - will never be running at same time as CLogWriter
       
   114 CSessionWriterServer - emptying buffers
       
   115 
       
   116 EPriorityStandard + 1:
       
   117 CDebugRouterClient - reads input from RDdebug::Print redirector
       
   118 
       
   119 EPriorityStandard:
       
   120 CCloggerServer
       
   121 CServerCallbackDispatcher - unused
       
   122 
       
   123 EPriorityLow:
       
   124 iIdleWriteTimer - only go to next buffer when nothing better to do
       
   125 */
       
   126 
       
   127 
       
   128 class CLogsDirWatcher : public CActive
       
   129 	{
       
   130 public:
       
   131 	CLogsDirWatcher(RFs& aFs, CCloggerServer& aServer)
       
   132 		: CActive(EPriorityHigh), iFs(aFs), iServer(aServer)
       
   133 		, iDirToWatch(KLogDir().Left(KLogDir().Length()-1)) // Strip trailing backslash
       
   134 		{
       
   135 
       
   136 		CActiveScheduler::Add(this);	
       
   137 		//__DEBUGGER();
       
   138 		iFs.NotifyChange(ENotifyAll, iStatus, iDirToWatch);
       
   139 		SetActive();
       
   140 		}
       
   141 
       
   142 	void DoCancel()
       
   143 		{
       
   144 		iFs.NotifyChangeCancel();
       
   145 		}
       
   146 
       
   147 	~CLogsDirWatcher()
       
   148 		{
       
   149 		Cancel();
       
   150 		}
       
   151 
       
   152 	void RunL()
       
   153 		{
       
   154 		//__DEBUGGER();
       
   155 		if (iStatus != KErrNone) return; // Give up
       
   156 		TEntry entry;
       
   157 		if (iFs.Entry(KLogDir, entry) == KErrNone)
       
   158 			{
       
   159 			iServer.LogsDirHasBeenCreated();
       
   160 			}
       
   161 		else
       
   162 			{
       
   163 			// Keep listening
       
   164 			iFs.NotifyChange(ENotifyAll, iStatus, iDirToWatch);
       
   165 			SetActive();
       
   166 			}	
       
   167 		}
       
   168 
       
   169 private:
       
   170 	RFs& iFs;
       
   171 	CCloggerServer& iServer;
       
   172 	TPtrC iDirToWatch;
       
   173 	};
       
   174 
       
   175 CSession2* CCloggerServer::NewSessionL(const TVersion& /*aVersion*/, const RMessage2& /*aMessage*/) const
       
   176 	{
       
   177 	return new(ELeave) CCloggerSession();
       
   178 	}
       
   179 
       
   180 CCloggerServer::CCloggerServer()
       
   181 : CSensibleServer()
       
   182 	{
       
   183 	}
       
   184 
       
   185 TInt CCloggerServer::TransientServerShutdownTime() const
       
   186 	{
       
   187 	return 0; // Never shutdown
       
   188 	}
       
   189 
       
   190 CCloggerServer::~CCloggerServer()
       
   191 	{
       
   192 	//__DEBUGGER();
       
   193 	if (iFlags.IsSet(EWrittenToLog)) FlushBuffers();
       
   194 	CloseBuffers();
       
   195 	iBufs.Close();
       
   196 	iChunkForBufs.Close();
       
   197 
       
   198 	for (TInt i = 0; i < iWriters.Count(); i++)
       
   199 		{
       
   200 		iWriters[i]->CloseWriter();
       
   201 		}
       
   202 	iWriters.Close();
       
   203 	delete iSessionWriterServer;
       
   204 
       
   205 	if (iCompressor)
       
   206 		{
       
   207 		iCompressor->Cancel(); // This will wait for the compress to complete. Safest thing to do
       
   208 		delete iCompressor;
       
   209 		}
       
   210 
       
   211 	delete iLogsDirWatcher;
       
   212 	iLogFile.Close();
       
   213 	iFs.Close();
       
   214 	//iFileBeingRotated.Close();
       
   215 
       
   216 	TPtrHashMapIter<TDesC8, TTagData> tagIter(iTags);
       
   217 	TTagData* tag;
       
   218 	while ((tag = const_cast<TTagData*>(tagIter.NextValue())) != NULL)
       
   219 		{
       
   220 		tagIter.RemoveCurrent();
       
   221 		delete tag->iTagName;
       
   222 		delete tag;
       
   223 		}
       
   224 	iTags.Close();
       
   225 	iTempBuf.Close();
       
   226 	iSessionTempBuf.Close();
       
   227 	iRDebugTags.Close();
       
   228 
       
   229 	delete iIdleWriteTimer;
       
   230 	ASSERT(!iFlushBufferWait.IsStarted());
       
   231 	delete iKernDebugRouter; // When should this be deleted?
       
   232 	}
       
   233 
       
   234 void CCloggerServer::ConstructL()
       
   235 	{
       
   236 	CSensibleServer::ConstructL();
       
   237 	GetSettingsL();
       
   238 
       
   239 	iWriters.ReserveL(EMaxWriters);
       
   240 	// Note: important to get the order of writers in the array to be the same as is defined in enum TWriters
       
   241 	CLogWriter* filelogger = new(ELeave) CLogWriter(*this, iLogFile);
       
   242 	filelogger->SetEnabled(ETrue);
       
   243 	iWriters.Append(filelogger);
       
   244 	
       
   245 	CRDebugWriter* rdebuglogger = new(ELeave) CRDebugWriter(*this);
       
   246 	CleanupStack::PushL(rdebuglogger);
       
   247 	CSyncWriterWrapper* rdebugWrapper = CSyncWriterWrapper::NewL(*this, *rdebuglogger, iWriters.Count());
       
   248 	CleanupStack::Pop(rdebuglogger);
       
   249 	rdebugWrapper->SetEnabled(EFalse);
       
   250 	iWriters.Append(rdebugWrapper);
       
   251 
       
   252 	CMessageQueueWriter* msgq = CMessageQueueWriter::NewL();
       
   253 	CleanupStack::PushL(msgq);
       
   254 	CSyncWriterWrapper* msgqWrapper = CSyncWriterWrapper::NewL(*this, *msgq, iWriters.Count());
       
   255 	CleanupStack::Pop(msgq);
       
   256 	rdebugWrapper->SetEnabled(EFalse);
       
   257 	iWriters.Append(msgqWrapper);
       
   258 
       
   259 	CSessionWriter* sessionWriter = new(ELeave) CSessionWriter(*this);
       
   260 	sessionWriter->SetEnabled(EFalse);
       
   261 	iWriters.Append(sessionWriter);
       
   262 
       
   263 	User::LeaveIfError(iFs.Connect());
       
   264 	User::LeaveIfError(iFs.SetSessionPath(KLogDir));
       
   265 
       
   266 	TInt err = OpenLogFile();
       
   267 	if (err == KErrPathNotFound)
       
   268 		{
       
   269 		err = KErrNone;
       
   270 		iLogsDirWatcher = new(ELeave) CLogsDirWatcher(iFs, *this);
       
   271 		}
       
   272 	User::LeaveIfError(err);
       
   273 	/*TInt err = iLogFile.Open(iFs, KLogFile, EFileWrite|EFileShareAny|EFileStream);
       
   274 	if (err == KErrNotFound) err = iLogFile.Create(iFs, KLogFile, EFileWrite|EFileShareAny|EFileStream);
       
   275 	if (err == KErrPathNotFound)
       
   276 		{
       
   277 		iWriters[EFile]->SetEnabled(EFalse);
       
   278 		err = KErrNone;
       
   279 		iLogsDirWatcher = new(ELeave) CLogsDirWatcher(iFs, *this);
       
   280 		}
       
   281 	else
       
   282 		{
       
   283 		User::LeaveIfError(err);
       
   284 		TInt seekTo = -1;
       
   285 		User::LeaveIfError(iLogFile.Seek(ESeekEnd, seekTo));
       
   286 		}
       
   287 	*/
       
   288 	iIdleWriteTimer = CPeriodic::NewL(CActive::EPriorityLow);
       
   289 	
       
   290 	// Important that we start the kern debug router early, before the first call to UpdateBufferSizeL because we now rely on the debug router to allocate our chunk for us
       
   291 	TRAPD(debugRouterErr, iKernDebugRouter = CDebugRouterClient::NewL(*this)); // We check 'debugRouterErr' further down
       
   292 	const TInt KMaxChunkSize = 512*1024; // We will say 512 KB for max chunk size
       
   293 	err = CreateKernChunkForClient(NULL, KMaxChunkSize, 0, iChunkForBufs);
       
   294 	if (err == KErrNotSupported)
       
   295 		{
       
   296 		// Then debug router not found - so just create a chunk ourselves
       
   297 		_LIT(KName, "CloggerBufferChunk");
       
   298 		err = iChunkForBufs.CreateGlobal(KName, 0, KMaxChunkSize);
       
   299 		}
       
   300 	User::LeaveIfError(err);
       
   301 
       
   302 	UpdateBufferSizeL(iBufferSize, iNumBuffers);
       
   303 	iTempBuf.CreateL(512);
       
   304 	iSessionTempBuf.CreateL(512);
       
   305 
       
   306 	// The mechanism to compress log files in the background is a special case of a CSyncWriterWrapper
       
   307 	CLogCompressor* compressor = CLogCompressor::NewLC(*this);
       
   308 	iCompressor = CSyncWriterWrapper::NewL(*this, *compressor, -1);
       
   309 	CleanupStack::Pop(compressor);
       
   310 	iCompressor->SetEnabled(ETrue); // Otherwise CSyncWriterWrapper will ignore our requests to compress things!
       
   311 
       
   312 	iTags.ReserveL(32);
       
   313 	// Construct some tags that always exist
       
   314 	iCloggerTag = iTags.Find(KCloggerTag);
       
   315 	if (!iCloggerTag)
       
   316 		{
       
   317 		HBufC8* tag = KCloggerTag().AllocLC();
       
   318 		iCloggerTag = reinterpret_cast<TTagData*>(NewSessionForTagL(tag));
       
   319 		iCloggerTag->SetShouldDisplay();
       
   320 		iCloggerTag->iEnabled = ELogNewRdebuggers; // Defaults to off, except for logging new rdebuggers - because you generally want to be able to see the thread name
       
   321 		CleanupStack::Pop(tag);
       
   322 		}
       
   323 	iRDebugTag = iTags.Find(KRDebugTag);
       
   324 	if (!iRDebugTag)
       
   325 		{
       
   326 		HBufC8* tag = KRDebugTag().AllocLC();
       
   327 		iRDebugTag = reinterpret_cast<TTagData*>(NewSessionForTagL(tag));
       
   328 		// Should not be shown unless used, so don't SetShouldDisplay
       
   329 		CleanupStack::Pop(tag);
       
   330 		}
       
   331 	iFallbackTag = iTags.Find(KFallbackTag);
       
   332 	if (!iFallbackTag)
       
   333 		{
       
   334 		HBufC8* tag = KFallbackTag().AllocLC();
       
   335 		iFallbackTag = reinterpret_cast<TTagData*>(NewSessionForTagL(tag));
       
   336 		iFallbackTag->SetShouldDisplay();
       
   337 		CleanupStack::Pop(tag);
       
   338 		}
       
   339 
       
   340 	TUint32 tickCount = User::NTickCount();
       
   341 	iTimeAtStartup.UniversalTime();
       
   342 	TInt tickPeriod;
       
   343 	//User::LeaveIfError(HAL::Get(HAL::EFastCounterFrequency, iTickFreq));
       
   344 	User::LeaveIfError(HAL::Get(HAL::ENanoTickPeriod, tickPeriod));
       
   345 	iTickFreq = 1000000 / tickPeriod; // We work in frequencies because they are the round numbers when using the fast counter, and at some point we might want to again
       
   346 
       
   347 	iStartupTickInMicroseconds = ((TInt64)tickCount * 1000000) / (TInt64)iTickFreq; // Just making damn sure we're using 64bit math
       
   348 
       
   349 	// Rotate uses the tick stuff so must come after it
       
   350 	if (iRotateBehaviour & RClogger::EAutoRotateAtStartup)
       
   351 		{
       
   352 		Rotate();
       
   353 		}
       
   354 
       
   355 	UpdatedGlobalOptionsL(iOptions & RClogger::EBufferLog); // Passing in the current value of EBufferLog means we don't trigger another UpdateBufferSizeL, which is good because we've explicitly called that earlier on in this function
       
   356 
       
   357 	iFlags.Set(EWrittenToLog);
       
   358 
       
   359 	_LIT8(KCrLf, "\r\n");
       
   360 	_LIT8(KStarted, "Server started (log format v4)");
       
   361 	// Format v1 used incorrect time stamps, v2 fixed that, v3 indicates that the buffer info is published via P&S
       
   362 	// v4 scraps P&S and uses the kern debug router to map the buffers into the crashlog
       
   363 
       
   364 	LogLine(KCrLf);
       
   365 	Log(NULL, KStarted, User::NTickCount());
       
   366 	if (iFlags.IsSet(ECenrepFailed))
       
   367 		{
       
   368 		_LIT8(KCenrep, "Couldn't access the cenrep repository.");
       
   369 		LogError(KCenrep);
       
   370 		}
       
   371 	if (debugRouterErr)
       
   372 		{
       
   373 		_LIT8(KDebugRouterFailed, "Failed to load the debug router LDD, err=%i.");
       
   374 		LogError(KDebugRouterFailed, debugRouterErr);
       
   375 		}
       
   376 
       
   377 	_LIT_SECURITY_POLICY_PASS(KRead);
       
   378 	_LIT_SECURITY_POLICY_S0(KWrite, KCloggerUid.iUid);
       
   379 
       
   380 	RProperty::Define(KCloggerUid, ESequenceNumber, RProperty::EInt, KRead, KWrite);
       
   381 	RProperty::Set(KCloggerUid, ESequenceNumber, iEnabledStatesSequenceNumber);
       
   382 	}
       
   383 
       
   384 void CCloggerServer::GetSettingsL()
       
   385 	{
       
   386 	TRAPD(err, DoGetSettingsL());
       
   387 	// Don't allow messed-up cenrep config to prevent us from launching
       
   388 
       
   389 	if (err)
       
   390 		{
       
   391 		iBufferSize = 4096;
       
   392 		iNumBuffers = 2;
       
   393 		iNumRotates = 4;
       
   394 		iFlags.Set(ECenrepFailed);
       
   395 		}
       
   396 	}
       
   397 
       
   398 void CCloggerServer::DoGetSettingsL()
       
   399 	{
       
   400 	CRepository* cenrep = CRepository::NewLC(KCloggerUid);
       
   401 	User::LeaveIfError(cenrep->Get(EGlobalOptions, (TInt&)iOptions));
       
   402 	User::LeaveIfError(cenrep->Get(EBufferSize, iBufferSize));
       
   403 	User::LeaveIfError(cenrep->Get(ENumBuffers, iNumBuffers));
       
   404 	User::LeaveIfError(cenrep->Get(ENumRotates, iNumRotates));
       
   405 	User::LeaveIfError(cenrep->Get(ERotateBehaviour, (TInt&)iRotateBehaviour));
       
   406 	TInt version = 0;
       
   407 	TBool needToPrettifyThreadNames = EFalse;
       
   408 	TInt err = cenrep->Get(ERepositoryVersion, version);
       
   409 	if (err || version < ECenrepThreadNamesArePrettified)
       
   410 		{
       
   411 		needToPrettifyThreadNames = ETrue;
       
   412 		}
       
   413 
       
   414 	RArray<TUint32> foundKeys;
       
   415 	CleanupClosePushL(foundKeys);
       
   416 	err = cenrep->FindL(KTagEnabledPartialKey, KEnabledMask, foundKeys);
       
   417 	if (err == KErrNone)
       
   418 		{
       
   419 		TInt n = foundKeys.Count();
       
   420 		TBuf8<1> dummyBuf;
       
   421 		for (TInt i = 0; i < n; i++)
       
   422 			{
       
   423 			TUint32 enabled;
       
   424 			User::LeaveIfError(cenrep->Get(foundKeys[i], (TInt&)enabled));
       
   425 			TInt len;
       
   426 			HBufC8* tagName = NULL;
       
   427 			TInt err = cenrep->Get(foundKeys[i]+1, dummyBuf, len);
       
   428 			if (err == KErrNone)
       
   429 				{
       
   430 				tagName = dummyBuf.AllocLC();
       
   431 				}
       
   432 			else if (err == KErrOverflow)
       
   433 				{
       
   434 				tagName = HBufC8::NewLC(len);
       
   435 				}
       
   436 			else
       
   437 				{
       
   438 				User::LeaveIfError(err);
       
   439 				}
       
   440 			TPtr8 ptr = tagName->Des();
       
   441 			User::LeaveIfError(cenrep->Get(foundKeys[i]+1, ptr, len));
       
   442 			if (needToPrettifyThreadNames)
       
   443 				{
       
   444 				ThreadPrettyName(ptr);
       
   445 				}
       
   446 
       
   447 			if (*tagName == KKernPrintfTag)
       
   448 				{
       
   449 				// We don't use this any more
       
   450 				CleanupStack::PopAndDestroy(tagName);
       
   451 				continue;
       
   452 				}
       
   453 			else if (*tagName == KOldFallbackTag)
       
   454 				{
       
   455 				// In case the old definition is kicking round in a cenrep file
       
   456 				*tagName = KFallbackTag;
       
   457 				}
       
   458 			else if (*tagName == KOldRDebugTag)
       
   459 				{
       
   460 				// We've renamed this too
       
   461 				*tagName = KRDebugTag;
       
   462 				}
       
   463 
       
   464 			TTagData* tagData = iTags.Find(*tagName);
       
   465 			if (tagData)
       
   466 				{
       
   467 				// tagName is not needed
       
   468 				CleanupStack::PopAndDestroy(tagName);
       
   469 				}
       
   470 			else
       
   471 				{
       
   472 				tagData = new(ELeave)TTagData(tagName);
       
   473 				if (*tagName == KRDebugTag)
       
   474 					{
       
   475 					// We don't want this tag to show up unless we've actually used it, since it's only used for last-ditch OOM logging (this is to minimise confusion about which tags are used for what)
       
   476 					}
       
   477 				else
       
   478 					{
       
   479 					tagData->SetShouldDisplay(); // If the tag comes from cenrep then we should show it
       
   480 					}
       
   481 				CleanupStack::PushL(tagData);
       
   482 				iTags.InsertL(tagName, tagData);
       
   483 				CleanupStack::Pop(tagData);
       
   484 				CleanupStack::Pop(tagName);
       
   485 				}
       
   486 			tagData->iEnabled = enabled;
       
   487 			}
       
   488 		}
       
   489 	CleanupStack::PopAndDestroy(&foundKeys);
       
   490 
       
   491 	/*
       
   492 	TInt descSize = 0;
       
   493 	TBuf8<1> dummyBuf; // Don't bother trying to succeed without knowing the buffer size
       
   494 	TInt err = cenrep->Get(EEnabledTags, dummyBuf, descSize);
       
   495 	if (err == KErrOverflow)
       
   496 		{
       
   497 		// If err is not found, we don't care (repository key hasn't been defined) so do nothing
       
   498 		RBuf8 buf;
       
   499 		CleanupClosePushL(buf);
       
   500 		buf.CreateL(descSize);
       
   501 		err = cenrep->Get(EEnabledTags, buf, descSize);
       
   502 		User::LeaveIfError(err); // Shouldn't happen
       
   503 
       
   504 		CBufFlat* cbuf = CBufFlat::NewL(buf.Length());
       
   505 		CleanupStack::PushL(cbuf);
       
   506 		cbuf->InsertL(0, buf);
       
   507 		RBufReadStream stream(*cbuf);
       
   508 		CleanupClosePushL(stream);
       
   509 
       
   510 		TInt count = stream.ReadInt32L();
       
   511 		while (count--)
       
   512 			{
       
   513 			TUint32 enabled = stream.ReadUint32L();
       
   514 			HBufC8* tagName = HBufC8::NewL(stream, 2000);
       
   515 			TTagData* tagData = iTags.Find(*tagName);
       
   516 			if (tagData)
       
   517 				{
       
   518 				delete tagName; // Not needed
       
   519 				}
       
   520 			else
       
   521 				{
       
   522 				tagData = new(ELeave)TTagData();
       
   523 				tagData->iTagName = tagName;
       
   524 				tagData->iRefCount = 0;
       
   525 				CleanupStack::PushL(tagData);
       
   526 				iTags.InsertL(tagName, tagData); // TODO hmm if this leaves, tagName will be leaked
       
   527 				CleanupStack::Pop(tagData);
       
   528 				}
       
   529 			tagData->iEnabled = enabled;
       
   530 			}
       
   531 		CleanupStack::PopAndDestroy(3, &buf); // stream, cbuf, buf
       
   532 		}
       
   533 	*/
       
   534 	CleanupStack::PopAndDestroy(cenrep);
       
   535 	}
       
   536 
       
   537 void CCloggerServer::PersistSettingsL()
       
   538 	{
       
   539 	CRepository* cenrep = CRepository::NewLC(KCloggerUid);
       
   540 	User::LeaveIfError(cenrep->Set(EGlobalOptions, (TInt&)iOptions));
       
   541 	User::LeaveIfError(cenrep->Set(EBufferSize, iBufferSize));
       
   542 	User::LeaveIfError(cenrep->Set(ENumBuffers, iNumBuffers));
       
   543 	User::LeaveIfError(cenrep->Set(ENumRotates, iNumRotates));
       
   544 	User::LeaveIfError(cenrep->Set(ERotateBehaviour, (TInt&)iRotateBehaviour));
       
   545 	User::LeaveIfError(cenrep->Set(ERepositoryVersion, ECenrepThreadNamesArePrettified));
       
   546 
       
   547 	User::LeaveIfError(cenrep->StartTransaction(CRepository::EReadWriteTransaction));
       
   548 	cenrep->CleanupCancelTransactionPushL();
       
   549 	TUint32 dontCare;
       
   550 	TInt err = cenrep->Delete(KEverythingPartialKey, KEverythingMask, dontCare);
       
   551 	if (err && err != KErrNotFound) User::Leave(err);
       
   552 	TUint32 key = KTagEnabledPartialKey;
       
   553 	TPtrHashMapIter<TDesC8, TTagData> tagIter(iTags);
       
   554 	const TTagData* tag;
       
   555 	while ((tag = tagIter.NextValue()) != NULL)
       
   556 		{
       
   557 		User::LeaveIfError(cenrep->Set(key, (TInt&)tag->iEnabled));
       
   558 		key++;
       
   559 		User::LeaveIfError(cenrep->Set(key, *tag->iTagName));
       
   560 		key++;
       
   561 		}
       
   562 	CleanupStack::Pop(); // Transaction
       
   563 	User::LeaveIfError(cenrep->CommitTransaction(dontCare));
       
   564 	CleanupStack::PopAndDestroy(cenrep);
       
   565 	}
       
   566 
       
   567 void CCloggerServer::ResetSettingsL()
       
   568 	{
       
   569 	CRepository* cenrep = CRepository::NewLC(KCloggerUid);
       
   570 	cenrep->Reset();
       
   571 	CleanupStack::PopAndDestroy(cenrep);
       
   572 	GetSettingsL();
       
   573 	}
       
   574 
       
   575 
       
   576 void CCloggerServer::UpdateBufferSizeL(TInt aSize, TInt aNum)
       
   577 	{
       
   578 	if (aSize < KMinWriteSize) aSize = KMinWriteSize; // Anything smaller is just pointless
       
   579 	if (aNum < 2) aNum = 2; // Likewise
       
   580 
       
   581 	FlushBuffers(); // Ensure everything is empty before we start
       
   582 	CloseBuffers();
       
   583 
       
   584 	iBufferSize = aSize;
       
   585 	iNumBuffers = aNum;
       
   586 	if (!(iOptions & RClogger::EBufferLog))
       
   587 		{
       
   588 		return;
       
   589 		}
       
   590 	TUint oldOptions = iOptions;
       
   591 	iOptions &= ~RClogger::EBufferLog; // Clear this, and set it back to oldOptions at the end, so that if we leave our flags accurately describe the state of our buffers
       
   592 	
       
   593 	User::LeaveIfError(AdjustBufferChunk(iBufferSize * iNumBuffers));
       
   594 	TUint8* ptr = iChunkForBufs.Base();
       
   595 	
       
   596 	while (aNum--)
       
   597 		{
       
   598 		TBufEntry* entry = new(ELeave) TBufEntry();
       
   599 		CleanupStack::PushL(entry);
       
   600 		entry->iBuf.Set(ptr, 0, iBufferSize);
       
   601 		entry->iArrayIdx = iBufs.Count();
       
   602 		iBufs.AppendL(entry);
       
   603 		CleanupStack::Pop(entry);
       
   604 		ptr += iBufferSize;
       
   605 		if (iBufs.Count() > 1) iBufs[iBufs.Count()-2]->iNext = entry;
       
   606 		}
       
   607 	
       
   608 	iOptions = oldOptions;
       
   609 	iBufs[iBufs.Count()-1]->iNext = iBufs[0];
       
   610 	iCurrent = iBufs[0];
       
   611 	UpdatedBuffers();
       
   612 	
       
   613 	if (iLogFile.SubSessionHandle())
       
   614 		{
       
   615 		ReCalculateFileAlignment();
       
   616 		// Need to update iSubtractSizeOfNextBuffer in case there's been some unbuffered logging since the file opened
       
   617 		// (Or indeed if this is the first time UpdateBuffers has been called, immediately after the file was opened)
       
   618 		}
       
   619 	}
       
   620 
       
   621 void CCloggerServer::ReCalculateFileAlignment()
       
   622 	{
       
   623 	TInt seekTo = 0;
       
   624 	/*TInt err =*/ iLogFile.Seek(ESeekCurrent, seekTo);
       
   625 	// Assuming iLogFile is valid, ESeekCurrent can never return an error (the documentation is not clear but the implementation is)
       
   626 	iSubtractSizeOfNextBuffer = KMinWriteSize - (seekTo % KMinWriteSize);
       
   627 	}
       
   628 
       
   629 TInt CCloggerServer::OpenLogFile()
       
   630 	{
       
   631 	TInt err = iLogFile.Open(iFs, KLogFile, EFileWrite|EFileShareAny|EFileStream);
       
   632 	if (err == KErrNotFound) err = iLogFile.Create(iFs, KLogFile, EFileWrite|EFileShareAny|EFileStream);
       
   633 	if (err == KErrNone)
       
   634 		{
       
   635 		TInt seekTo = -1;
       
   636 		/*err =*/ iLogFile.Seek(ESeekEnd, seekTo);
       
   637 		iWriters[EFile]->SetEnabled(ETrue);
       
   638 		ReCalculateFileAlignment();
       
   639 		}
       
   640 	else
       
   641 		{
       
   642 		iWriters[EFile]->SetEnabled(EFalse);
       
   643 		}
       
   644 	
       
   645 	return err;
       
   646 	}
       
   647 
       
   648 // Session
       
   649 
       
   650 inline CCloggerServer& CCloggerSession::Server()
       
   651 	{
       
   652 	return *static_cast<CCloggerServer*>(const_cast<CServerBase*>(CSessionBase::Server()));
       
   653 	}
       
   654 
       
   655 CCloggerSession::CCloggerSession()
       
   656 : CSensibleSession()
       
   657 	{
       
   658 	}
       
   659 
       
   660 
       
   661 CCloggerSession::~CCloggerSession()
       
   662 	{
       
   663 	if (iPerformanceLoggingChunk.Handle())
       
   664 		{
       
   665 		TUint8* base = iPerformanceLoggingChunk.Base();
       
   666 		TInt size = *(TInt*)base;
       
   667 		TPtrC8 ptr(base+4, size);
       
   668 		//__DEBUGGER();
       
   669 		Server().LogHighPerformanceBuffer(ptr);
       
   670 		iPerformanceLoggingChunk.Close();
       
   671 		}
       
   672 	iGetTagStatesContext.Close();
       
   673 	Server().DropSession(this);
       
   674 	}
       
   675 
       
   676 TBool CCloggerSession::DoServiceL(const RMessage& aMessage)
       
   677 	{
       
   678 	//CleanupPanicPushL(); //DEBUG
       
   679 
       
   680 	if (Server().ForceBreakpointRequested())
       
   681 		{
       
   682 		__DEBUGGER();
       
   683 		}
       
   684 
       
   685 	TBool handled = ETrue;
       
   686 	TInt res = KErrNone;
       
   687 
       
   688 	TInt func = aMessage.Function();
       
   689 	if (!iContext && func != ESetTag && func != ESetTag8)
       
   690 		{
       
   691 		ClientPanic(aMessage); // SetTag should have been called
       
   692 		return ETrue;
       
   693 		}
       
   694 
       
   695 	switch (func)
       
   696 		{
       
   697 		case ESetTag:
       
   698 		case ESetTag8:
       
   699 			{
       
   700 			TInt tagLen = aMessage.GetDesLengthL(0);
       
   701 			TBool twoLevel = aMessage.Ptr1() != NULL;
       
   702 			if (tagLen && twoLevel)
       
   703 				{
       
   704 				// 2-level tag name, as used by flogger/CDU
       
   705 				tagLen = tagLen + 1 + aMessage.GetDesLengthL(1); // plus 1 for the slash in "tag/subtag"
       
   706 				}
       
   707 			if (tagLen > 256)
       
   708 				{
       
   709 				// It makes it easier to guarantee correctness if we limit tag lengths. Since thread fullnames are also 256, this is a good number
       
   710 				User::Leave(KErrTooBig);
       
   711 				}
       
   712 
       
   713 			HBufC8* newTag = NULL;
       
   714 			if (tagLen)
       
   715 				{
       
   716 				newTag = HBufC8::NewMaxLC(tagLen);
       
   717 				if (func == ESetTag)
       
   718 					{
       
   719 					HBufC* tag = HBufC::NewMaxLC(tagLen);
       
   720 					TPtr ptr = tag->Des();
       
   721 					aMessage.ReadL(0, ptr);
       
   722 					if (twoLevel)
       
   723 						{
       
   724 						ptr.Append('/');
       
   725 						TInt len = ptr.Length();
       
   726 						TPtr16 endBit((TUint16*)ptr.Ptr()+len, 0, ptr.MaxLength() - len);
       
   727 						aMessage.ReadL(1, endBit);
       
   728 						ptr.SetLength(len + endBit.Length());
       
   729 						}
       
   730 					newTag->Des().Copy(ptr);
       
   731 					CleanupStack::PopAndDestroy(tag);
       
   732 					}
       
   733 				else
       
   734 					{
       
   735 					TPtr8 ptr = newTag->Des();
       
   736 					aMessage.ReadL(0, ptr);
       
   737 					if (twoLevel)
       
   738 						{
       
   739 						// Use a different separator for the 8-bit variant (as that distinguishes commsdebug from flogger)
       
   740 						ptr.Append(':');
       
   741 						TInt len = ptr.Length();
       
   742 						TPtr8 endBit((TUint8*)ptr.Ptr()+len, 0, ptr.MaxLength() - len);
       
   743 						aMessage.ReadL(1, endBit);
       
   744 						ptr.SetLength(len + endBit.Length());
       
   745 						}
       
   746 					}
       
   747 				if (*newTag == KCloggerTag || *newTag == KFallbackTag)
       
   748 					{
       
   749 					// Not allowed for any session to pretend to be us
       
   750 					CleanupStack::PopAndDestroy(newTag);
       
   751 					newTag = NULL;
       
   752 					tagLen = 0;
       
   753 					// Drop through to using thread name in this case
       
   754 					}
       
   755 				}
       
   756 
       
   757 			if (!tagLen)
       
   758 				{
       
   759 				// Default to using thread name for the tag
       
   760 				RThread client;
       
   761 				aMessage.ClientL(client);
       
   762 				CleanupClosePushL(client);
       
   763 				TFullName threadName = client.FullName();
       
   764 				CleanupStack::PopAndDestroy(&client);
       
   765 				newTag = HBufC8::NewLC(threadName.Length());
       
   766 				TPtr8 tagPtr = newTag->Des();
       
   767 				tagPtr.Copy(threadName);
       
   768 				CCloggerServer::ThreadPrettyName(tagPtr);
       
   769 				}
       
   770 
       
   771 			if (iContext)
       
   772 				{
       
   773 				Server().ReplaceTagL(iContext, newTag);
       
   774 				CleanupStack::Pop(newTag);
       
   775 				}
       
   776 			else
       
   777 				{
       
   778 				iContext = Server().NewSessionForTagL(newTag);
       
   779 				CleanupStack::Pop(newTag);
       
   780 				}
       
   781 
       
   782 			TInt sequenceNumber;
       
   783 			TUint32 enabled = Server().TagEnabled(iContext, &sequenceNumber);
       
   784 			TPckg<TUint32> enablePkg(enabled);
       
   785 			aMessage.WriteL(2, enablePkg);
       
   786 			res = sequenceNumber;
       
   787 			break;
       
   788 			}
       
   789 		case ELog8:
       
   790 			{
       
   791 			TUint32 enabledMask = aMessage.Int2();
       
   792 			TUint32 tagEnabled = Server().TagEnabled(iContext);
       
   793 			if (!(enabledMask & tagEnabled))
       
   794 				{
       
   795 				Server().RegisterDisabledLog(iContext); // SetShouldDisplay usually gets called when you call log, but if it's disabled, then we don't get that far...
       
   796 				// Don't bother reading the log data
       
   797 				break;
       
   798 				}
       
   799 
       
   800 			TInt stringLen = aMessage.GetDesLengthL(0);
       
   801 			RBuf8& buf = Server().SessionTempBuf();
       
   802 			if (stringLen > buf.MaxLength())
       
   803 				{
       
   804 				buf.ReAllocL(stringLen);
       
   805 				}
       
   806 			aMessage.ReadL(0, buf);
       
   807 			TInt tickCount = aMessage.Int1();
       
   808 			Server().Log(iContext, buf, tickCount);
       
   809 			break;
       
   810 			}
       
   811 		case EUpdateEnabledMask:
       
   812 			{
       
   813 			TUint32 e = Server().TagEnabled(iContext);
       
   814 			TPckg<TUint32> enabledBuf(e);
       
   815 			aMessage.WriteL(0, enabledBuf);
       
   816 			break;
       
   817 			}
       
   818 		case EHexDump:
       
   819 		case EHexDump16:
       
   820 			{
       
   821 			TUint32 enabledMask = aMessage.Int3();
       
   822 			if (!(enabledMask & Server().TagEnabled(iContext)))
       
   823 				{
       
   824 				// Don't bother reading the log data
       
   825 				break;
       
   826 				}
       
   827 			
       
   828 			RBuf8& header = Server().SessionTempBuf();
       
   829 			TInt dataLen = aMessage.GetDesLengthL(1);
       
   830 
       
   831 			if (func == EHexDump)
       
   832 				{
       
   833 				aMessage.ReadL(0, header);
       
   834 				}
       
   835 			else
       
   836 				{
       
   837 				TPtr16 widePtr((TUint16*)header.Ptr(), header.MaxLength() / 2);
       
   838 				aMessage.ReadL(0, widePtr);
       
   839 				header.SetLength(widePtr.Size());
       
   840 				header.Collapse();
       
   841 				}
       
   842 
       
   843 			// Should we use a preallocated buffer here? For ease of coding, don't
       
   844 			RBuf8 data;
       
   845 			CleanupClosePushL(data);
       
   846 			data.CreateL(dataLen);
       
   847 			aMessage.ReadL(1, data);
       
   848 			
       
   849 			TInt tickCount = aMessage.Int2();
       
   850 			Server().HexDumpL(iContext, header, data, tickCount);
       
   851 			CleanupStack::PopAndDestroy(&data);
       
   852 
       
   853 			break;
       
   854 			}
       
   855 		case EGetTagStates1:
       
   856 			{
       
   857 			iGetTagStatesContext.Close();
       
   858 			TServerCallback cb;
       
   859 			HBufC8* context;
       
   860 			TCallbackWriter writer(cb, &context);
       
   861 			Server().WriteCallbackForGetTagStatesL(writer);
       
   862 
       
   863 			if (context) iGetTagStatesContext.Assign(context);
       
   864 
       
   865 			TPckg<TServerCallback> pkg(cb);
       
   866 			aMessage.WriteL(0, pkg);
       
   867 			break;
       
   868 			}
       
   869 		case EGetTagStates2:
       
   870 			{
       
   871 			aMessage.WriteL(0, iGetTagStatesContext);
       
   872 			iGetTagStatesContext.Close();
       
   873 			break;
       
   874 			}
       
   875 		case ECreatePerformanceLoggingChunk:
       
   876 			{
       
   877 			if (iPerformanceLoggingChunk.Handle())
       
   878 				{
       
   879 				return KErrAlreadyExists;
       
   880 				}
       
   881 			RThread client;
       
   882 			aMessage.ClientL(client);
       
   883 			TInt size = aMessage.Int0();
       
   884 			res = Server().CreateKernChunkForClient(&client, size, size, iPerformanceLoggingChunk);
       
   885 			client.Close();
       
   886 			break;
       
   887 			}
       
   888 		case ERegisterPerformanceLoggingChunk:
       
   889 			{
       
   890 			TInt err = iPerformanceLoggingChunk.Open(aMessage, 0, EFalse);
       
   891 			User::LeaveIfError(err);
       
   892 			break;
       
   893 			}
       
   894 		default:
       
   895 			handled = EFalse;
       
   896 			break;
       
   897 		}
       
   898 	//CleanupStack::Pop(); //DEBUG
       
   899 	if (handled)
       
   900 		{
       
   901 		aMessage.Complete(res);
       
   902 		}
       
   903 	else
       
   904 		{
       
   905 		// Then just pass the message on to the server
       
   906 		return Server().DoServiceL(aMessage);
       
   907 
       
   908 		//DEBUG to catch unbalanced PushLs
       
   909 		//TBool r = 0;
       
   910 		//TRAPD(err, r = Server().DoServiceL(aMessage));
       
   911 		//User::LeaveIfError(err);
       
   912 		//return r;
       
   913 		//END DEBUG
       
   914 		}
       
   915 	return handled;
       
   916 	}
       
   917 
       
   918 
       
   919 TBool CCloggerServer::DoServiceL(const RMessage& aMessage)
       
   920 	{
       
   921 	TBool handled = ETrue;
       
   922 	TInt res = KErrNone;
       
   923 
       
   924 	switch (aMessage.Function())
       
   925 		{
       
   926 		case EDebugAlignLogFile:
       
   927 		case EDebugShutdownServer:
       
   928 		case EDebugForceBreakpointInServiceL:
       
   929 			{
       
   930 			_LIT_SECURITY_POLICY_S0(KTClogPolicy, FSHELL_UID_TCLOG);
       
   931 			User::LeaveIfError(KTClogPolicy().CheckPolicy(aMessage, "Debug API called  from not within tclog.exe"));
       
   932 			}
       
   933 			break;
       
   934 		default:
       
   935 			break;
       
   936 		}
       
   937 
       
   938 	switch (aMessage.Function())
       
   939 		{
       
   940 		case ESetGlobalOptions:
       
   941 			{
       
   942 			TUint oldOptions = iOptions;
       
   943 			iOptions = aMessage.Int0();
       
   944 
       
   945 			UpdatedGlobalOptionsL(oldOptions);
       
   946 			break;
       
   947 			}
       
   948 		case EGetGlobalOptions:
       
   949 			{
       
   950 			res = iOptions;
       
   951 			break;
       
   952 			}
       
   953 		case ESetEnabled:
       
   954 			{
       
   955 
       
   956 			ACQUIRE_FLAG_LOCK_OR_FAIL(EUsingTempBuf, break);
       
   957 			iTempBuf.Zero();
       
   958 			TPtr16 ptr((TUint16*)iTempBuf.Ptr(), iTempBuf.MaxLength()/2);
       
   959 			TInt err = aMessage.Read(0, ptr);
       
   960 			if (err)
       
   961 				{
       
   962 				RELEASE_FLAG_LOCK(EUsingTempBuf);
       
   963 				User::Leave(err);
       
   964 				}
       
   965 			TPtrC8 tagname8 = ptr.Collapse();
       
   966 			TTagData* tag = iTags.Find(tagname8);
       
   967 			if (tag == NULL)
       
   968 				{
       
   969 				// Implicitly create the tag
       
   970 				HBufC8* tagBuf = tagname8.AllocLC();
       
   971 				tag = reinterpret_cast<TTagData*>(NewSessionForTagL(tagBuf));
       
   972 				tag->SetShouldDisplay(); // The user wants to see it if they've just created it
       
   973 				CleanupStack::Pop(tagBuf);
       
   974 				}
       
   975 			RELEASE_FLAG_LOCK(EUsingTempBuf);
       
   976 
       
   977 			tag->iEnabled = aMessage.Int1();
       
   978 			_LIT8(KTagChanged, "Client %S changed log mask of tag [%S] to 0x%08x");
       
   979 			TPtrC8 safeTagName = tag->iTagName->Left(128); // LogNote doesn't check lengths
       
   980 			RThread client;
       
   981 			aMessage.ClientL(client);
       
   982 			TFullName clientName = client.FullName();
       
   983 			TPtrC8 safeClientName = clientName.Collapse().Left(128);
       
   984 			client.Close();
       
   985 			LogNote(ELogTagChanges, KTagChanged, &safeClientName, &safeTagName, tag->iEnabled);
       
   986 
       
   987 			// Send update message to all sessions that have this tag and have enabled
       
   988 			// EDontLogIfTagIsDisabled
       
   989 			NotifySessionsOfChangedTag(tag);
       
   990 
       
   991 			iEnabledStatesSequenceNumber++;
       
   992 			RProperty::Set(KCloggerUid, ESequenceNumber, iEnabledStatesSequenceNumber);
       
   993 			break;
       
   994 			}
       
   995 		case EIsEnabled:
       
   996 			{
       
   997 			ACQUIRE_FLAG_LOCK_OR_FAIL(EUsingTempBuf, break);
       
   998 			iTempBuf.Zero();
       
   999 			TPckgBuf<TUint32> logMask;
       
  1000 			TPtr16 ptr((TUint16*)iTempBuf.Ptr(), iTempBuf.MaxLength()/2);
       
  1001 			TInt err = aMessage.Read(0, ptr);
       
  1002 			if (err)
       
  1003 				{
       
  1004 				RELEASE_FLAG_LOCK(EUsingTempBuf);
       
  1005 				User::Leave(err);
       
  1006 				}
       
  1007 			TTagData* tag = iTags.Find(ptr.Collapse());
       
  1008 			RELEASE_FLAG_LOCK(EUsingTempBuf);
       
  1009 			if (tag)
       
  1010 				{
       
  1011 				logMask = tag->iEnabled;
       
  1012 				}
       
  1013 			else
       
  1014 				{
       
  1015 				logMask = iFallbackTag->iEnabled; // If/when it does start logging, this is the enabled mask it will get
       
  1016 				}
       
  1017 			aMessage.WriteL(1, logMask);
       
  1018 			break;
       
  1019 			}
       
  1020 		case EGetRamBufferSize:
       
  1021 			{
       
  1022 			TBuf8<8> buf;
       
  1023 			buf.SetLength(8);
       
  1024 			TInt* ptr = (TInt*)buf.Ptr();
       
  1025 			ptr[0] = iBufferSize;
       
  1026 			ptr[1] = iNumBuffers;
       
  1027 			aMessage.WriteL(0, buf);
       
  1028 			break;
       
  1029 			}
       
  1030 		case ESetRamBufferSize:
       
  1031 			{
       
  1032 			UpdateBufferSizeL(aMessage.Int0(), aMessage.Int1());
       
  1033 			break;
       
  1034 			}
       
  1035 		case ERotate:
       
  1036 			{
       
  1037 			Rotate(&aMessage);
       
  1038 			return ETrue;
       
  1039 			}
       
  1040 		case EGetRotateBehaviour:
       
  1041 			{
       
  1042 			TBuf8<8> buf;
       
  1043 			buf.SetLength(8);
       
  1044 			TInt* ptr = (TInt*)buf.Ptr();
       
  1045 			ptr[0] = iRotateBehaviour;
       
  1046 			ptr[1] = iNumRotates;
       
  1047 			aMessage.WriteL(0, buf);
       
  1048 			break;
       
  1049 			}
       
  1050 		case ESetRotateBehaviour:
       
  1051 			{
       
  1052 			iNumRotates = aMessage.Int0();
       
  1053 			iRotateBehaviour = aMessage.Int1();
       
  1054 			break;
       
  1055 			}
       
  1056 		case EPersistSettings:
       
  1057 			{
       
  1058 			PersistSettingsL();			
       
  1059 			break;
       
  1060 			}
       
  1061 		case EResetSettings:
       
  1062 			{
       
  1063 			ResetSettingsL();			
       
  1064 			break;
       
  1065 			}
       
  1066 		case EDebugAlignLogFile:
       
  1067 			{
       
  1068 			FlushBuffers();
       
  1069 			iLogFile.Write(TPtrC8((const TUint8*)MINTAGSTART));
       
  1070 			TInt pos = 0;
       
  1071 			User::LeaveIfError(iLogFile.Seek(ESeekCurrent, pos));
       
  1072 			pos = 4096 - (pos % 4096) - aMessage.Int0();
       
  1073 			if (pos < 2) pos += 4096; // use 2 rather than zero so that we always have room in buf for "\r\n"
       
  1074 			RBuf8 buf;
       
  1075 			buf.CreateMaxL(pos);
       
  1076 			buf.Fill('.');
       
  1077 			buf[pos-2] = '\r';
       
  1078 			buf[pos-1] = '\n';
       
  1079 			iLogFile.Write(buf);
       
  1080 			iLogFile.Flush();
       
  1081 			buf.Close();
       
  1082 			break;
       
  1083 			}
       
  1084 		case EDebugShutdownServer:
       
  1085 			{
       
  1086 			CloseBuffers(); // The tests assume we don't flush buffers when we receive a shutdown. Because it tests more things we do a tidy shutdown that would normally involve flushing the buffers.
       
  1087 			CActiveScheduler::Stop();
       
  1088 			return ETrue; // To skip the message complete
       
  1089 			}
       
  1090 		case ESetTagStates:
       
  1091 			{
       
  1092 			RBuf8 buf;
       
  1093 			CleanupClosePushL(buf);
       
  1094 			buf.CreateL(aMessage.GetDesLengthL(0));
       
  1095 			aMessage.ReadL(0, buf);
       
  1096 
       
  1097 			// Dear Points of View, Why Oh Why does RBufReadStream's constructor take a CBufBase and not a TDesC8?
       
  1098 			// Answer: Because no-one's really thought about this API for 15 years.
       
  1099 			//
       
  1100 			// There is one copy for IPC, one to construct the CBufFlat, and one to read an HBufC from the stream
       
  1101 			// Something like TCallbackWriter extended slightly could do it in one copy (the IPC)
       
  1102 
       
  1103 			CBufFlat* cbuf = CBufFlat::NewL(buf.Length());
       
  1104 			CleanupStack::PushL(cbuf);
       
  1105 			cbuf->InsertL(0, buf);
       
  1106 			RBufReadStream stream(*cbuf);
       
  1107 			CleanupClosePushL(stream);
       
  1108 			TInt count = stream.ReadInt32L();
       
  1109 			RBuf8 enabled;
       
  1110 			CleanupClosePushL(enabled);
       
  1111 			enabled.Assign(HBufC8::NewL(stream, KMaxTInt));
       
  1112 
       
  1113 			iEnabledStatesSequenceNumber++;
       
  1114 			RProperty::Set(KCloggerUid, ESequenceNumber, iEnabledStatesSequenceNumber);
       
  1115 
       
  1116 			_LIT8(KTagChanged, "Client %S updating tags");
       
  1117 			RThread client;
       
  1118 			aMessage.ClientL(client);
       
  1119 			TFullName clientName = client.FullName();
       
  1120 			TPtrC8 safeClientName = clientName.Collapse().Left(128);
       
  1121 			client.Close();
       
  1122 			LogNote(ELogTagChanges, KTagChanged, &safeClientName);
       
  1123 
       
  1124 			for (TInt i = 0; i < count; i++)
       
  1125 				{
       
  1126 				RBuf tagName;
       
  1127 				CleanupClosePushL(tagName);
       
  1128 				tagName.Assign(HBufC::NewL(stream, KMaxTInt));
       
  1129 				TUint32 enabledMask = *((TUint32*)&enabled[i * 4]);
       
  1130 				TTagData* tag = iTags.Find(tagName.Collapse());
       
  1131 				if (tag)
       
  1132 					{
       
  1133 					tag->iEnabled = enabledMask;
       
  1134 					NotifySessionsOfChangedTag(tag);
       
  1135 					}
       
  1136 				else
       
  1137 					{
       
  1138 					// If the client asked us to configure a non-existant tag, we'll just ignore it. The other option
       
  1139 					// would be to set it up on the assumption that tag will be used later. But we've specified in the API
       
  1140 					// what we'll do.
       
  1141 					}
       
  1142 				CleanupStack::PopAndDestroy(&tagName);
       
  1143 				}
       
  1144 			CleanupStack::PopAndDestroy(4, &buf); // enabled, stream, cbuf, buf
       
  1145 			break;
       
  1146 			}
       
  1147 		case EDebugForceBreakpointInServiceL:
       
  1148 			{
       
  1149 			iFlags.Set(EForceBreakpoint);
       
  1150 			break;
       
  1151 			}
       
  1152 		case EStartSessionWriterServer:
       
  1153 			{
       
  1154 			if (iSessionWriterServer)
       
  1155 				{
       
  1156 				res = KErrAlreadyExists;
       
  1157 				}
       
  1158 			else
       
  1159 				{
       
  1160 				iSessionWriterServer = new(ELeave) CSessionWriterServer(*this);
       
  1161 				iSessionWriterServer->ConstructL();
       
  1162 				}
       
  1163 			break;
       
  1164 			}
       
  1165 		default:
       
  1166 			handled = EFalse;
       
  1167 			break;
       
  1168 		}
       
  1169 	if (handled)
       
  1170 		{
       
  1171 		aMessage.Complete(res);
       
  1172 		}
       
  1173 	return handled;
       
  1174 	}
       
  1175 
       
  1176 TAny* CCloggerServer::NewSessionForTag(HBufC8* aTag)
       
  1177 	{
       
  1178 	// TODO reverse these so that we don't need a TRAP
       
  1179 	TAny* res = NULL;
       
  1180 	TRAP_IGNORE(res = NewSessionForTagL(aTag));
       
  1181 	return res;
       
  1182 	}
       
  1183 
       
  1184 TAny* CCloggerServer::NewSessionForTagL(HBufC8* aTag)
       
  1185 	{
       
  1186 	TTagData* tagData = iTags.Find(*aTag);
       
  1187 	if (!tagData)
       
  1188 		{
       
  1189 		tagData = new(ELeave) TTagData(aTag);
       
  1190 		tagData->iRefCount = 1;
       
  1191 		if (iFallbackTag)
       
  1192 			{
       
  1193 			// If the fallback tag has been initialised (Which it always will be except when we are setting up default tags during startup
       
  1194 			tagData->iEnabled = iFallbackTag->iEnabled;
       
  1195 			}
       
  1196 		else
       
  1197 			{
       
  1198 			tagData->iEnabled = KAllEnabled;
       
  1199 			}
       
  1200 		// Don't call SetShouldDisplay
       
  1201 		CleanupStack::PushL(tagData);
       
  1202 		iTags.InsertL(aTag, tagData);
       
  1203 		CleanupStack::Pop(tagData);
       
  1204 
       
  1205 		TPtrC8 safeTag = aTag->Left(200);
       
  1206 		_LIT8(KNewTag, "New tag created: [%S]");
       
  1207 		LogNote(ELogNewTags, KNewTag, &safeTag);
       
  1208 		}
       
  1209 	else
       
  1210 		{
       
  1211 		delete aTag;
       
  1212 		tagData->iRefCount++;
       
  1213 		}
       
  1214 	return tagData;
       
  1215 	}
       
  1216 
       
  1217 void CCloggerServer::ReplaceTagL(TAny*& aCurrentContext, HBufC8* aNewTag)
       
  1218 	{
       
  1219 	//TTagData* tag = iTags.Find(aCurrentTag);
       
  1220 	TTagData* tag = reinterpret_cast<TTagData*>(aCurrentContext);
       
  1221 	if (!tag || tag->iRefCount != 1 || tag->ShouldDisplay())
       
  1222 		{
       
  1223 		// Can't imagine how tag could be non-null. 
       
  1224 		// Don't allow tag name to updated if more than one session has been opened for it, or if anything's been written to the log
       
  1225 
       
  1226 		// The commsdebug API actually allows this, so we have to cater for it by instead doing a NewSessionForTag
       
  1227 		aCurrentContext = NewSessionForTagL(aNewTag);
       
  1228 		}
       
  1229 	else if (iTags.Find(*aNewTag) != NULL)
       
  1230 		{
       
  1231 		// We already have a session for the new tag name, so again NewSessionForTagL is the right thing to do
       
  1232 		aCurrentContext = NewSessionForTagL(aNewTag);
       
  1233 		}
       
  1234 	else
       
  1235 		{
       
  1236 		// This is a bit more complex than you'd expect because tag->iTagName must not be deleted until tag has been removed from the hashtable (since it is used as the key)
       
  1237 
       
  1238 		iTags.InsertL(aNewTag, tag); // On error, don't change anything, particularly what tag->iTagName points to
       
  1239 		// If that succeeded, update the tag's iTagName, remove the old tag name from the hashtable and finally delete it
       
  1240 		HBufC8* oldTagName = tag->iTagName;
       
  1241 		tag->iTagName = aNewTag; // Takes ownership
       
  1242 		iTags.Remove(oldTagName);
       
  1243 
       
  1244 		_LIT8(KNewTag, "Tag %S renamed to %S");
       
  1245 		TPtrC8 safeOld = oldTagName->Left(128);
       
  1246 		TPtrC8 safeNew = aNewTag->Left(128);
       
  1247 		LogNote(ELogNewTags, KNewTag, &safeOld, &safeNew);
       
  1248 
       
  1249 		delete oldTagName;
       
  1250 		}
       
  1251 	}
       
  1252 
       
  1253 void CCloggerServer::DropSession(CCloggerSession* /*aSession*/)
       
  1254 	{
       
  1255 	//TODO decrement ref count and remove tag if reaches zero?
       
  1256 	}
       
  1257 
       
  1258 void CCloggerServer::LogHighPerformanceBuffer(const TDesC8& aBuf)
       
  1259 	{
       
  1260 	// To avoid having to copy the data again (it could be 2MB) we use the sync write mechanism
       
  1261 	TUint oldOptions = iOptions;
       
  1262 	if (iOptions & RClogger::EBufferLog)
       
  1263 		{
       
  1264 		iOptions &= ~RClogger::EBufferLog;
       
  1265 		FlushBuffers();
       
  1266 		}
       
  1267 	_LIT8(KHighPerf, "Dumping high-performance logging chunk (one tick=%00.3fus)");
       
  1268 	LogError(KHighPerf, 1000000.0/iTickFreq);
       
  1269 	LogLine(aBuf);
       
  1270 	// Should really call UpdatedGlobalOptions, or at least UpdateBufferSizeL. Meh.
       
  1271 	iOptions = oldOptions;
       
  1272 	ReCalculateFileAlignment();
       
  1273 	}
       
  1274 
       
  1275 void CCloggerServer::LogLine(const TDesC8& aLine)
       
  1276 	{
       
  1277 	if (iOptions & RClogger::EBufferLog)
       
  1278 		{
       
  1279 		ResetIdleWriteTimer();
       
  1280 		TPtrC8 lineFrag(aLine);
       
  1281 		while (lineFrag.Length())
       
  1282 			{
       
  1283 			TDes8& buf = iCurrent->iBuf;
       
  1284 			TInt bufMaxLength = buf.MaxLength();
       
  1285 			if (iSubtractSizeOfNextBuffer > buf.MaxLength())
       
  1286 				{
       
  1287 				// Then we have a buffer < 512B. Can't happen because that's the min buffer size
       
  1288 				}
       
  1289 			bufMaxLength -= iSubtractSizeOfNextBuffer;
       
  1290 
       
  1291 			TInt spaceFree = bufMaxLength - buf.Length();
       
  1292 			ASSERT(spaceFree >= 0); // If it's negative then something's gone very wrong, we have less space in the buffer than the size of iSubtractSizeOfNextBuffer, implying the buffer was allowed to get too full
       
  1293 			buf.Append(lineFrag.Left(spaceFree));
       
  1294 			if (buf.Length() == bufMaxLength)
       
  1295 				{
       
  1296 				TRAPD(err, GotoNextBufL()); //TODO make this not need a trap?
       
  1297 				iSubtractSizeOfNextBuffer = 0; // If iSubtractSizeOfNextBuffer was non-zero, then by rotating buffers right now, we become all square
       
  1298 				if (err == KErrNoMemory)
       
  1299 					{
       
  1300 					// We needed to allocate a new buffer but couldn't, so block until we have space
       
  1301 					FlushBuffers(); // strictly we only need to wait for one buffer to be free, not all of them
       
  1302 					_LIT8(KNoMem, MINTAGSTART "Ran out of memory trying to expand buffers\r\n"); // we shouldn't be using iTempBuf here, so we can't format the timestamp!
       
  1303 					LogLine(KNoMem);
       
  1304 					}
       
  1305 				else if (err)
       
  1306 					{
       
  1307 					ASSERT(EFalse); // Nothing else should be causing an error in that function
       
  1308 					}
       
  1309 				}
       
  1310 			lineFrag.Set(lineFrag.Mid(Min(spaceFree, lineFrag.Length())));
       
  1311 			// If the line was longer than the amount of freespace in the current buffer, we'll loop here to write the rest
       
  1312 			}
       
  1313 		}
       
  1314 	else
       
  1315 		{
       
  1316 		iSyncWriteBuffer = &aLine;
       
  1317 		TUint anythingEnabled = GetEnabledWriters(); // If no writers are enabled, no need to do anything (and moreover we'd hang if we tried it)
       
  1318 		if (anythingEnabled)
       
  1319 			{
       
  1320 			TellAllWritersToWriteBuf(KSyncBufferIdx);
       
  1321 			BlockRequestsFrom(this, iKernDebugRouter);
       
  1322 			iFlushBufferWait.Start();
       
  1323 			// The logic to do the stop is in CompletedWritingBuf
       
  1324 			ASSERT(iSyncWriteBufferBusy == 0);
       
  1325 			StopBlocking();
       
  1326 			}
       
  1327 		iSyncWriteBuffer = NULL;
       
  1328 		}
       
  1329 	}
       
  1330 
       
  1331 void CCloggerServer::Log(TAny* aContext, const TDesC8& aLine, TUint32 aTickCount)
       
  1332 	{
       
  1333 	ACQUIRE_FLAG_LOCK(EInMiddleOfLog);
       
  1334 	ACQUIRE_FLAG_LOCK(EUsingTempBuf);
       
  1335 
       
  1336 	TTagData* tag = reinterpret_cast<TTagData*>(aContext);
       
  1337 	if (tag)
       
  1338 		{
       
  1339 		tag->SetShouldDisplay();
       
  1340 		}
       
  1341 	TBuf8<32> rdebugId;
       
  1342 	const TDesC8* t = &KCloggerTag;
       
  1343 	if (tag)
       
  1344 		{
       
  1345 		if (tag->iThreadIdForRDebugger)
       
  1346 			{
       
  1347 			// For RDebug::Prints we use [tid] for the tag name
       
  1348 			rdebugId.Num(tag->iThreadIdForRDebugger);
       
  1349 			t = &rdebugId;
       
  1350 			}
       
  1351 		else
       
  1352 			{
       
  1353 			t = tag->iTagName;
       
  1354 			}
       
  1355 		}
       
  1356 	const TDesC8& aTag = *t;
       
  1357 
       
  1358 	TDateTime dt = TickCountToTime(aTickCount).DateTime();
       
  1359 	_LIT8(KFormat, "%i-%02i-%02i %02i:%02i:%02i.%03i: [%S] %S\r\n");
       
  1360 	// Have to add 1 to Month and Day, as these are zero-based
       
  1361 	#define SF_ARGLIST dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond()/1000, &aTag, &aLine
       
  1362 
       
  1363 	#define SF_FORMAT KFormat
       
  1364 	#define SF_BUF iTempBuf
       
  1365 	#define SF_ACTION(buf) LogLine(buf)
       
  1366 	#include "SensibleFormat.h"
       
  1367 
       
  1368 	RELEASE_FLAG_LOCK(EInMiddleOfLog);
       
  1369 	RELEASE_FLAG_LOCK(EUsingTempBuf);
       
  1370 
       
  1371 	if (iFlags.IsSet(ELogBufferOverflow))
       
  1372 		{
       
  1373 		iFlags.Clear(ELogBufferOverflow);
       
  1374 		_LIT8(KCreated, "Had to create a new buffer because a writer wasn't finished (iBufferBusy=0x%x)");
       
  1375 
       
  1376 		// Is OK to use the temp buf now that the rest of the Log() function has finished
       
  1377 		// Since we know our string is < 512 chars (and that's the minimum for iTempBuf) we can dispense with the usual paranoid formatting constructs above
       
  1378 		LogError(KCreated, iCurrent->iNext->iBufferBusy);
       
  1379 		}
       
  1380 	}
       
  1381 
       
  1382 void CCloggerServer::CloseBuffers()
       
  1383 	{
       
  1384 	UpdatedBuffers(ETrue);
       
  1385 	for (TInt i = iBufs.Count()-1; i >= 0; i--)
       
  1386 		{
       
  1387 		TBufEntry* buf = iBufs[i];
       
  1388 		//buf->iBuf.Close();
       
  1389 		iBufs.Remove(i);
       
  1390 		delete buf;
       
  1391 		}
       
  1392 	AdjustBufferChunk(0);
       
  1393 	iCurrent = NULL;
       
  1394 	}
       
  1395 
       
  1396 void CCloggerServer::FlushBuffers()
       
  1397 	{
       
  1398 	iIdleWriteTimer->Cancel();
       
  1399 	// In the if statement below, check not only that we are buffering (iCurrent) but also that we have some writers to wait for (anythingEnabled)
       
  1400 	TUint anythingEnabled = GetEnabledWriters(); // If no writers are enabled, no need to do anything (and moreover we'd hang if we tried it)
       
  1401 	if (iCurrent && anythingEnabled)
       
  1402 		{
       
  1403 		iFlags.Set(EAllowCurrentBufferToBeRead);
       
  1404 		// All enabled writers should already be writing out any filled buffers we have
       
  1405 		// In case some have already finished writing all buffers, explicitly ask them to write out the current buffer as well
       
  1406 		TellAllWritersToWriteBuf(iCurrent->iArrayIdx);
       
  1407 		BlockRequestsFrom(this, iKernDebugRouter);
       
  1408 		iFlushBufferWait.Start();
       
  1409 		// The logic to do the stop is in CompletedWritingBuf
       
  1410 		StopBlocking();
       
  1411 		iFlags.Clear(EAllowCurrentBufferToBeRead);
       
  1412 
       
  1413 		ASSERT(iCurrent->iBufferBusy == 0); // Otherwise something is still outstanding...
       
  1414 		}
       
  1415 	}
       
  1416 
       
  1417 void CCloggerServer::GotoNextBufL()
       
  1418 	{
       
  1419 	iSubtractSizeOfNextBuffer = KMinWriteSize - (iCurrent->iBuf.Size() % KMinWriteSize);
       
  1420 	if (iSubtractSizeOfNextBuffer == KMinWriteSize) iSubtractSizeOfNextBuffer = 0;
       
  1421 
       
  1422 	// Tell writers to get cracking if they aren't already
       
  1423 	TellAllWritersToWriteBuf(iCurrent->iArrayIdx);
       
  1424 
       
  1425 	// Now update current buf
       
  1426 	TBufEntry* next = iCurrent->iNext;
       
  1427 	if (next->iBufferBusy)
       
  1428 		{
       
  1429 		// Buffer is still busy - so need to allocate a new one
       
  1430 		TBufEntry* entry = new(ELeave) TBufEntry();
       
  1431 		CleanupStack::PushL(entry);
       
  1432 		TInt size = iChunkForBufs.Size();
       
  1433 		User::LeaveIfError(AdjustBufferChunk(size + iBufferSize));
       
  1434 		entry->iBuf.Set(iChunkForBufs.Base() + size, 0, iBufferSize);
       
  1435 		entry->iArrayIdx = iBufs.Count();
       
  1436 		iBufs.AppendL(entry);
       
  1437 		CleanupStack::Pop(entry);
       
  1438 		// Insert buffer into the circular buffer
       
  1439 		entry->iNext = next;
       
  1440 		iCurrent->iNext = entry;
       
  1441 		iCurrent = entry;
       
  1442 		iFlags.Set(ELogBufferOverflow);
       
  1443 		}
       
  1444 	else
       
  1445 		{
       
  1446 		next->iBuf.Zero(); // If there are no writers enabled, next might not actually be empty
       
  1447 		iCurrent = next;
       
  1448 		}
       
  1449 	}
       
  1450 
       
  1451 const TDesC8& CCloggerServer::GetBuf(TInt aIdx)
       
  1452 	{
       
  1453 	if (aIdx == KSyncBufferIdx) return *iSyncWriteBuffer;
       
  1454 	if (aIdx == KCompressFileNameBufferIdx) return KNullDesC8; // The compressor sync writer doesn't use this parameter
       
  1455 
       
  1456 	TBufEntry* entry = iBufs[aIdx];
       
  1457 	ASSERT(entry->iBufferBusy); // If the buffer isn't marked as busy, noone should be accessing it
       
  1458 	return entry->iBuf;
       
  1459 	}
       
  1460 
       
  1461 void CCloggerServer::CompletedWritingBuf(MWriter* aWriter, TInt aIdx)
       
  1462 	{
       
  1463 	if (aIdx == KSyncBufferIdx)
       
  1464 		{
       
  1465 		// Magic number for sync writes
       
  1466 		TInt writerId = iWriters.Find(aWriter);
       
  1467 		ASSERT(writerId != KErrNotFound);
       
  1468 		iSyncWriteBufferBusy &= ~(1 << writerId);
       
  1469 		if (iSyncWriteBufferBusy == 0)
       
  1470 			{
       
  1471 			iFlushBufferWait.AsyncStop();
       
  1472 			}
       
  1473 		return;
       
  1474 		}
       
  1475 	else if (aIdx == KCompressFileNameBufferIdx)
       
  1476 		{
       
  1477 		// Magic number for background compress completed
       
  1478 		TInt err = KErrNone;
       
  1479 		if (iFlags.IsSet(ENeedToCopyCompressedLog) && iFileBeingRotated.Length())
       
  1480 			{
       
  1481 			iFlags.Clear(ENeedToCopyCompressedLog);
       
  1482 			TRAP(err, CopyLogToExternalMediaL(iFileBeingRotated));
       
  1483 			}
       
  1484 		if (!iRotationMessage.IsNull())
       
  1485 			{
       
  1486 			// Tell the client the rotate has finished
       
  1487 			if (!err) 
       
  1488 				{
       
  1489 				err = iRotationMessage.Write(0, iFileBeingRotated);
       
  1490 				if (err == KErrBadDescriptor) err = KErrNone; // Probably means they called Rotate() with no arguments and so didn't care about the file name
       
  1491 				}
       
  1492 			iRotationMessage.Complete(err);
       
  1493 			}
       
  1494 		iFileBeingRotated.SetLength(0);
       
  1495 		return;
       
  1496 		}
       
  1497 
       
  1498 	TBufEntry* entry = iBufs[aIdx];
       
  1499 
       
  1500 	TInt writerId = iWriters.Find(aWriter);
       
  1501 	ASSERT(writerId != KErrNotFound);
       
  1502 
       
  1503 	// Don't leave this in, it will cause an infinite loop if rdebug redirection is enabled!
       
  1504 	//RDebug::Printf("Writer %i finished writing buffer %i", writerId, aIdx);
       
  1505 
       
  1506 	// This writer is done with this buffer
       
  1507 	entry->iBufferBusy &= ~(1 << writerId);
       
  1508 
       
  1509 	TInt bufSize = entry->iBuf.Size();
       
  1510 	if (entry->iBufferBusy == 0)
       
  1511 		{
       
  1512 		// This buffer is now available again
       
  1513 		entry->iBuf.Zero();
       
  1514 		}
       
  1515 
       
  1516 	// Decide whether the next buffer in the chain also needs writing by this writer
       
  1517 
       
  1518 	TBufEntry* next = entry->iNext;
       
  1519 	if ((next->iBuf.Size() == next->iBuf.MaxSize() && entry != iCurrent) // The check for entry != iCurrent is to ensure we don't read past the end of the chain (ie it's technically possible for current to be full and next to be full but part of the tail of the chain)
       
  1520 		|| (next == iCurrent && iFlushBufferWait.IsStarted()))
       
  1521 		{
       
  1522 		// Next entry needs writing too
       
  1523 		TellWriterToWriteBuf(writerId, next->iArrayIdx);
       
  1524 		}
       
  1525 	else
       
  1526 		{
       
  1527 		// No more buffers need writing
       
  1528 		if (entry == iCurrent && entry->iBufferBusy == 0 && iFlushBufferWait.IsStarted())
       
  1529 			{
       
  1530 			// All writers have now completed so stop the scheduler to return to FlushBuffers()
       
  1531 			iFlushBufferWait.AsyncStop();
       
  1532 
       
  1533 			// Additionally we need to update iSubtractSizeOfNextBuffer since we don't do a GotoNextBuf when doing FlushBuffers
       
  1534 			iSubtractSizeOfNextBuffer = KMinWriteSize - (bufSize % KMinWriteSize);
       
  1535 			}
       
  1536 		}
       
  1537 	}
       
  1538 
       
  1539 TUint32 CCloggerServer::TagEnabled(const TAny* aContext, TInt* aSequenceNumber)
       
  1540 	{
       
  1541 	TUint32 res = KAllEnabled;
       
  1542 	const TTagData* data = reinterpret_cast<const TTagData*>(aContext);
       
  1543 	if (data)
       
  1544 		{
       
  1545 		res = data->iEnabled;
       
  1546 		}
       
  1547 	if (aSequenceNumber)
       
  1548 		{
       
  1549 		*aSequenceNumber = iEnabledStatesSequenceNumber;
       
  1550 		}
       
  1551 	return res;
       
  1552 	}
       
  1553 
       
  1554 void CCloggerServer::WriteCallbackForGetTagStatesL(TCallbackWriter& aWriter)
       
  1555 	{
       
  1556 	RBuf8 enabled;
       
  1557 	enabled.CreateL(iTags.Count() * 4);
       
  1558 	CleanupClosePushL(enabled);
       
  1559 
       
  1560 	TPtrHashMapIter<TDesC8, TTagData> tagIter(iTags);
       
  1561 	const TTagData* tag;
       
  1562 	while ((tag = tagIter.NextValue()) != NULL)
       
  1563 		{
       
  1564 		if (tag->ShouldDisplay())
       
  1565 			{
       
  1566 			// Don't include tags that have never logged anything - they are probably only here for getting the tag states
       
  1567 			const TPckgC<TUint32> tagEnabled(tag->iEnabled);
       
  1568 			enabled.Append(tagEnabled);
       
  1569 			}
       
  1570 		}
       
  1571 	aWriter.AddL(enabled);
       
  1572 	CleanupStack::PopAndDestroy(&enabled);
       
  1573 
       
  1574 	tagIter.Reset();
       
  1575 	while ((tag = tagIter.NextValue()) != NULL)
       
  1576 		{
       
  1577 		if (tag->ShouldDisplay())
       
  1578 			{
       
  1579 			const TDesC8* tagName = tag->iTagName;
       
  1580 			// Don't include tags that have never logged anything - they are probably only here for getting the tag states
       
  1581 			HBufC* tag16 = HBufC::NewLC(tagName->Length());
       
  1582 			tag16->Des().Copy(*tagName);
       
  1583 			aWriter.AddL(*tag16);
       
  1584 			CleanupStack::PopAndDestroy(tag16);
       
  1585 			}
       
  1586 		}
       
  1587 	}
       
  1588 
       
  1589 void CCloggerServer::NotifySessionsOfChangedTag(CCloggerServer::TTagData* tag)
       
  1590 	{
       
  1591 	iSessionIter.SetToFirst();
       
  1592 	CCloggerSession* sess;
       
  1593 	TServerCallback callback(ETagEnabledChanged);
       
  1594 	TCallbackWriter writer(callback, NULL);
       
  1595 	writer.AddL((TUint)tag->iEnabled);
       
  1596 
       
  1597 	while ((sess = (CCloggerSession*)iSessionIter++) != NULL)
       
  1598 		{
       
  1599 		if (sess->iContext == tag)
       
  1600 			{
       
  1601 			sess->DispatchCallback(callback);
       
  1602 			}
       
  1603 		}
       
  1604 	}
       
  1605 void CCloggerServer::ResetIdleWriteTimer()
       
  1606 	{
       
  1607 	ASSERT(iOptions & RClogger::EBufferLog); // The timer shouldn't get set when buffering is disabled
       
  1608 	const TInt KIdleTime = 500000; // 0.5 seconds
       
  1609 	iIdleWriteTimer->Cancel();
       
  1610 	TCallBack cb(StaticIdleTimerExpired, this);
       
  1611 	iIdleWriteTimer->Start(KIdleTime, KIdleTime, cb);
       
  1612 	}
       
  1613 
       
  1614 TInt CCloggerServer::StaticIdleTimerExpired(TAny* aThis)
       
  1615 	{
       
  1616 	static_cast<CCloggerServer*>(aThis)->IdleTimerExpired();
       
  1617 	return 0;
       
  1618 	}
       
  1619 
       
  1620 void CCloggerServer::IdleTimerExpired()
       
  1621 	{
       
  1622 	ASSERT(iOptions & RClogger::EBufferLog); // The timer shouldn't be firing when buffering is disabled
       
  1623 	iIdleWriteTimer->Cancel(); // Don't be periodic, this'll just waste CPU
       
  1624 
       
  1625 	// Go to the next buf, that will take care of everything
       
  1626 	TRAPD(err, GotoNextBufL());
       
  1627 	if (err == KErrNoMemory)
       
  1628 		{
       
  1629 		// We needed to allocate a new buffer but couldn't, so block until we have space
       
  1630 		FlushBuffers(); //TODO we only need to wait for one buffer to be free, not all of them
       
  1631 		_LIT8(KNoMem, "Ran out of memory trying to expand buffers during idle write");
       
  1632 		Log(NULL, KNoMem, User::NTickCount());
       
  1633 		}
       
  1634 	else if (err)
       
  1635 		{
       
  1636 		ASSERT(EFalse); // Nothing else should be causing an error in that function
       
  1637 		}
       
  1638 	if (iFlags.IsSet(ELogBufferOverflow))
       
  1639 		{
       
  1640 		// Important to check this flag whenever GotoNextBufL is called! Otherwise you risk it not getting picked up
       
  1641 		// until the next call to Log(), by which time buffering might have been disabled meaning iCurrent is no
       
  1642 		// longer valid
       
  1643 		iFlags.Clear(ELogBufferOverflow);
       
  1644 		_LIT8(KCreated, "Had to create a new buffer during idle write because a writer wasn't finished (iBufferBusy=0x%x)");
       
  1645 
       
  1646 		LogError(KCreated, iCurrent->iNext->iBufferBusy);
       
  1647 		}
       
  1648 
       
  1649 	}
       
  1650 
       
  1651 TUint CCloggerServer::GetEnabledWriters() const
       
  1652 	{
       
  1653 	TUint res = 0;
       
  1654 	for (TInt i = 0; i < iWriters.Count(); i++)
       
  1655 		{
       
  1656 		if (iWriters[i]->IsEnabled()) res |= 1 << i;
       
  1657 		}
       
  1658 	return res;
       
  1659 	}
       
  1660 
       
  1661 void CCloggerServer::Rotate(const RMessage* aMsg)
       
  1662 	{
       
  1663 	// This function uses a number of different error variables (rotateErr, continuationErr, listingErr) because not all errors are fatal or should be handled in the same way
       
  1664 
       
  1665 	if (iCompressor->IsActive() && (iRotateBehaviour & RClogger::ECompressRotatedLogs))
       
  1666 		{
       
  1667 		if (aMsg) aMsg->Complete(KErrNotReady);
       
  1668 		return;
       
  1669 		}
       
  1670 
       
  1671 	ASSERT(iRotationMessage.IsNull());
       
  1672 
       
  1673 	_LIT(KFormat, "%c:\\logs\\clogger_%i%02i%02i_%02i-%02i-%02i.%03i.txt");
       
  1674 	TDateTime dt = TickCountToTime(User::NTickCount()).DateTime();
       
  1675 	TDes& newName = iFileBeingRotated;
       
  1676 	iFs.SessionPath(newName);
       
  1677 	TUint driveLetter = newName[0];
       
  1678 	newName.Format(KFormat, driveLetter, dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond()/1000);
       
  1679 	
       
  1680 	FlushBuffers(); // overkill again but easier to implement
       
  1681 	iLogFile.Close();
       
  1682 	// NOTE: Be sure not to call LogNote or LogError between this point and the call to OpenLogFile below!
       
  1683 	RFile logFile;
       
  1684 	TInt rotateErr = logFile.Open(iFs, KLogFile, EFileShareExclusive|EFileWrite); // Need to reopen the file for exclusive access so I can rename it
       
  1685 	if (rotateErr == KErrNone)
       
  1686 		{
       
  1687 		rotateErr = logFile.Rename(newName);
       
  1688 		}
       
  1689 	logFile.Close();
       
  1690 
       
  1691 	if (rotateErr == KErrNotFound)
       
  1692 		{
       
  1693 		rotateErr = KErrNone;
       
  1694 		// No worries
       
  1695 		}
       
  1696 	else if (rotateErr)
       
  1697 		{
       
  1698 		// We couldn't rotate the log file. Just log the fact later on
       
  1699 		}
       
  1700 
       
  1701 	TInt continuationErr = OpenLogFile();
       
  1702 	if (continuationErr)
       
  1703 		{
       
  1704 		// We're in trouble now. Log to any remaining writers
       
  1705 		_LIT8(KRotateErr, "Error trying to reopen log file (%i)");
       
  1706 		LogError(KRotateErr, continuationErr);
       
  1707 		}
       
  1708 
       
  1709 	if (rotateErr)
       
  1710 		{
       
  1711 		// Then we failed to rotate (although we may have succeeded in reopening the file for logging)
       
  1712 		_LIT8(KRotateErr, "Failed to rotate log file (%i)");
       
  1713 		LogError(KRotateErr, rotateErr);
       
  1714 		}
       
  1715 
       
  1716 	// Delete all log files more than iNumRotates
       
  1717 	_LIT(KLogFileFormat, "clogger_*");
       
  1718 	CDir* list = NULL;
       
  1719 	TInt listingErr = iFs.GetDir(KLogFileFormat, KEntryAttNormal, ESortByName, list);
       
  1720 	if (!listingErr && list->Count() > iNumRotates)
       
  1721 		{
       
  1722 		for (TInt i = 0; i < list->Count() - iNumRotates; i++)
       
  1723 			{
       
  1724 			// Don't delete the log we've just created if we need to rotate it or if iNumRotates is anything other than zero
       
  1725 			// (On devices where the time is consistantly wrong it is possible to get in this situation)
       
  1726 			TBool justCreated = (*list)[i].iName.CompareC(newName) == 0;
       
  1727 			if (justCreated && ((iRotateBehaviour & RClogger::ECopyRotatedToExternalMedia) || iNumRotates > 0))
       
  1728 				{
       
  1729 				continue;
       
  1730 				}
       
  1731 			iFs.Delete((*list)[i].iName); // Ignore any errors because there's nothing we need to do
       
  1732 			}
       
  1733 		}
       
  1734 	delete list;
       
  1735 
       
  1736 	TBool compress = EFalse;
       
  1737 #ifdef FSHELL_EZLIB_SUPPORT
       
  1738 	compress = (rotateErr == KErrNone && (iRotateBehaviour & RClogger::ECompressRotatedLogs));
       
  1739 #endif
       
  1740 	if (compress)
       
  1741 		{
       
  1742 		if (iRotateBehaviour & RClogger::ECopyRotatedToExternalMedia)
       
  1743 			{
       
  1744 			iFlags.Set(ENeedToCopyCompressedLog);
       
  1745 			}
       
  1746 		iCompressor->WriteBuf(KCompressFileNameBufferIdx);
       
  1747 		}
       
  1748 	
       
  1749 	if (rotateErr == KErrNone && !compress && (iRotateBehaviour & RClogger::ECopyRotatedToExternalMedia))
       
  1750 		{
       
  1751 		TRAP(rotateErr, CopyLogToExternalMediaL(newName));
       
  1752 		}
       
  1753 	TInt aResult = rotateErr ? rotateErr : continuationErr;
       
  1754 
       
  1755 	TBool completeNow = !compress;
       
  1756 	if (aMsg)
       
  1757 		{
       
  1758 		if (completeNow)
       
  1759 			{
       
  1760 			if (aResult == KErrNone)
       
  1761 				{
       
  1762 				aResult = aMsg->Write(0, iFileBeingRotated);
       
  1763 				if (aResult == KErrBadDescriptor) aResult = KErrNone; // Probably means they called Rotate() with no arguments and so didn't care about the file name
       
  1764 				}
       
  1765 			aMsg->Complete(aResult);
       
  1766 			iFileBeingRotated.SetLength(0); // Finished with this buffer for now
       
  1767 			}
       
  1768 		else
       
  1769 			{
       
  1770 			iRotationMessage = *aMsg;
       
  1771 			}
       
  1772 		}
       
  1773 	}
       
  1774 
       
  1775 void CCloggerServer::CopyLogToExternalMediaL(TDes& aFile)
       
  1776 	{
       
  1777 	TInt err = KErrNone;
       
  1778 	TInt removableDrive = KErrNotFound;
       
  1779 	TInt hdAttributeDrive = KErrNotFound;
       
  1780 	// Figure out the first external media device
       
  1781 	for (TInt drive = EDriveA; drive <= EDriveZ; drive++)
       
  1782 		{
       
  1783 		TVolumeInfo info;
       
  1784 		err = iFs.Volume(info, drive);
       
  1785 		if (err == KErrNone)
       
  1786 			{
       
  1787 			LogNote(ELogDisks, _L8("Found drive %c iDrivaAtt=0x%x iType=0x%x"), 'A' + drive, info.iDrive.iDriveAtt, info.iDrive.iType);
       
  1788 			}
       
  1789 		if (err == KErrNone && (info.iDrive.iDriveAtt & KDriveAttRemovable))
       
  1790 			{
       
  1791 			removableDrive = drive;
       
  1792 			}
       
  1793 		else if (err == KErrNone && info.iDrive.iType == EMediaHardDisk)
       
  1794 			{
       
  1795 			// Added the check for hard disk without removable so we can use _epoc_drive_d in the emulator
       
  1796 			hdAttributeDrive = drive;
       
  1797 			break;
       
  1798 			}
       
  1799 		}
       
  1800 	TInt theDrive = hdAttributeDrive;
       
  1801 	if (removableDrive != KErrNotFound) theDrive = removableDrive; // Prefer something with the removable attribute, if we have both
       
  1802 
       
  1803 	if (theDrive != KErrNotFound)
       
  1804 		{
       
  1805 		CFileMan* fm = CFileMan::NewL(iFs);
       
  1806 		CleanupStack::PushL(fm);
       
  1807 		// aName is of the format C:\logs\clogger_xyz
       
  1808 		// extName needs to be D:\logs\clogger_xyz
       
  1809 		HBufC* nm = aFile.AllocLC();
       
  1810 		RBuf extName;
       
  1811 		extName.Assign(nm);
       
  1812 		TChar ffs;
       
  1813 		RFs::DriveToChar(theDrive, ffs);
       
  1814 		extName[0] = ffs;
       
  1815 		// Actually copy the file
       
  1816 		User::LeaveIfError(fm->Copy(aFile, extName, CFileMan::ERecurse));
       
  1817 		aFile = extName; // If all went well update the file name to reflect where we copied to
       
  1818 		CleanupStack::PopAndDestroy(2, fm); // extName/nm, fms
       
  1819 		}
       
  1820 	else
       
  1821 		{
       
  1822 		LogNote(ELogDisks, _L8("Couldn't find any suitable volumes to copy log file on to"));
       
  1823 		}
       
  1824 	}
       
  1825 
       
  1826 void CCloggerServer::LogError(TRefByValue<const TDesC8> aFmt, ...)
       
  1827 	{
       
  1828 	VA_LIST args;
       
  1829 	VA_START(args, aFmt);
       
  1830 	DoLogErrorOrNote(RClogger::EAllEnabled, aFmt, args);
       
  1831 	VA_END(args);
       
  1832 	}
       
  1833 
       
  1834 void CCloggerServer::LogNote(TUint32 aLogMask, TRefByValue<const TDesC8> aFmt, ...)
       
  1835 	{
       
  1836 	VA_LIST args;
       
  1837 	VA_START(args, aFmt);
       
  1838 	DoLogErrorOrNote(aLogMask, aFmt, args);
       
  1839 	VA_END(args);
       
  1840 	}
       
  1841 
       
  1842 void CCloggerServer::DoLogErrorOrNote(TUint32 aLogMask, const TDesC8 &aFmt, VA_LIST args)
       
  1843 	{
       
  1844 	if (!iFlags.IsSet(EWrittenToLog))
       
  1845 		{
       
  1846 		return; // Not ready to log yet - this can happen in the case that logging is attempted during ConstructL
       
  1847 		}
       
  1848 
       
  1849 	if (!(aLogMask & iCloggerTag->iEnabled) && aLogMask != RClogger::EAllEnabled)
       
  1850 		{
       
  1851 		// Make sure we always log errors, which are signified by aLogMask being EAllEnabled
       
  1852 		return;
       
  1853 		}
       
  1854 
       
  1855 	// Whole string must be less than iTempBuf.MaxLength (ie 512) and will cause a panic if it isn't. So use with caution!
       
  1856 	// ie don't pass in user-generated strings that might be massive.
       
  1857 
       
  1858 	_LIT8(KFmt, "%i-%02i-%02i %02i:%02i:%02i.%03i: [Clogger] ");
       
  1859 	_LIT8(KEnd, "\r\n");
       
  1860 
       
  1861 	ACQUIRE_FLAG_LOCK(EUsingTempBuf);
       
  1862 
       
  1863 	iTempBuf.Zero();
       
  1864 	//iTempBuf.Append(KFmt);
       
  1865 
       
  1866 	TDateTime dt = TickCountToTime(User::NTickCount()).DateTime();
       
  1867 	iTempBuf.Format(KFmt, dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond()/1000);
       
  1868 	iTempBuf.AppendFormatList(aFmt, args);
       
  1869 	iTempBuf.Append(KEnd);
       
  1870 	LogLine(iTempBuf);
       
  1871 
       
  1872 	RELEASE_FLAG_LOCK(EUsingTempBuf);
       
  1873 	}
       
  1874 
       
  1875 void CCloggerServer::LogsDirHasBeenCreated()
       
  1876 	{
       
  1877 	//__DEBUGGER();
       
  1878 	OpenLogFile(); // Ignore error
       
  1879 	}
       
  1880 
       
  1881 TDes& CCloggerServer::GetFilenameToRotate()
       
  1882 	{
       
  1883 	return iFileBeingRotated;
       
  1884 	}
       
  1885 
       
  1886 void CCloggerServer::HexDumpL(TAny* aContext, const TDesC8& aHeader, const TDesC8& aData, TUint32 aTickCount)
       
  1887 	{
       
  1888 	const TInt KLineSize = 16;
       
  1889 	const TInt KExtra = 7 + 1; // The number of chars of padding that go into the output line.
       
  1890 	// Header0000 : 00 01 02 03  ....
       
  1891 	// So line len is headerLen + 4 + 3 + (3 * lineSize) + 1 + lineSize
       
  1892 	_LIT8(KFormat, "%04X : ");
       
  1893 	RBuf8 lineBuf;
       
  1894 	CleanupClosePushL(lineBuf);
       
  1895 	lineBuf.CreateL(aHeader.Length() + 4 * KLineSize + KExtra);
       
  1896 
       
  1897 	TPtrC8 lineFrag(aData);
       
  1898 	TInt offset = 0;
       
  1899 	while (lineFrag.Length())
       
  1900 		{
       
  1901 		lineBuf.Zero();
       
  1902 		TInt lineSize = Min(KLineSize, lineFrag.Length());
       
  1903 		// Start with header (or empty space if continuation)
       
  1904 		if (offset == 0)
       
  1905 			{
       
  1906 			lineBuf.Append(aHeader);
       
  1907 			}
       
  1908 		else
       
  1909 			{
       
  1910 			lineBuf.AppendFill(' ', aHeader.Length());
       
  1911 			}
       
  1912 
       
  1913 		// Add offset
       
  1914 		lineBuf.AppendFormat(KFormat, offset);
       
  1915 		offset += lineSize;
       
  1916 
       
  1917 		// Add hex representation
       
  1918 		for (TInt i = 0; i < lineSize; i++)
       
  1919 			{
       
  1920 			TBuf8<2> charBuf;
       
  1921 			charBuf.NumFixedWidthUC(lineFrag[i], EHex, 2);
       
  1922 			lineBuf.Append(charBuf);
       
  1923 			lineBuf.Append(' ');
       
  1924 			}
       
  1925 		// Add filler if lineSize < KLineSize
       
  1926 		lineBuf.AppendFill(' ', (KLineSize - lineSize) * 3);
       
  1927 
       
  1928 		// Add ascii representation
       
  1929 		lineBuf.Append(' ');
       
  1930 		for (TInt i = 0; i < lineSize; i++)
       
  1931 			{
       
  1932 			TChar c = lineFrag[i];
       
  1933 			lineBuf.Append(c.IsPrint() ? c : TChar('.'));
       
  1934 			}
       
  1935 		lineFrag.Set(lineFrag.Mid(lineSize));
       
  1936 		Log(aContext, lineBuf, aTickCount);
       
  1937 		}
       
  1938 	CleanupStack::PopAndDestroy(&lineBuf);
       
  1939 	}
       
  1940 
       
  1941 void CCloggerServer::SetKernelLoggingL(TBool aEnable)
       
  1942 	{
       
  1943 	if (!iKernDebugRouter)
       
  1944 		{
       
  1945 		// Either means we're being called very early during server ConstructL, or the debug router LDD is missing
       
  1946 		return;
       
  1947 		}
       
  1948 	if (aEnable)
       
  1949 		{
       
  1950 		iKernDebugRouter->OpenChunkL(); // This will do nothing if already open
       
  1951 		}
       
  1952 	
       
  1953 	if (aEnable)
       
  1954 		{
       
  1955 		TBool consume = ETrue; //iOptions & RClogger::EMirrorToRDebugPrint;
       
  1956 		// ^ We always consume, it makes things easier.
       
  1957 		iKernDebugRouter->StartRouting(consume);
       
  1958 		}
       
  1959 	else
       
  1960 		{
       
  1961 		iKernDebugRouter->StopRouting();
       
  1962 		}
       
  1963 	}
       
  1964 
       
  1965 const TInt KThreadTagNamBufLen = 256;
       
  1966 
       
  1967 void CCloggerServer::LogKernMessage(TUint8 aWhere, TUint32 aTickCount, TUint aThreadId, const TDesC8& aMsg)
       
  1968 	{
       
  1969 	TUint enableMask = aWhere == 'K' ? ELogKernPrintf : aWhere == 'P' ? ELogPlatSecDiagnostics : ELogRDebugPrint;
       
  1970 	TBool kern = aWhere != 'U';
       
  1971 	TTagData* tag = iRDebugTag; // This is used only as a last-ditch fallback if we've run out memory
       
  1972 
       
  1973 	if (aThreadId != 0)
       
  1974 		{
       
  1975 		// Look for a tag in the iRDebugTags
       
  1976 		TTagData** tagDataPtr = iRDebugTags.Find(aThreadId);
       
  1977 		if (tagDataPtr) tag = *tagDataPtr;
       
  1978 		else
       
  1979 			{
       
  1980 			// New tag (or rather, look in iTags keyed by thread name)
       
  1981 			RThread thread;
       
  1982 			TInt err = KErrNone;
       
  1983 			HBufC8* tagBuf = HBufC8::New(KThreadTagNamBufLen*2);
       
  1984 			if (!tagBuf) err = KErrNoMemory;
       
  1985 			
       
  1986 			if (err)
       
  1987 				{
       
  1988 				// Fall back to just RDebug::Print or Kern::Printf as appropriate
       
  1989 				_LIT8(KUnknown, "Unknown thread %u has started rdebugging");
       
  1990 				_LIT8(KUnknownKern, "Unknown kernel thread %u has started rdebugging");
       
  1991 				LogNote(ELogNewRdebuggers, kern ? KUnknownKern() : KUnknown() , aThreadId);
       
  1992 				iRDebugTags.Insert(aThreadId, tag); // So that we don't get the above message every time this thread debugs
       
  1993 				}
       
  1994 			else
       
  1995 				{
       
  1996 				err = thread.Open(aThreadId);
       
  1997 				TPtr wPtr((TUint16*)tagBuf->Ptr(), KThreadTagNamBufLen);
       
  1998 				if (err)
       
  1999 					{
       
  2000 					// Couldn't open thread - use Thread-xxx as tag
       
  2001 					_LIT(KThreadFormat, "Thread-%u");
       
  2002 					wPtr.Format(KThreadFormat, aThreadId);
       
  2003 					}
       
  2004 				else
       
  2005 					{
       
  2006 					//thread.FullName(wPtr); // This didn't exist on 9.1...
       
  2007 					TFullName name = thread.FullName();
       
  2008 					wPtr = name;
       
  2009 					}
       
  2010 				thread.Close();
       
  2011 				TInt len = wPtr.Collapse().Length();
       
  2012 				TPtr8 narrowPtr = tagBuf->Des();
       
  2013 				narrowPtr.SetLength(len);
       
  2014 				ThreadPrettyName(narrowPtr);
       
  2015 				TPtrC8 safeName = tagBuf->Left(150);
       
  2016 				_LIT8(KNewTag, "Thread [%u] (%S) has started rdebugging");
       
  2017 				LogNote(ELogNewRdebuggers, KNewTag, aThreadId, &safeName);
       
  2018 				TAny* theTag = NewSessionForTag(tagBuf);
       
  2019 				if (theTag) 
       
  2020 					{
       
  2021 					tag = reinterpret_cast<TTagData*>(theTag);
       
  2022 					tag->iThreadIdForRDebugger = aThreadId;
       
  2023 					iRDebugTags.Insert(aThreadId, tag);
       
  2024 					}
       
  2025 				else
       
  2026 					{
       
  2027 					delete tagBuf;
       
  2028 					}
       
  2029 				}
       
  2030 			}
       
  2031 			// If an error occurred then we'll just log using the RDebug::Print tag
       
  2032 		}
       
  2033 
       
  2034 	if (tag->iEnabled & enableMask)
       
  2035 		{
       
  2036 		Log(tag, aMsg, aTickCount);
       
  2037 		}
       
  2038 	else
       
  2039 		{
       
  2040 		RegisterDisabledLog(tag);
       
  2041 		}
       
  2042 	}
       
  2043 
       
  2044 void CCloggerServer::UpdatedGlobalOptionsL(TUint aOldOptions)
       
  2045 	{
       
  2046 	if ((aOldOptions & RClogger::EBufferLog) != (iOptions & RClogger::EBufferLog))
       
  2047 		{
       
  2048 		UpdateBufferSizeL(iBufferSize, iNumBuffers);
       
  2049 		}
       
  2050 
       
  2051 	iWriters[ERDebug]->SetEnabled(iOptions & RClogger::EMirrorToRDebugPrint);
       
  2052 	iWriters[EMessageQueue]->SetEnabled(iOptions & RClogger::EMirrorToMessageQueue);
       
  2053 	iWriters[EFile]->SetEnabled(!(iOptions & RClogger::EDisableFileWriter));
       
  2054 
       
  2055 	TBool redirectRDebugBeingChanged = (aOldOptions & RClogger::ERedirectRDebugPrintToClogger) != (iOptions & RClogger::ERedirectRDebugPrintToClogger);
       
  2056 	TBool mirrorRDebugChanged = (aOldOptions & RClogger::EMirrorToRDebugPrint) != (iOptions & RClogger::EMirrorToRDebugPrint);
       
  2057 
       
  2058 	if (redirectRDebugBeingChanged || mirrorRDebugChanged)
       
  2059 		{
       
  2060 		SetKernelLoggingL(iOptions & RClogger::ERedirectRDebugPrintToClogger);
       
  2061 		}
       
  2062 	}
       
  2063 
       
  2064 void CCloggerServer::TellAllWritersToWriteBuf(TInt aBuf)
       
  2065 	{
       
  2066 	for (TInt i = 0; i < iWriters.Count(); i++)
       
  2067 		{
       
  2068 		TellWriterToWriteBuf(i, aBuf);
       
  2069 		}
       
  2070 	}
       
  2071 
       
  2072 void CCloggerServer::TellWriterToWriteBuf(TInt aWriterId, TInt aBuf)
       
  2073 	{
       
  2074 	MWriter* writer = iWriters[aWriterId];
       
  2075 	if (writer->IsEnabled() && !writer->IsBusyWriting())
       
  2076 		{
       
  2077 		if (aBuf == KSyncBufferIdx)
       
  2078 			{
       
  2079 			iSyncWriteBufferBusy |= (1<<aWriterId);
       
  2080 			}
       
  2081 		else
       
  2082 			{
       
  2083 			TBufEntry* entry = iBufs[aBuf];
       
  2084 			entry->iBufferBusy |= (1<<aWriterId);
       
  2085 			}
       
  2086 		writer->WriteBuf(aBuf);
       
  2087 		}
       
  2088 	}
       
  2089 
       
  2090 void CCloggerServer::RegisterDisabledLog(TAny* aContext)
       
  2091 	{
       
  2092 	reinterpret_cast<TTagData*>(aContext)->SetShouldDisplay();
       
  2093 	}
       
  2094 
       
  2095 void CCloggerServer::UpdatedBuffers(TBool aAboutToCloseBuffers)
       
  2096 	{
       
  2097 	if (!iKernDebugRouter)
       
  2098 		{
       
  2099 		// No point doing anything
       
  2100 		return;
       
  2101 		}
       
  2102 	
       
  2103 	// If there are more than 8 buffers then you're on your own!
       
  2104 	const TInt KMaxBuffersInParams = 8; // Note - this should probably be defined to be the same as KMaxCrashDumpAreas
       
  2105 	
       
  2106 	TUint32 base = (TUint32)iChunkForBufs.Base();
       
  2107 	
       
  2108 	SCloggerCrashDumpArea bufAreas[KMaxBuffersInParams];
       
  2109 	TInt numBuffers = 0;
       
  2110 	if (!aAboutToCloseBuffers)
       
  2111 		{
       
  2112 		for (TInt i = 0; numBuffers < KMaxBuffersInParams && i < iBufs.Count(); i++)
       
  2113 			{
       
  2114 			TBufEntry* buf = iBufs[i];
       
  2115 			bufAreas[numBuffers].iChunkHandle = iChunkForBufs.Handle();
       
  2116 			bufAreas[numBuffers].iOffset = (TUint32)buf->iBuf.Ptr() - base;
       
  2117 			bufAreas[numBuffers].iSize = buf->iBuf.MaxSize();
       
  2118 			_LIT8(KBufName, "Clogger Buffer %i");
       
  2119 			bufAreas[numBuffers].iName.Format(KBufName, i);
       
  2120 			numBuffers++;
       
  2121 			}
       
  2122 		}
       
  2123 	// Now check sessions for performance logging chunks
       
  2124 	iSessionIter.SetToFirst();
       
  2125 	CCloggerSession* sess;
       
  2126 	while ((sess = (CCloggerSession*)iSessionIter++) != NULL)
       
  2127 		{
       
  2128 		TInt chunkHandle = sess->iPerformanceLoggingChunk.Handle();
       
  2129 		if (chunkHandle && numBuffers < KMaxBuffersInParams)
       
  2130 			{
       
  2131 			bufAreas[numBuffers].iChunkHandle = chunkHandle;
       
  2132 			bufAreas[numBuffers].iOffset = 0; // Performance logging uses the whole chunk
       
  2133 			bufAreas[numBuffers].iSize = sess->iPerformanceLoggingChunk.Size();
       
  2134 			_LIT8(KBufName, "Clogger MemLog ");
       
  2135 			bufAreas[numBuffers].iName = KBufName;
       
  2136 			TPtrC8 tagName = reinterpret_cast<TTagData*>(sess->iContext)->iTagName->Left(bufAreas[numBuffers].iName.MaxLength() - bufAreas[numBuffers].iName.Length());
       
  2137 			bufAreas[numBuffers].iName.Append(tagName);
       
  2138 			numBuffers++;
       
  2139 			}
       
  2140 		}
       
  2141 	
       
  2142 	TPtrC8 ptr((const TUint8*)&bufAreas[0], numBuffers * sizeof(SCloggerCrashDumpArea));
       
  2143 	iKernDebugRouter->RegisterCrashDumpAreas(ptr);
       
  2144 	}
       
  2145 
       
  2146 TInt CCloggerServer::CreateKernChunkForClient(RThread* aClient, TInt aMaxSize, TInt aCommittedSize, RChunk& aOurChunk)
       
  2147 	{
       
  2148 	if (!iKernDebugRouter)
       
  2149 		{
       
  2150 		return KErrNotSupported;
       
  2151 		}
       
  2152 
       
  2153 	return iKernDebugRouter->CreateKernChunkForClient(aClient, aMaxSize, aCommittedSize, aOurChunk);
       
  2154 	}
       
  2155 
       
  2156 TInt CCloggerServer::AdjustBufferChunk(TInt aNewSize)
       
  2157 	{
       
  2158 	// This is needed because you can't adjust a chunk created on kernel-side from user side. Grr.
       
  2159 	TInt err = KErrNotSupported;
       
  2160 	if (iKernDebugRouter)
       
  2161 		{
       
  2162 		err = iKernDebugRouter->AdjustChunk(iChunkForBufs, aNewSize);
       
  2163 		} 
       
  2164 	else if (iChunkForBufs.Handle()) // Might not have been created yet
       
  2165 		{
       
  2166 		// If the chunk wasn't created via the device driver, it's fine to adjust it directly
       
  2167 		err = iChunkForBufs.Adjust(aNewSize);
       
  2168 		}
       
  2169 	return err;
       
  2170 	}
       
  2171 
       
  2172 CSessionWriter* CCloggerServer::RegisterSessionWithSessionWriter(CSessionWriterSession* aSession)
       
  2173 	{
       
  2174 	CSessionWriter* sessionWriter = static_cast<CSessionWriter*>(iWriters[ESessionWriter]);
       
  2175 	if (!aSession)
       
  2176 		{
       
  2177 		// Session closing
       
  2178 		sessionWriter->SetEnabled(EFalse);
       
  2179 		sessionWriter->iSession = NULL;
       
  2180 		return NULL;
       
  2181 		}
       
  2182 	else if (sessionWriter->iSession)
       
  2183 		{
       
  2184 		// Already got one
       
  2185 		return NULL;
       
  2186 		}
       
  2187 	else
       
  2188 		{
       
  2189 		sessionWriter->iSession = aSession;
       
  2190 		return sessionWriter;
       
  2191 		}
       
  2192 	}
       
  2193 
       
  2194 RChunk& CCloggerServer::GetBufChunk()
       
  2195 	{
       
  2196 	return iChunkForBufs;
       
  2197 	}
       
  2198 
       
  2199 void CCloggerServer::ThreadPrettyName(TDes8& aName)
       
  2200 	{
       
  2201 	// Algorithm is:
       
  2202 	// Given a aName xxx(.exe)?\[uid\]nonce::(!)?yyy
       
  2203 	// if yyy == xxx (case insensitive compare) then just display yyy (with exclamation mark if present)
       
  2204 	// else display xxx::yyy
       
  2205 
       
  2206 	// Find the :: that splits thread and process name
       
  2207 	_LIT8(KDoubleColon, "::");
       
  2208 	TInt colon = aName.Find(KDoubleColon);
       
  2209 	if (colon == KErrNotFound)
       
  2210 		{
       
  2211 		// It's not a thread name
       
  2212 		return;
       
  2213 		}
       
  2214 
       
  2215 	// Remove .exe if present immediately before [uid]
       
  2216 	TInt brak = aName.Left(colon).LocateReverse('[');
       
  2217 	_LIT8(KExe, ".exe");
       
  2218 	if (brak >= 5 && aName.Mid(brak-4, 4).CompareF(KExe) == 0)
       
  2219 		{
       
  2220 		aName.Delete(brak-4, 4);
       
  2221 		brak -= 4;
       
  2222 		colon -= 4;
       
  2223 		}
       
  2224 
       
  2225 	TPtrC8 procaName = brak >=0 ? aName.Left(brak) : aName.Left(colon);
       
  2226 	TPtrC8 threadaName = aName.Mid(colon+2);
       
  2227 	TPtrC8 realThreadaName = threadaName.Length() && threadaName[0] == '!' ? threadaName.Mid(1) : threadaName;
       
  2228 	if (procaName.CompareF(realThreadaName) == 0)
       
  2229 		{
       
  2230 		aName.Delete(0, colon+2);
       
  2231 		}
       
  2232 	else if (brak >= 0)
       
  2233 		{
       
  2234 		aName.Delete(brak, colon-brak);
       
  2235 		}
       
  2236 	}
       
  2237 
       
  2238 TBool CCloggerServer::ForceBreakpointRequested() const
       
  2239 	{
       
  2240 	return iFlags.IsSet(EForceBreakpoint);
       
  2241 	}
       
  2242 
       
  2243 inline TTime CCloggerServer::TickCountToTime(TUint32 aTickCount) const
       
  2244 	{
       
  2245 	return TTime(iTimeAtStartup.Int64() + (((TInt64)aTickCount*1000000) / (TInt64)iTickFreq) - iStartupTickInMicroseconds);
       
  2246 	}