traceservices/commsdebugutility/SSVR/comsdbgsvr.cpp
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implements the Flogger server side
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21 */
       
    22 
       
    23 #include "comsdbgsvr.h"
       
    24 #include "comsdbgwriter.h"
       
    25 #include "comsdbgstd.h"
       
    26 #include "comsdbgmessages.h"
       
    27 
       
    28 _LIT8(KOOMErrorString, "#Logs may be lost out of memory!! Further OOM conditions may not be recorded.\r\n");
       
    29 _LIT8(KThreadDiedString, "#Something caused the secondary thread in comsdbgutil to die.\r\n");
       
    30 _LIT8(KIniFileProblem, "#There is a problem with the ini file\r\n");
       
    31 _LIT8(KIniFileUpdate, "#Ini file changes detected and noted.\r\n");
       
    32 _LIT(KFloggerSecondaryThreadName, "Comsdbg2");
       
    33 
       
    34 
       
    35 
       
    36 
       
    37 
       
    38 //
       
    39 // CFileLoggerServer class definition
       
    40 //
       
    41 
       
    42 
       
    43 CFileLoggerServer* CFileLoggerServer::NewL()
       
    44 	{
       
    45 
       
    46 	CFileLoggerServer* r=new(ELeave) CFileLoggerServer();
       
    47 	CleanupStack::PushL(r);
       
    48 	r->ConstructL();
       
    49 	r->StartL(KFLoggerServerName);
       
    50 	CleanupStack::Pop();
       
    51 	return r;
       
    52 	}
       
    53 
       
    54 CFileLoggerServer::CFileLoggerServer()
       
    55 	: CServer2(EPriorityNormal,ESharableSessions)
       
    56 	{}
       
    57 
       
    58 void CFileLoggerServer::ConstructL()
       
    59 /**
       
    60  *
       
    61  * @note Constructs the secondary thread, passing through a pointer to the log queue.
       
    62  * Constructs the file parser object and parses the file, attempting to copy the
       
    63  * file from the ROM if it is not found on C drive.
       
    64  * Constructs the time beat.
       
    65  * Performs the first UpdateMedia to ensure a media is set.
       
    66  */
       
    67 	{
       
    68 	User::LeaveIfError(iCriticalSection.CreateLocal());
       
    69 	User::LeaveIfError(iCompletionSemaphore.CreateLocal(0));
       
    70 	User::LeaveIfError(iFs.Connect());
       
    71 
       
    72 #if defined (__WINS__)
       
    73 	iDebugWriter = CDebugPortProtocol::NewL();
       
    74 #endif
       
    75 
       
    76 	User::LeaveIfError(iLogMessageArray.Append(NULL));
       
    77 	iPreAllocatedErrorMessage = CLogCommentMessage::NewL(KOOMErrorString);
       
    78 	iArrayHasSpaceForWrite = ETrue;
       
    79 	
       
    80 	TInt err(KErrNone);
       
    81 	TPtrC iniFile(_L(""));
       
    82 	
       
    83 	/* We first check whether KFloggerIniFile (commsdbg.ini) exists,
       
    84 	if it does we use that one, otherwise we use the old KFloggerIniOldFile
       
    85 	(comsdbg.ini) instead (or rather, we try), else copy the default ini file. */
       
    86 	TFindFile ff(iFs);
       
    87 	
       
    88 	err = ff.FindByDir(KFloggerIniFile, KFloggerIniDir);
       
    89 		
       
    90 	if(err != KErrNone)
       
    91 		{
       
    92 			// KFloggerIniFile was not there, lets use KFloggerIniOldFile
       
    93 			err = ff.FindByDir(KFloggerIniOldFile, KFloggerIniDir);
       
    94 		}
       
    95 		
       
    96 	if (err == KErrNone) 
       
    97       {
       
    98       // found the ini file to use, hold on to its name and location
       
    99       iniFile.Set (ff.File ());
       
   100       }
       
   101    else
       
   102 		{
       
   103 		// couldn't find an ini file with the new or old name, lets use ini file in the resource dir
       
   104 		err = ff.FindByDir(KFloggerIniFile, KFloggerIniRscDir);
       
   105 		
       
   106 		// Get the correct system drive letter in a buffer.	
       
   107 		TChar sysDriveLetter = RFs::GetSystemDriveChar();
       
   108 		TBuf<1> sysDriveLetterBuf;
       
   109 		sysDriveLetterBuf.Fill( sysDriveLetter, 1 );
       
   110 			
       
   111        	// Get the full path to the default ini file including the system drive letter.
       
   112 		TBuf<KMaxFileName> dfltIniFullPath( KFloggerDfltIniPartialPath );
       
   113 		dfltIniFullPath.Insert( 0, sysDriveLetterBuf );
       
   114 			
       
   115 		if(err == KErrNone)
       
   116 			{
       
   117 			//only ini file is the default one in z:\resource
       
   118 			CFileMan* fileMan = CFileMan::NewL(iFs);
       
   119 			err = fileMan->Copy(KFloggerIniInROM, dfltIniFullPath, CFileMan::ERecurse);
       
   120 			if (err==KErrNone)
       
   121 				{
       
   122 				err = fileMan->Attribs(dfltIniFullPath,0,KEntryAttReadOnly,TTime(0));
       
   123 		   		iniFile.Set (dfltIniFullPath);
       
   124 				}
       
   125 			delete fileMan;
       
   126 			}
       
   127 		else
       
   128    			{
       
   129 			// Get the full path to the old ini file including the system drive letter.
       
   130 			TBuf<KMaxFileName> dfltIniOldIniFullPath( KFloggerIniOldFilePartialPath );
       
   131 			dfltIniOldIniFullPath.Insert( 0, sysDriveLetterBuf );
       
   132 			
       
   133   			// watch ini file, even tho it isnt there
       
   134    			// also create another file watched to watch for the old file for backward compatibility
       
   135    			iniFile.Set(dfltIniFullPath);
       
   136 	 		iIniOldFileWatcher = CIniFileWatcher::NewL(iFs, *this, dfltIniOldIniFullPath);
       
   137 			}
       
   138 		}
       
   139 	
       
   140 	iIniFileParser = CIniFileParser::NewL(iFs);
       
   141    if (err==KErrNone)	//error getting the ini file or setting attributes
       
   142       {
       
   143    	err=iIniFileParser->ParseIniFile(iniFile);
       
   144       }
       
   145    else
       
   146       {
       
   147       // no default ini file to copy either, so lets just pretend there is an empty file
       
   148       err = KErrNone;
       
   149       }
       
   150 			
       
   151 	// create and set in motion the second thread
       
   152 	// we can only create the second thread thread once we know whether we are running
       
   153 	// synchronous or not. If we still don't know, then we'll force it to false.
       
   154 	// When flogger first starts, the flush setting is not known because the ini file
       
   155 	// parsing may fail. However, once client's start calling this function, we must
       
   156 	// decide whether to flush or not since it is not easy to switch from
       
   157 	// non-flushing to flushing. Thus, instead, the first time this function
       
   158 	// is called, we make a decision
       
   159 	iIniFileParser->FinaliseFlushSetting();
       
   160 	TBool currentFlushSetting;
       
   161 	iIniFileParser->FlushingOn(currentFlushSetting);
       
   162 	// the second thread needs to have been created before we need to place anything
       
   163 	// into the log queue, since the 2nd thread contains the semaphore we are using
       
   164 	// to count the # of mesgs in the queue.
       
   165 	iSecondaryThread = CSecondaryThread::NewL(*this,currentFlushSetting);
       
   166 
       
   167 	// update the media regardless of whether the parsing worked
       
   168 	// since we need to get the default set if needs be.
       
   169 	UpdateMediaL();
       
   170 	
       
   171 	if (err!=KErrNone)	//Problem with ini file reading. Stick a message in the log...
       
   172 		{
       
   173 		CLogCommentMessage* message = CLogCommentMessage::NewL(KIniFileProblem);
       
   174 		err = AppendAndGiveOwnership(message);
       
   175 		if (err != KErrNone)
       
   176 			{
       
   177 			delete message;
       
   178 			User::Leave(err);
       
   179 			}
       
   180 		}
       
   181 
       
   182 	iIniFileWatcher = CIniFileWatcher::NewL(iFs, *this, iniFile);
       
   183 	iTimeManager = CTimeManager::NewL(*this);
       
   184 	}
       
   185 
       
   186 void CFileLoggerServer::UpdateMediaL()
       
   187 	{
       
   188 	CMediaUpdateMessage* message = new(ELeave) CMediaUpdateMessage(*iIniFileParser);
       
   189 	CleanupStack::PushL(message);
       
   190 	if (AppendAndGiveOwnership(message)!=KErrNone)	//Problem => Leave media as it was.
       
   191 		{
       
   192 		CleanupStack::Pop(message);
       
   193 		delete message;
       
   194 		return;
       
   195 		}
       
   196 	CleanupStack::Pop(message);
       
   197 	}
       
   198 
       
   199 CFileLoggerServer::~CFileLoggerServer()
       
   200 	{
       
   201 	delete iSecondaryThread;
       
   202 	delete iTimeManager;
       
   203 	delete iIniFileWatcher;
       
   204 	delete iIniOldFileWatcher;
       
   205 	delete iIniFileParser;
       
   206 	delete iPreAllocatedErrorMessage;
       
   207 	iFs.Close();
       
   208 	iCriticalSection.Close();
       
   209 	iCompletionSemaphore.Close();
       
   210 	iLogMessageArray.ResetAndDestroy();
       
   211 #if defined (__WINS__)
       
   212 	delete iDebugWriter;
       
   213 #endif
       
   214 	}
       
   215 
       
   216 
       
   217 CSession2* CFileLoggerServer::NewSessionL(const TVersion &aVersion ,const RMessage2& /*aMessage*/) const
       
   218 /**
       
   219  * Create a new server session. Check that client is using current or older interface and make a new session.
       
   220  * @note Called by kernel after RFileLogger::DoConnect().
       
   221  */
       
   222 	{
       
   223 
       
   224 	TVersion v(KFLogSrvMajorVersionNumber,KFLogSrvMinorVersionNumber,KFLogSrvBuildVersionNumber);
       
   225 	if (!User::QueryVersionSupported(v,aVersion))
       
   226 		{
       
   227 		User::Leave(KErrNotSupported);
       
   228 		}
       
   229 		
       
   230 	return CFileLogSession::NewL(*(const_cast<CFileLoggerServer*>(this)), *iIniFileParser);
       
   231 	}
       
   232 
       
   233 void CFileLoggerServer::RePrepareForOOML()
       
   234 /**
       
   235  * Called to ensure there is space for the OOM error msg in log queue.
       
   236  */
       
   237 	{
       
   238 	if (!iPreAllocatedErrorMessage)
       
   239 		{
       
   240 		iPreAllocatedErrorMessage = CLogCommentMessage::NewL(KOOMErrorString);
       
   241 		}
       
   242 	//Must reserve 1 space in array for error handling or leave.
       
   243 	User::LeaveIfError(iLogMessageArray.Append(NULL));
       
   244 	//We've got everything we need should we hit an OOM to guarentee we can get an error in the log.
       
   245 	iArrayHasSpaceForWrite=ETrue;
       
   246 	}
       
   247 
       
   248 TInt CFileLoggerServer::AppendAndGiveOwnership(CLogMessageBase* aMessage)	
       
   249 /**
       
   250  * Append a log package to the queue end.
       
   251  * @note Entry only allowed for primary (producer) thread.
       
   252  * @note If win32 and debug port logging on, package is written immediately to the debug port as well.
       
   253  * @note If no space has been allocated for the OOM error msg, then this is done first.
       
   254  * @note If flushing (synchronous) operation then waits for completion.
       
   255  @return KErrNoMemory
       
   256  */
       
   257 	{
       
   258 	iCriticalSection.Wait();
       
   259 #if defined (__WINS__)
       
   260 	if (iIniFileParser->Win32DebugEnabled())
       
   261 		{
       
   262 		aMessage->Invoke(*iDebugWriter);
       
   263 		}
       
   264 #endif
       
   265 	TInt err(KErrNone);
       
   266 	if (!iArrayHasSpaceForWrite) 	//We ran into low memmory a while ago, time to get set up again.
       
   267 									//iArrayHasSpaceForWrite==ETrue <==> 1 free slot in the array
       
   268 									//iArrayHasSpaceForWrite==EFalse <==> 0 free slots in the array
       
   269 									//Above  MUST be true or we'll go horribly wrong!!
       
   270 									//RePrepareForOOML must be done in CS since we'll be mucking about with the array.
       
   271 		{
       
   272 		TRAP(err, RePrepareForOOML());
       
   273 		if (err!=KErrNone)
       
   274 			{
       
   275 			iCriticalSection.Signal();
       
   276 			return err;
       
   277 			}
       
   278 		}
       
   279 	//If we get to here then we must have 1 space in the array. First try to expand
       
   280 	//then if that works stick the message in the array, otherwise return error.
       
   281 	if ((err = iLogMessageArray.Append(NULL))==KErrNone)
       
   282 		{
       
   283 		const TInt arrayCount(iLogMessageArray.Count());
       
   284 		iLogMessageArray[arrayCount-2] = aMessage;
       
   285 		iSecondaryThread->SignalRequestSemaphore();
       
   286 		}
       
   287 	iCriticalSection.Signal();
       
   288 
       
   289 	if (err==KErrNone)
       
   290 		{
       
   291 		TBool flushSetting;
       
   292 		iIniFileParser->FlushingOn(flushSetting);
       
   293 
       
   294 		if (flushSetting == EFlushOn)
       
   295 			{
       
   296 			iCompletionSemaphore.Wait(); // one for each signal of the request semaphore
       
   297 			}
       
   298 		}
       
   299 	return err;
       
   300 	}
       
   301 
       
   302 void CFileLoggerServer::PutOOMErrorInLog()
       
   303 	{
       
   304 	//Best attempt to put error in log, if there's no space then we can't
       
   305 	//We don't try to allocate space in the array. The reasons for this are left as
       
   306 	//an excercise to whomever is unfortunate enough to be trying to debug this.
       
   307 	//Basically, this is the only place the last slot of the array can ever be filled,
       
   308 	//so if iArrayHasSpaceForWrite==EFalse we're guaranteed to have got an error in the
       
   309 	//log already earlier on, and since
       
   310 	//in the AppendAndGiveOwnership method we fail if we cant realocate the error message
       
   311 	//we're guarenteed that the last line in the log is and error message already.
       
   312 	if (iArrayHasSpaceForWrite)
       
   313 		{
       
   314 		iCriticalSection.Wait();
       
   315 		const TInt arrayCount(iLogMessageArray.Count());
       
   316 		iLogMessageArray[arrayCount-1] = iPreAllocatedErrorMessage;
       
   317 		iPreAllocatedErrorMessage=NULL;
       
   318 		iArrayHasSpaceForWrite=EFalse;
       
   319 		iCriticalSection.Signal();
       
   320 		iSecondaryThread->SignalRequestSemaphore();
       
   321 
       
   322 		TBool flushSetting;
       
   323 		iIniFileParser->FlushingOn(flushSetting);
       
   324 
       
   325 		if (flushSetting == EFlushOn)
       
   326 			{
       
   327 			iCompletionSemaphore.Wait(); // one for each signal of the request semaphore
       
   328 			}
       
   329 
       
   330 		}
       
   331 
       
   332 	}
       
   333 
       
   334 
       
   335 void CFileLoggerServer::GetFirstMessageAndTakeOwnership(CLogMessageBase*& aMessage)	
       
   336 /*
       
   337  * Remove the message at the head of the log queue.
       
   338  * @note Entry only allowed for secondary (consumer) thread.
       
   339  * @note Blocks if no messages in the log queue.
       
   340  */
       
   341 
       
   342 	{
       
   343 	// Wait on the request semaphore, since we are using that to communicate the number of
       
   344 	// outstanding log items in the queue.
       
   345 	User::WaitForAnyRequest();
       
   346 	iCriticalSection.Wait();
       
   347 	aMessage = iLogMessageArray[0];
       
   348 	iLogMessageArray.Remove(0);
       
   349 	iCriticalSection.Signal();
       
   350 	}
       
   351 
       
   352 
       
   353 
       
   354 void CFileLoggerServer::SignalCompletionSemaphore()
       
   355 // signal the completion semaphore. Called by the slave/consumer thread when it is
       
   356 // done with the current message. Since the slave thread doesn't know if flushing
       
   357 // is on, it will call this regardless of whether we actually need to signal the
       
   358 // semphore or not.
       
   359 	{
       
   360 
       
   361 	TBool flushSetting;
       
   362 	iIniFileParser->FlushingOn(flushSetting);
       
   363 
       
   364 	if (flushSetting == EFlushOn)
       
   365 		{
       
   366 		iCompletionSemaphore.Signal();
       
   367 		}
       
   368 	}
       
   369 
       
   370 
       
   371 
       
   372 TInt CFileLoggerServer::RunError(TInt aError)
       
   373 /**
       
   374  * Leave has occured in CFileLogSession::ServiceL.
       
   375  * Usually this is because the appending of the message to the queue has failed
       
   376  * due to the queue being filled.
       
   377  */
       
   378 	{
       
   379 	PutOOMErrorInLog();
       
   380 	return CServer2::RunError(aError);
       
   381 	}
       
   382 
       
   383 
       
   384 void CFileLoggerServer::IniFileChanged(TDesC &aIniFile)
       
   385 /**
       
   386 Called by the file watcher when the ini file changes.
       
   387 Any OOM problems are ignored
       
   388 */
       
   389 	{
       
   390 	CLogCommentMessage* message = NULL;
       
   391 	TRAPD(err, message = CLogCommentMessage::NewL(KIniFileUpdate))
       
   392 	if ((err == KErrNone) && (message))
       
   393 		{
       
   394 		err = AppendAndGiveOwnership(message);
       
   395 		if (err != KErrNone)
       
   396 			{
       
   397 			delete message;
       
   398 			}
       
   399 		}
       
   400 	err = iIniFileParser->ParseIniFile (aIniFile);
       
   401 
       
   402 	// update media regardless of success, since we may want to
       
   403 	// set the default media. update media will only leave if memory full.
       
   404 	// in which case we cant output an error msg anyway.
       
   405 	TRAPD(err2, UpdateMediaL());
       
   406 	
       
   407 	if (err!=KErrNone)	//problem parsing ini file, leave settings as they are and carry on.
       
   408 		{
       
   409 		CLogCommentMessage* message = NULL;
       
   410 		TRAP(err, message = CLogCommentMessage::NewL(KIniFileProblem))
       
   411 		if ((err == KErrNone) && (message))
       
   412 			{
       
   413 			err = AppendAndGiveOwnership(message);
       
   414 			if (err != KErrNone)
       
   415 				{
       
   416 				delete message;
       
   417 				}
       
   418 			}
       
   419 		return;
       
   420 		} 
       
   421 	else if (err2 != KErrNone)
       
   422 		{
       
   423 		// memory full, but cant even output msg to say this
       
   424 		}
       
   425 
       
   426 
       
   427 	//Ignore error. Above can only fail due to OOM, so carry on regardless.
       
   428 	CSession2* p=NULL;
       
   429 	iSessionIter.SetToFirst();
       
   430 	while ((p=iSessionIter++)!=NULL)
       
   431 		{
       
   432 		static_cast<CFileLogSession*>(p)->IniFileChanged();
       
   433 		}
       
   434 	}
       
   435 
       
   436 #ifdef _DEBUG
       
   437 void CFileLoggerServer::__DbgKillTimeManager()
       
   438 	{
       
   439 	delete iTimeManager;
       
   440 	iTimeManager=NULL;
       
   441 	}
       
   442 #endif	//_DEBUG
       
   443 //
       
   444 // CFileLogSession class definition
       
   445 //
       
   446 
       
   447 CFileLogSession* CFileLogSession::NewL(MLogArrayAccess& aArrayAccess, const MIniFlushModeAndLogValidQuery& aLogValidQuery)
       
   448 /**
       
   449  * Construct new server end of session.
       
   450  * @note Only called from CFileLoggerServer::NewSessionL()
       
   451  */
       
   452 	{
       
   453 
       
   454 	CFileLogSession* self = new(ELeave) CFileLogSession(aArrayAccess, aLogValidQuery);
       
   455 	return self;
       
   456 	}
       
   457 
       
   458 CFileLogSession::CFileLogSession(MLogArrayAccess& aArrayAccess, const MIniFlushModeAndLogValidQuery& aLogValidQuery)
       
   459 	: iArrayAccess(aArrayAccess), iFlushModeLogValidQuery(aLogValidQuery), iLogValid(KLoggingOnOffDefault)
       
   460 	{}
       
   461 
       
   462 
       
   463 CFileLogSession::~CFileLogSession()
       
   464 	{
       
   465 	}
       
   466 
       
   467 void CFileLogSession::ServiceL(const RMessage2& aMessage)
       
   468 /**
       
   469  * Processes message from client-side (RFileLogger)
       
   470  * @note Most messages result in logs being added to the queue. If
       
   471  * synchronous logging is on, this function will wait until the queue is then emptied.
       
   472  */
       
   473 	{
       
   474 	RThread clientThread;
       
   475 	TBool flushOn;
       
   476 	iFlushModeLogValidQuery.FlushingOn(flushOn);
       
   477 
       
   478 	// All of the common & performance-critical requests need the client thread id. Note that RFileLogger
       
   479 	// sessions are shareable; the thread now logging may be other than that which created the session
       
   480 	User::LeaveIfError(aMessage.Client(clientThread));
       
   481 	iThreadId = clientThread.Id();
       
   482 
       
   483 
       
   484 
       
   485 	switch(aMessage.Function())
       
   486 		{
       
   487 		case EStaticWriteToLog:
       
   488 			{
       
   489 			aMessage.ReadL(0, iSubsystem);
       
   490 			aMessage.ReadL(1, iComponent);
       
   491 			if (iFlushModeLogValidQuery.LogValid(iSubsystem, iComponent))
       
   492 				{
       
   493 				HBufC8* stringOnHeap =  HBufC8::NewLC(aMessage.Int3());
       
   494 				TPtr8 ptrToString(stringOnHeap->Des());
       
   495 				aMessage.ReadL(2, ptrToString);
       
   496 				if (!flushOn)
       
   497 					{
       
   498 					//We're done with the client now, so we can complete its request.
       
   499 					aMessage.Complete(KErrNone);
       
   500 					}
       
   501 				CLogStringMessage* logMessage = new(ELeave) CLogStringMessage(stringOnHeap, iSubsystem, iComponent, iThreadId);
       
   502 				CleanupStack::Pop(stringOnHeap);
       
   503 				TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage);
       
   504 				if(err != KErrNone)
       
   505 					{
       
   506 					delete logMessage;
       
   507 					User::Leave(err);
       
   508 					}
       
   509 				if (flushOn)
       
   510 					{
       
   511 					aMessage.Complete(KErrNone);
       
   512 					}
       
   513 				}
       
   514 			else
       
   515 				{
       
   516 				//We've done with the client now, so we can complete it's request.
       
   517 				aMessage.Complete(KErrNone);
       
   518 				}
       
   519 			break;
       
   520 			} 
       
   521 		case EClearLog:
       
   522 			{
       
   523 			CheckClientHasSetTagsL(aMessage);
       
   524 			CClearLogMessage* clearLogMessage = new(ELeave) CClearLogMessage(clientThread.FullName());
       
   525 			TInt err = iArrayAccess.AppendAndGiveOwnership(clearLogMessage);
       
   526 			if(err != KErrNone)
       
   527 				{
       
   528 				delete clearLogMessage;
       
   529 				User::Leave(err);
       
   530 				}
       
   531 			aMessage.Complete(KErrNone);
       
   532 			break;
       
   533 			}
       
   534 		case ESetLogTag:
       
   535 			{
       
   536 			aMessage.ReadL(0, iSubsystem);
       
   537 			aMessage.ReadL(1, iComponent);
       
   538 			iSetLogMessage = aMessage;
       
   539 			SetLoggingOnOffInClient();
       
   540 			aMessage.Complete(KErrNone);
       
   541 			break;
       
   542 			}
       
   543 		case EWriteToLog:
       
   544 			{
       
   545 			CheckClientHasSetTagsL(aMessage);
       
   546 			HBufC8* stringOnHeap =  HBufC8::NewLC(aMessage.Int1());
       
   547 			TPtr8 ptrToString(stringOnHeap->Des());
       
   548 			aMessage.ReadL(0, ptrToString);
       
   549 			if (!flushOn)
       
   550 				{
       
   551 				//We're done with the client now, so we can complete its request.
       
   552 				aMessage.Complete(KErrNone);
       
   553 				}
       
   554 			CLogStringMessage* logMessage = new(ELeave) CLogStringMessage(stringOnHeap, iSubsystem, iComponent, iThreadId);
       
   555 			CleanupStack::Pop(stringOnHeap);//Above call takes ownership of stringOnHeap
       
   556 			TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage);
       
   557 			if(err != KErrNone)
       
   558 				{
       
   559 				delete logMessage;
       
   560 				User::Leave(err);
       
   561 				}
       
   562 			if (flushOn)
       
   563 				{
       
   564 				aMessage.Complete(KErrNone);
       
   565 				}
       
   566 			
       
   567 			break;
       
   568 			}
       
   569 		case EWriteBinary:
       
   570 			{
       
   571 			CheckClientHasSetTagsL(aMessage);
       
   572 			HBufC8* stringOnHeap = HBufC8::NewLC(aMessage.Int1());
       
   573 			TPtr8 ptrToString(stringOnHeap->Des());
       
   574 			aMessage.ReadL(0, ptrToString);
       
   575 			CLogBinaryString* logMessage = new(ELeave) CLogBinaryString(stringOnHeap, iSubsystem, iComponent);
       
   576 			CleanupStack::Pop(stringOnHeap);//Above call takes ownership of stringOnHeap
       
   577 			if (!flushOn)
       
   578 				{
       
   579 				//We're done with the client now, so we can complete its request.
       
   580 				aMessage.Complete(KErrNone);
       
   581 				}
       
   582 
       
   583 			TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage);
       
   584 			if(err != KErrNone)
       
   585 				{
       
   586 				delete logMessage;
       
   587 				User::Leave(err);
       
   588 				}
       
   589 			if (flushOn)
       
   590 				{
       
   591 				aMessage.Complete(KErrNone);
       
   592 				}
       
   593 			break;
       
   594 			}
       
   595 #ifdef _DEBUG	//These methods are only accessible in debug.
       
   596 		case EShutDownServer:
       
   597 			{
       
   598 			CActiveScheduler::Stop();
       
   599 			aMessage.Complete(KErrNone);
       
   600 			break;
       
   601 			}
       
   602 		case ESetHeapFailure:
       
   603 			{
       
   604 			//we need to stop the timer otherwise server will
       
   605 			//keep allocing when we're doing heap failure test which makes the test fail.
       
   606 			const_cast<CFileLoggerServer*>(static_cast<const CFileLoggerServer*>(Server()))->__DbgKillTimeManager();
       
   607 			__UHEAP_FAILNEXT(aMessage.Int0());
       
   608 			aMessage.Complete(KErrNone);
       
   609 			break;
       
   610 			}
       
   611 #endif	//_DEBUG	
       
   612 		default:
       
   613 			{
       
   614  			aMessage.Panic(KFloggerServerPanic, EBadMessageFunction);
       
   615 			}
       
   616 		}
       
   617 	clientThread.Close();
       
   618 	}
       
   619 
       
   620 void CFileLogSession::CheckClientHasSetTagsL(const RMessage2& aMessage)
       
   621 /**
       
   622  * Ensure for a connection that the client has set the tags, otherwise panic.
       
   623  * @param aMessage the current client message in progress
       
   624  * @note Tags are kept server side so that we don't need to store the tags in the client and pass them through with each request.
       
   625  */
       
   626 
       
   627 	{
       
   628 	if (iSetLogMessage.IsNull())
       
   629 		{
       
   630 		aMessage.Panic(KFloggerPanic, ESetLogTagsNotCalled);	//Client ain't called set log tags.
       
   631 		User::Leave(KErrGeneral);
       
   632 		}
       
   633 
       
   634 	}
       
   635 
       
   636 void CFileLogSession::SetLoggingOnOffInClient()
       
   637 	{
       
   638 	const TBool currentLoggingOnOffState = iLogValid;
       
   639 	iLogValid = iFlushModeLogValidQuery.LogValid(iSubsystem, iComponent);
       
   640 	if (currentLoggingOnOffState!=iLogValid)	//Logging on/off has changed. Set state in client
       
   641 		{
       
   642 		// ignore the error returned
       
   643 		(void)iSetLogMessage.Write(2, TPckgBuf<TBool>(iLogValid));
       
   644 		}
       
   645 	}
       
   646 
       
   647 void CFileLogSession::IniFileChanged()
       
   648 	//We only need to update clients that have called SetLogTags
       
   649 	//We don't update clients that are using the static API client side.
       
   650 	{
       
   651 	if (!iSetLogMessage.IsNull())
       
   652 		{
       
   653 		SetLoggingOnOffInClient();
       
   654 		}
       
   655 	}
       
   656 
       
   657 /////////////////////////////////////////////////////////////////
       
   658 
       
   659 CSecondaryThread* CSecondaryThread::NewL(MLogArrayAccess& aArrayAccess, TBool aFlushOn)
       
   660 	{
       
   661 	CSecondaryThread* self = new(ELeave) CSecondaryThread(aArrayAccess,aFlushOn);
       
   662 	CleanupStack::PushL(self);
       
   663 	self->ConstructL();
       
   664 	CleanupStack::Pop(self);
       
   665 	return self;
       
   666 	}
       
   667 
       
   668 CSecondaryThread::CSecondaryThread(MLogArrayAccess& aArrayAccess, TBool aFlushOn)
       
   669 : CActive(EPriorityHigh), iArrayAccess(aArrayAccess), iFlushingOn(aFlushOn)
       
   670 	{}
       
   671 
       
   672 void CSecondaryThread::RunL()
       
   673 /**
       
   674  * Runs when second thread dies, and simply restarts it again.
       
   675  * @note On death a thread-death message is placed in the queue so that
       
   676  * a user is aware this happened.
       
   677  * @note StartSecondaryThread issues a request to be informed of thread death,
       
   678  * so starts active object again.
       
   679  */
       
   680 	{
       
   681 	StartSecondaryThreadL(ETrue);
       
   682 	}
       
   683 
       
   684 void CSecondaryThread::DoCancel()
       
   685 /**
       
   686  * Appends a special shutdown message into the log array. When this reaches
       
   687  * the head and is run, it shuts down the second thread.
       
   688  * @note Logs onto second thread and waits for it to finish.
       
   689  */
       
   690 
       
   691 	{
       
   692 	iSecondaryThread.LogonCancel(iStatus);
       
   693 	if (iArrayAccess.AppendAndGiveOwnership(iShutDownMessage)!=KErrNone)
       
   694 		{	//Nothing else we can do here. We'll have to just kill the other thread.
       
   695 		iSecondaryThread.Kill(KErrGeneral);
       
   696 		}
       
   697 	else
       
   698 		{
       
   699 		iShutDownMessage = NULL;
       
   700 		TRequestStatus status(KRequestPending);
       
   701 		iSecondaryThread.Logon(status);
       
   702 		User::WaitForRequest(status);
       
   703 		}
       
   704 	}
       
   705 
       
   706 void CSecondaryThread::StartSecondaryThreadL(TBool aRestarting)
       
   707 /**
       
   708  * Start the second/consumer/slave thread and issue a request to be told when it dies.
       
   709  */
       
   710 	{
       
   711 	TRequestStatus stat;
       
   712 	
       
   713 	User::LeaveIfError(iSecondaryThread.Create(KFloggerSecondaryThreadName,CLogManager::ThreadEntryPoint,KDefaultStackSize,NULL,&iArrayAccess));
       
   714 
       
   715 	iSecondaryThread.Rendezvous(stat);
       
   716 
       
   717 	if (iFlushingOn)
       
   718 		{
       
   719 		iSecondaryThread.SetPriority(EPriorityAbsoluteHigh);  //was EPriorityMuchMore
       
   720 		} 
       
   721 	else
       
   722 		{
       
   723 		iSecondaryThread.SetPriority(EPriorityAbsoluteForeground);  // was EPriorityMuchLess
       
   724 		}
       
   725 
       
   726 	iSecondaryThread.Resume();
       
   727 
       
   728 	User::WaitForRequest(stat);
       
   729 
       
   730 	iSecondaryThread.Logon(iStatus);
       
   731 
       
   732 	if (aRestarting)
       
   733 		{	
       
   734 		CLogCommentMessage* errorMessage = CLogCommentMessage::NewL(KThreadDiedString);
       
   735 		TInt err = iArrayAccess.AppendAndGiveOwnership(errorMessage);
       
   736 		if(err != KErrNone)
       
   737 			{
       
   738 			delete errorMessage;
       
   739 			User::Leave(err);
       
   740 			}
       
   741 		}
       
   742 		
       
   743 	SetActive();
       
   744 
       
   745 	}
       
   746 
       
   747 void CSecondaryThread::ConstructL()
       
   748 /**
       
   749  * Contructs and kicks off the secondary thread, while also issuing a request to be informed
       
   750  * if the thread dies, which will run the active object
       
   751  */
       
   752 	{
       
   753 	CActiveScheduler::Add(this);
       
   754 	//Preallocate a shutdown message 
       
   755 	iShutDownMessage = new(ELeave) CShutDownMessage;
       
   756 
       
   757 	StartSecondaryThreadL(EFalse);
       
   758 	}
       
   759 
       
   760 TInt CSecondaryThread::RunError(TInt /*aError*/)
       
   761 	{
       
   762 	CActiveScheduler::Stop();	//What the hell happened! Shut the server down
       
   763 	return KErrNone;
       
   764 	}
       
   765 
       
   766 CSecondaryThread::~CSecondaryThread()
       
   767 	{
       
   768 	Cancel();
       
   769 	delete iShutDownMessage;
       
   770 	iSecondaryThread.Close();
       
   771 	}
       
   772