os/persistentdata/traceservices/commsdebugutility/SSVR/comsdbgsvr.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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