1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/traceservices/commsdebugutility/SSVR/comsdbgsvr.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,772 @@
1.4 +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// Implements the Flogger server side
1.18 +//
1.19 +//
1.20 +
1.21 +/**
1.22 + @file
1.23 + @internalComponent
1.24 +*/
1.25 +
1.26 +#include "comsdbgsvr.h"
1.27 +#include "comsdbgwriter.h"
1.28 +#include "comsdbgstd.h"
1.29 +#include "comsdbgmessages.h"
1.30 +
1.31 +_LIT8(KOOMErrorString, "#Logs may be lost out of memory!! Further OOM conditions may not be recorded.\r\n");
1.32 +_LIT8(KThreadDiedString, "#Something caused the secondary thread in comsdbgutil to die.\r\n");
1.33 +_LIT8(KIniFileProblem, "#There is a problem with the ini file\r\n");
1.34 +_LIT8(KIniFileUpdate, "#Ini file changes detected and noted.\r\n");
1.35 +_LIT(KFloggerSecondaryThreadName, "Comsdbg2");
1.36 +
1.37 +
1.38 +
1.39 +
1.40 +
1.41 +//
1.42 +// CFileLoggerServer class definition
1.43 +//
1.44 +
1.45 +
1.46 +CFileLoggerServer* CFileLoggerServer::NewL()
1.47 + {
1.48 +
1.49 + CFileLoggerServer* r=new(ELeave) CFileLoggerServer();
1.50 + CleanupStack::PushL(r);
1.51 + r->ConstructL();
1.52 + r->StartL(KFLoggerServerName);
1.53 + CleanupStack::Pop();
1.54 + return r;
1.55 + }
1.56 +
1.57 +CFileLoggerServer::CFileLoggerServer()
1.58 + : CServer2(EPriorityNormal,ESharableSessions)
1.59 + {}
1.60 +
1.61 +void CFileLoggerServer::ConstructL()
1.62 +/**
1.63 + *
1.64 + * @note Constructs the secondary thread, passing through a pointer to the log queue.
1.65 + * Constructs the file parser object and parses the file, attempting to copy the
1.66 + * file from the ROM if it is not found on C drive.
1.67 + * Constructs the time beat.
1.68 + * Performs the first UpdateMedia to ensure a media is set.
1.69 + */
1.70 + {
1.71 + User::LeaveIfError(iCriticalSection.CreateLocal());
1.72 + User::LeaveIfError(iCompletionSemaphore.CreateLocal(0));
1.73 + User::LeaveIfError(iFs.Connect());
1.74 +
1.75 +#if defined (__WINS__)
1.76 + iDebugWriter = CDebugPortProtocol::NewL();
1.77 +#endif
1.78 +
1.79 + User::LeaveIfError(iLogMessageArray.Append(NULL));
1.80 + iPreAllocatedErrorMessage = CLogCommentMessage::NewL(KOOMErrorString);
1.81 + iArrayHasSpaceForWrite = ETrue;
1.82 +
1.83 + TInt err(KErrNone);
1.84 + TPtrC iniFile(_L(""));
1.85 +
1.86 + /* We first check whether KFloggerIniFile (commsdbg.ini) exists,
1.87 + if it does we use that one, otherwise we use the old KFloggerIniOldFile
1.88 + (comsdbg.ini) instead (or rather, we try), else copy the default ini file. */
1.89 + TFindFile ff(iFs);
1.90 +
1.91 + err = ff.FindByDir(KFloggerIniFile, KFloggerIniDir);
1.92 +
1.93 + if(err != KErrNone)
1.94 + {
1.95 + // KFloggerIniFile was not there, lets use KFloggerIniOldFile
1.96 + err = ff.FindByDir(KFloggerIniOldFile, KFloggerIniDir);
1.97 + }
1.98 +
1.99 + if (err == KErrNone)
1.100 + {
1.101 + // found the ini file to use, hold on to its name and location
1.102 + iniFile.Set (ff.File ());
1.103 + }
1.104 + else
1.105 + {
1.106 + // couldn't find an ini file with the new or old name, lets use ini file in the resource dir
1.107 + err = ff.FindByDir(KFloggerIniFile, KFloggerIniRscDir);
1.108 +
1.109 + // Get the correct system drive letter in a buffer.
1.110 + TChar sysDriveLetter = RFs::GetSystemDriveChar();
1.111 + TBuf<1> sysDriveLetterBuf;
1.112 + sysDriveLetterBuf.Fill( sysDriveLetter, 1 );
1.113 +
1.114 + // Get the full path to the default ini file including the system drive letter.
1.115 + TBuf<KMaxFileName> dfltIniFullPath( KFloggerDfltIniPartialPath );
1.116 + dfltIniFullPath.Insert( 0, sysDriveLetterBuf );
1.117 +
1.118 + if(err == KErrNone)
1.119 + {
1.120 + //only ini file is the default one in z:\resource
1.121 + CFileMan* fileMan = CFileMan::NewL(iFs);
1.122 + err = fileMan->Copy(KFloggerIniInROM, dfltIniFullPath, CFileMan::ERecurse);
1.123 + if (err==KErrNone)
1.124 + {
1.125 + err = fileMan->Attribs(dfltIniFullPath,0,KEntryAttReadOnly,TTime(0));
1.126 + iniFile.Set (dfltIniFullPath);
1.127 + }
1.128 + delete fileMan;
1.129 + }
1.130 + else
1.131 + {
1.132 + // Get the full path to the old ini file including the system drive letter.
1.133 + TBuf<KMaxFileName> dfltIniOldIniFullPath( KFloggerIniOldFilePartialPath );
1.134 + dfltIniOldIniFullPath.Insert( 0, sysDriveLetterBuf );
1.135 +
1.136 + // watch ini file, even tho it isnt there
1.137 + // also create another file watched to watch for the old file for backward compatibility
1.138 + iniFile.Set(dfltIniFullPath);
1.139 + iIniOldFileWatcher = CIniFileWatcher::NewL(iFs, *this, dfltIniOldIniFullPath);
1.140 + }
1.141 + }
1.142 +
1.143 + iIniFileParser = CIniFileParser::NewL(iFs);
1.144 + if (err==KErrNone) //error getting the ini file or setting attributes
1.145 + {
1.146 + err=iIniFileParser->ParseIniFile(iniFile);
1.147 + }
1.148 + else
1.149 + {
1.150 + // no default ini file to copy either, so lets just pretend there is an empty file
1.151 + err = KErrNone;
1.152 + }
1.153 +
1.154 + // create and set in motion the second thread
1.155 + // we can only create the second thread thread once we know whether we are running
1.156 + // synchronous or not. If we still don't know, then we'll force it to false.
1.157 + // When flogger first starts, the flush setting is not known because the ini file
1.158 + // parsing may fail. However, once client's start calling this function, we must
1.159 + // decide whether to flush or not since it is not easy to switch from
1.160 + // non-flushing to flushing. Thus, instead, the first time this function
1.161 + // is called, we make a decision
1.162 + iIniFileParser->FinaliseFlushSetting();
1.163 + TBool currentFlushSetting;
1.164 + iIniFileParser->FlushingOn(currentFlushSetting);
1.165 + // the second thread needs to have been created before we need to place anything
1.166 + // into the log queue, since the 2nd thread contains the semaphore we are using
1.167 + // to count the # of mesgs in the queue.
1.168 + iSecondaryThread = CSecondaryThread::NewL(*this,currentFlushSetting);
1.169 +
1.170 + // update the media regardless of whether the parsing worked
1.171 + // since we need to get the default set if needs be.
1.172 + UpdateMediaL();
1.173 +
1.174 + if (err!=KErrNone) //Problem with ini file reading. Stick a message in the log...
1.175 + {
1.176 + CLogCommentMessage* message = CLogCommentMessage::NewL(KIniFileProblem);
1.177 + err = AppendAndGiveOwnership(message);
1.178 + if (err != KErrNone)
1.179 + {
1.180 + delete message;
1.181 + User::Leave(err);
1.182 + }
1.183 + }
1.184 +
1.185 + iIniFileWatcher = CIniFileWatcher::NewL(iFs, *this, iniFile);
1.186 + iTimeManager = CTimeManager::NewL(*this);
1.187 + }
1.188 +
1.189 +void CFileLoggerServer::UpdateMediaL()
1.190 + {
1.191 + CMediaUpdateMessage* message = new(ELeave) CMediaUpdateMessage(*iIniFileParser);
1.192 + CleanupStack::PushL(message);
1.193 + if (AppendAndGiveOwnership(message)!=KErrNone) //Problem => Leave media as it was.
1.194 + {
1.195 + CleanupStack::Pop(message);
1.196 + delete message;
1.197 + return;
1.198 + }
1.199 + CleanupStack::Pop(message);
1.200 + }
1.201 +
1.202 +CFileLoggerServer::~CFileLoggerServer()
1.203 + {
1.204 + delete iSecondaryThread;
1.205 + delete iTimeManager;
1.206 + delete iIniFileWatcher;
1.207 + delete iIniOldFileWatcher;
1.208 + delete iIniFileParser;
1.209 + delete iPreAllocatedErrorMessage;
1.210 + iFs.Close();
1.211 + iCriticalSection.Close();
1.212 + iCompletionSemaphore.Close();
1.213 + iLogMessageArray.ResetAndDestroy();
1.214 +#if defined (__WINS__)
1.215 + delete iDebugWriter;
1.216 +#endif
1.217 + }
1.218 +
1.219 +
1.220 +CSession2* CFileLoggerServer::NewSessionL(const TVersion &aVersion ,const RMessage2& /*aMessage*/) const
1.221 +/**
1.222 + * Create a new server session. Check that client is using current or older interface and make a new session.
1.223 + * @note Called by kernel after RFileLogger::DoConnect().
1.224 + */
1.225 + {
1.226 +
1.227 + TVersion v(KFLogSrvMajorVersionNumber,KFLogSrvMinorVersionNumber,KFLogSrvBuildVersionNumber);
1.228 + if (!User::QueryVersionSupported(v,aVersion))
1.229 + {
1.230 + User::Leave(KErrNotSupported);
1.231 + }
1.232 +
1.233 + return CFileLogSession::NewL(*(const_cast<CFileLoggerServer*>(this)), *iIniFileParser);
1.234 + }
1.235 +
1.236 +void CFileLoggerServer::RePrepareForOOML()
1.237 +/**
1.238 + * Called to ensure there is space for the OOM error msg in log queue.
1.239 + */
1.240 + {
1.241 + if (!iPreAllocatedErrorMessage)
1.242 + {
1.243 + iPreAllocatedErrorMessage = CLogCommentMessage::NewL(KOOMErrorString);
1.244 + }
1.245 + //Must reserve 1 space in array for error handling or leave.
1.246 + User::LeaveIfError(iLogMessageArray.Append(NULL));
1.247 + //We've got everything we need should we hit an OOM to guarentee we can get an error in the log.
1.248 + iArrayHasSpaceForWrite=ETrue;
1.249 + }
1.250 +
1.251 +TInt CFileLoggerServer::AppendAndGiveOwnership(CLogMessageBase* aMessage)
1.252 +/**
1.253 + * Append a log package to the queue end.
1.254 + * @note Entry only allowed for primary (producer) thread.
1.255 + * @note If win32 and debug port logging on, package is written immediately to the debug port as well.
1.256 + * @note If no space has been allocated for the OOM error msg, then this is done first.
1.257 + * @note If flushing (synchronous) operation then waits for completion.
1.258 + @return KErrNoMemory
1.259 + */
1.260 + {
1.261 + iCriticalSection.Wait();
1.262 +#if defined (__WINS__)
1.263 + if (iIniFileParser->Win32DebugEnabled())
1.264 + {
1.265 + aMessage->Invoke(*iDebugWriter);
1.266 + }
1.267 +#endif
1.268 + TInt err(KErrNone);
1.269 + if (!iArrayHasSpaceForWrite) //We ran into low memmory a while ago, time to get set up again.
1.270 + //iArrayHasSpaceForWrite==ETrue <==> 1 free slot in the array
1.271 + //iArrayHasSpaceForWrite==EFalse <==> 0 free slots in the array
1.272 + //Above MUST be true or we'll go horribly wrong!!
1.273 + //RePrepareForOOML must be done in CS since we'll be mucking about with the array.
1.274 + {
1.275 + TRAP(err, RePrepareForOOML());
1.276 + if (err!=KErrNone)
1.277 + {
1.278 + iCriticalSection.Signal();
1.279 + return err;
1.280 + }
1.281 + }
1.282 + //If we get to here then we must have 1 space in the array. First try to expand
1.283 + //then if that works stick the message in the array, otherwise return error.
1.284 + if ((err = iLogMessageArray.Append(NULL))==KErrNone)
1.285 + {
1.286 + const TInt arrayCount(iLogMessageArray.Count());
1.287 + iLogMessageArray[arrayCount-2] = aMessage;
1.288 + iSecondaryThread->SignalRequestSemaphore();
1.289 + }
1.290 + iCriticalSection.Signal();
1.291 +
1.292 + if (err==KErrNone)
1.293 + {
1.294 + TBool flushSetting;
1.295 + iIniFileParser->FlushingOn(flushSetting);
1.296 +
1.297 + if (flushSetting == EFlushOn)
1.298 + {
1.299 + iCompletionSemaphore.Wait(); // one for each signal of the request semaphore
1.300 + }
1.301 + }
1.302 + return err;
1.303 + }
1.304 +
1.305 +void CFileLoggerServer::PutOOMErrorInLog()
1.306 + {
1.307 + //Best attempt to put error in log, if there's no space then we can't
1.308 + //We don't try to allocate space in the array. The reasons for this are left as
1.309 + //an excercise to whomever is unfortunate enough to be trying to debug this.
1.310 + //Basically, this is the only place the last slot of the array can ever be filled,
1.311 + //so if iArrayHasSpaceForWrite==EFalse we're guaranteed to have got an error in the
1.312 + //log already earlier on, and since
1.313 + //in the AppendAndGiveOwnership method we fail if we cant realocate the error message
1.314 + //we're guarenteed that the last line in the log is and error message already.
1.315 + if (iArrayHasSpaceForWrite)
1.316 + {
1.317 + iCriticalSection.Wait();
1.318 + const TInt arrayCount(iLogMessageArray.Count());
1.319 + iLogMessageArray[arrayCount-1] = iPreAllocatedErrorMessage;
1.320 + iPreAllocatedErrorMessage=NULL;
1.321 + iArrayHasSpaceForWrite=EFalse;
1.322 + iCriticalSection.Signal();
1.323 + iSecondaryThread->SignalRequestSemaphore();
1.324 +
1.325 + TBool flushSetting;
1.326 + iIniFileParser->FlushingOn(flushSetting);
1.327 +
1.328 + if (flushSetting == EFlushOn)
1.329 + {
1.330 + iCompletionSemaphore.Wait(); // one for each signal of the request semaphore
1.331 + }
1.332 +
1.333 + }
1.334 +
1.335 + }
1.336 +
1.337 +
1.338 +void CFileLoggerServer::GetFirstMessageAndTakeOwnership(CLogMessageBase*& aMessage)
1.339 +/*
1.340 + * Remove the message at the head of the log queue.
1.341 + * @note Entry only allowed for secondary (consumer) thread.
1.342 + * @note Blocks if no messages in the log queue.
1.343 + */
1.344 +
1.345 + {
1.346 + // Wait on the request semaphore, since we are using that to communicate the number of
1.347 + // outstanding log items in the queue.
1.348 + User::WaitForAnyRequest();
1.349 + iCriticalSection.Wait();
1.350 + aMessage = iLogMessageArray[0];
1.351 + iLogMessageArray.Remove(0);
1.352 + iCriticalSection.Signal();
1.353 + }
1.354 +
1.355 +
1.356 +
1.357 +void CFileLoggerServer::SignalCompletionSemaphore()
1.358 +// signal the completion semaphore. Called by the slave/consumer thread when it is
1.359 +// done with the current message. Since the slave thread doesn't know if flushing
1.360 +// is on, it will call this regardless of whether we actually need to signal the
1.361 +// semphore or not.
1.362 + {
1.363 +
1.364 + TBool flushSetting;
1.365 + iIniFileParser->FlushingOn(flushSetting);
1.366 +
1.367 + if (flushSetting == EFlushOn)
1.368 + {
1.369 + iCompletionSemaphore.Signal();
1.370 + }
1.371 + }
1.372 +
1.373 +
1.374 +
1.375 +TInt CFileLoggerServer::RunError(TInt aError)
1.376 +/**
1.377 + * Leave has occured in CFileLogSession::ServiceL.
1.378 + * Usually this is because the appending of the message to the queue has failed
1.379 + * due to the queue being filled.
1.380 + */
1.381 + {
1.382 + PutOOMErrorInLog();
1.383 + return CServer2::RunError(aError);
1.384 + }
1.385 +
1.386 +
1.387 +void CFileLoggerServer::IniFileChanged(TDesC &aIniFile)
1.388 +/**
1.389 +Called by the file watcher when the ini file changes.
1.390 +Any OOM problems are ignored
1.391 +*/
1.392 + {
1.393 + CLogCommentMessage* message = NULL;
1.394 + TRAPD(err, message = CLogCommentMessage::NewL(KIniFileUpdate))
1.395 + if ((err == KErrNone) && (message))
1.396 + {
1.397 + err = AppendAndGiveOwnership(message);
1.398 + if (err != KErrNone)
1.399 + {
1.400 + delete message;
1.401 + }
1.402 + }
1.403 + err = iIniFileParser->ParseIniFile (aIniFile);
1.404 +
1.405 + // update media regardless of success, since we may want to
1.406 + // set the default media. update media will only leave if memory full.
1.407 + // in which case we cant output an error msg anyway.
1.408 + TRAPD(err2, UpdateMediaL());
1.409 +
1.410 + if (err!=KErrNone) //problem parsing ini file, leave settings as they are and carry on.
1.411 + {
1.412 + CLogCommentMessage* message = NULL;
1.413 + TRAP(err, message = CLogCommentMessage::NewL(KIniFileProblem))
1.414 + if ((err == KErrNone) && (message))
1.415 + {
1.416 + err = AppendAndGiveOwnership(message);
1.417 + if (err != KErrNone)
1.418 + {
1.419 + delete message;
1.420 + }
1.421 + }
1.422 + return;
1.423 + }
1.424 + else if (err2 != KErrNone)
1.425 + {
1.426 + // memory full, but cant even output msg to say this
1.427 + }
1.428 +
1.429 +
1.430 + //Ignore error. Above can only fail due to OOM, so carry on regardless.
1.431 + CSession2* p=NULL;
1.432 + iSessionIter.SetToFirst();
1.433 + while ((p=iSessionIter++)!=NULL)
1.434 + {
1.435 + static_cast<CFileLogSession*>(p)->IniFileChanged();
1.436 + }
1.437 + }
1.438 +
1.439 +#ifdef _DEBUG
1.440 +void CFileLoggerServer::__DbgKillTimeManager()
1.441 + {
1.442 + delete iTimeManager;
1.443 + iTimeManager=NULL;
1.444 + }
1.445 +#endif //_DEBUG
1.446 +//
1.447 +// CFileLogSession class definition
1.448 +//
1.449 +
1.450 +CFileLogSession* CFileLogSession::NewL(MLogArrayAccess& aArrayAccess, const MIniFlushModeAndLogValidQuery& aLogValidQuery)
1.451 +/**
1.452 + * Construct new server end of session.
1.453 + * @note Only called from CFileLoggerServer::NewSessionL()
1.454 + */
1.455 + {
1.456 +
1.457 + CFileLogSession* self = new(ELeave) CFileLogSession(aArrayAccess, aLogValidQuery);
1.458 + return self;
1.459 + }
1.460 +
1.461 +CFileLogSession::CFileLogSession(MLogArrayAccess& aArrayAccess, const MIniFlushModeAndLogValidQuery& aLogValidQuery)
1.462 + : iArrayAccess(aArrayAccess), iFlushModeLogValidQuery(aLogValidQuery), iLogValid(KLoggingOnOffDefault)
1.463 + {}
1.464 +
1.465 +
1.466 +CFileLogSession::~CFileLogSession()
1.467 + {
1.468 + }
1.469 +
1.470 +void CFileLogSession::ServiceL(const RMessage2& aMessage)
1.471 +/**
1.472 + * Processes message from client-side (RFileLogger)
1.473 + * @note Most messages result in logs being added to the queue. If
1.474 + * synchronous logging is on, this function will wait until the queue is then emptied.
1.475 + */
1.476 + {
1.477 + RThread clientThread;
1.478 + TBool flushOn;
1.479 + iFlushModeLogValidQuery.FlushingOn(flushOn);
1.480 +
1.481 + // All of the common & performance-critical requests need the client thread id. Note that RFileLogger
1.482 + // sessions are shareable; the thread now logging may be other than that which created the session
1.483 + User::LeaveIfError(aMessage.Client(clientThread));
1.484 + iThreadId = clientThread.Id();
1.485 +
1.486 +
1.487 +
1.488 + switch(aMessage.Function())
1.489 + {
1.490 + case EStaticWriteToLog:
1.491 + {
1.492 + aMessage.ReadL(0, iSubsystem);
1.493 + aMessage.ReadL(1, iComponent);
1.494 + if (iFlushModeLogValidQuery.LogValid(iSubsystem, iComponent))
1.495 + {
1.496 + HBufC8* stringOnHeap = HBufC8::NewLC(aMessage.Int3());
1.497 + TPtr8 ptrToString(stringOnHeap->Des());
1.498 + aMessage.ReadL(2, ptrToString);
1.499 + if (!flushOn)
1.500 + {
1.501 + //We're done with the client now, so we can complete its request.
1.502 + aMessage.Complete(KErrNone);
1.503 + }
1.504 + CLogStringMessage* logMessage = new(ELeave) CLogStringMessage(stringOnHeap, iSubsystem, iComponent, iThreadId);
1.505 + CleanupStack::Pop(stringOnHeap);
1.506 + TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage);
1.507 + if(err != KErrNone)
1.508 + {
1.509 + delete logMessage;
1.510 + User::Leave(err);
1.511 + }
1.512 + if (flushOn)
1.513 + {
1.514 + aMessage.Complete(KErrNone);
1.515 + }
1.516 + }
1.517 + else
1.518 + {
1.519 + //We've done with the client now, so we can complete it's request.
1.520 + aMessage.Complete(KErrNone);
1.521 + }
1.522 + break;
1.523 + }
1.524 + case EClearLog:
1.525 + {
1.526 + CheckClientHasSetTagsL(aMessage);
1.527 + CClearLogMessage* clearLogMessage = new(ELeave) CClearLogMessage(clientThread.FullName());
1.528 + TInt err = iArrayAccess.AppendAndGiveOwnership(clearLogMessage);
1.529 + if(err != KErrNone)
1.530 + {
1.531 + delete clearLogMessage;
1.532 + User::Leave(err);
1.533 + }
1.534 + aMessage.Complete(KErrNone);
1.535 + break;
1.536 + }
1.537 + case ESetLogTag:
1.538 + {
1.539 + aMessage.ReadL(0, iSubsystem);
1.540 + aMessage.ReadL(1, iComponent);
1.541 + iSetLogMessage = aMessage;
1.542 + SetLoggingOnOffInClient();
1.543 + aMessage.Complete(KErrNone);
1.544 + break;
1.545 + }
1.546 + case EWriteToLog:
1.547 + {
1.548 + CheckClientHasSetTagsL(aMessage);
1.549 + HBufC8* stringOnHeap = HBufC8::NewLC(aMessage.Int1());
1.550 + TPtr8 ptrToString(stringOnHeap->Des());
1.551 + aMessage.ReadL(0, ptrToString);
1.552 + if (!flushOn)
1.553 + {
1.554 + //We're done with the client now, so we can complete its request.
1.555 + aMessage.Complete(KErrNone);
1.556 + }
1.557 + CLogStringMessage* logMessage = new(ELeave) CLogStringMessage(stringOnHeap, iSubsystem, iComponent, iThreadId);
1.558 + CleanupStack::Pop(stringOnHeap);//Above call takes ownership of stringOnHeap
1.559 + TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage);
1.560 + if(err != KErrNone)
1.561 + {
1.562 + delete logMessage;
1.563 + User::Leave(err);
1.564 + }
1.565 + if (flushOn)
1.566 + {
1.567 + aMessage.Complete(KErrNone);
1.568 + }
1.569 +
1.570 + break;
1.571 + }
1.572 + case EWriteBinary:
1.573 + {
1.574 + CheckClientHasSetTagsL(aMessage);
1.575 + HBufC8* stringOnHeap = HBufC8::NewLC(aMessage.Int1());
1.576 + TPtr8 ptrToString(stringOnHeap->Des());
1.577 + aMessage.ReadL(0, ptrToString);
1.578 + CLogBinaryString* logMessage = new(ELeave) CLogBinaryString(stringOnHeap, iSubsystem, iComponent);
1.579 + CleanupStack::Pop(stringOnHeap);//Above call takes ownership of stringOnHeap
1.580 + if (!flushOn)
1.581 + {
1.582 + //We're done with the client now, so we can complete its request.
1.583 + aMessage.Complete(KErrNone);
1.584 + }
1.585 +
1.586 + TInt err = iArrayAccess.AppendAndGiveOwnership(logMessage);
1.587 + if(err != KErrNone)
1.588 + {
1.589 + delete logMessage;
1.590 + User::Leave(err);
1.591 + }
1.592 + if (flushOn)
1.593 + {
1.594 + aMessage.Complete(KErrNone);
1.595 + }
1.596 + break;
1.597 + }
1.598 +#ifdef _DEBUG //These methods are only accessible in debug.
1.599 + case EShutDownServer:
1.600 + {
1.601 + CActiveScheduler::Stop();
1.602 + aMessage.Complete(KErrNone);
1.603 + break;
1.604 + }
1.605 + case ESetHeapFailure:
1.606 + {
1.607 + //we need to stop the timer otherwise server will
1.608 + //keep allocing when we're doing heap failure test which makes the test fail.
1.609 + const_cast<CFileLoggerServer*>(static_cast<const CFileLoggerServer*>(Server()))->__DbgKillTimeManager();
1.610 + __UHEAP_FAILNEXT(aMessage.Int0());
1.611 + aMessage.Complete(KErrNone);
1.612 + break;
1.613 + }
1.614 +#endif //_DEBUG
1.615 + default:
1.616 + {
1.617 + aMessage.Panic(KFloggerServerPanic, EBadMessageFunction);
1.618 + }
1.619 + }
1.620 + clientThread.Close();
1.621 + }
1.622 +
1.623 +void CFileLogSession::CheckClientHasSetTagsL(const RMessage2& aMessage)
1.624 +/**
1.625 + * Ensure for a connection that the client has set the tags, otherwise panic.
1.626 + * @param aMessage the current client message in progress
1.627 + * @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.
1.628 + */
1.629 +
1.630 + {
1.631 + if (iSetLogMessage.IsNull())
1.632 + {
1.633 + aMessage.Panic(KFloggerPanic, ESetLogTagsNotCalled); //Client ain't called set log tags.
1.634 + User::Leave(KErrGeneral);
1.635 + }
1.636 +
1.637 + }
1.638 +
1.639 +void CFileLogSession::SetLoggingOnOffInClient()
1.640 + {
1.641 + const TBool currentLoggingOnOffState = iLogValid;
1.642 + iLogValid = iFlushModeLogValidQuery.LogValid(iSubsystem, iComponent);
1.643 + if (currentLoggingOnOffState!=iLogValid) //Logging on/off has changed. Set state in client
1.644 + {
1.645 + // ignore the error returned
1.646 + (void)iSetLogMessage.Write(2, TPckgBuf<TBool>(iLogValid));
1.647 + }
1.648 + }
1.649 +
1.650 +void CFileLogSession::IniFileChanged()
1.651 + //We only need to update clients that have called SetLogTags
1.652 + //We don't update clients that are using the static API client side.
1.653 + {
1.654 + if (!iSetLogMessage.IsNull())
1.655 + {
1.656 + SetLoggingOnOffInClient();
1.657 + }
1.658 + }
1.659 +
1.660 +/////////////////////////////////////////////////////////////////
1.661 +
1.662 +CSecondaryThread* CSecondaryThread::NewL(MLogArrayAccess& aArrayAccess, TBool aFlushOn)
1.663 + {
1.664 + CSecondaryThread* self = new(ELeave) CSecondaryThread(aArrayAccess,aFlushOn);
1.665 + CleanupStack::PushL(self);
1.666 + self->ConstructL();
1.667 + CleanupStack::Pop(self);
1.668 + return self;
1.669 + }
1.670 +
1.671 +CSecondaryThread::CSecondaryThread(MLogArrayAccess& aArrayAccess, TBool aFlushOn)
1.672 +: CActive(EPriorityHigh), iArrayAccess(aArrayAccess), iFlushingOn(aFlushOn)
1.673 + {}
1.674 +
1.675 +void CSecondaryThread::RunL()
1.676 +/**
1.677 + * Runs when second thread dies, and simply restarts it again.
1.678 + * @note On death a thread-death message is placed in the queue so that
1.679 + * a user is aware this happened.
1.680 + * @note StartSecondaryThread issues a request to be informed of thread death,
1.681 + * so starts active object again.
1.682 + */
1.683 + {
1.684 + StartSecondaryThreadL(ETrue);
1.685 + }
1.686 +
1.687 +void CSecondaryThread::DoCancel()
1.688 +/**
1.689 + * Appends a special shutdown message into the log array. When this reaches
1.690 + * the head and is run, it shuts down the second thread.
1.691 + * @note Logs onto second thread and waits for it to finish.
1.692 + */
1.693 +
1.694 + {
1.695 + iSecondaryThread.LogonCancel(iStatus);
1.696 + if (iArrayAccess.AppendAndGiveOwnership(iShutDownMessage)!=KErrNone)
1.697 + { //Nothing else we can do here. We'll have to just kill the other thread.
1.698 + iSecondaryThread.Kill(KErrGeneral);
1.699 + }
1.700 + else
1.701 + {
1.702 + iShutDownMessage = NULL;
1.703 + TRequestStatus status(KRequestPending);
1.704 + iSecondaryThread.Logon(status);
1.705 + User::WaitForRequest(status);
1.706 + }
1.707 + }
1.708 +
1.709 +void CSecondaryThread::StartSecondaryThreadL(TBool aRestarting)
1.710 +/**
1.711 + * Start the second/consumer/slave thread and issue a request to be told when it dies.
1.712 + */
1.713 + {
1.714 + TRequestStatus stat;
1.715 +
1.716 + User::LeaveIfError(iSecondaryThread.Create(KFloggerSecondaryThreadName,CLogManager::ThreadEntryPoint,KDefaultStackSize,NULL,&iArrayAccess));
1.717 +
1.718 + iSecondaryThread.Rendezvous(stat);
1.719 +
1.720 + if (iFlushingOn)
1.721 + {
1.722 + iSecondaryThread.SetPriority(EPriorityAbsoluteHigh); //was EPriorityMuchMore
1.723 + }
1.724 + else
1.725 + {
1.726 + iSecondaryThread.SetPriority(EPriorityAbsoluteForeground); // was EPriorityMuchLess
1.727 + }
1.728 +
1.729 + iSecondaryThread.Resume();
1.730 +
1.731 + User::WaitForRequest(stat);
1.732 +
1.733 + iSecondaryThread.Logon(iStatus);
1.734 +
1.735 + if (aRestarting)
1.736 + {
1.737 + CLogCommentMessage* errorMessage = CLogCommentMessage::NewL(KThreadDiedString);
1.738 + TInt err = iArrayAccess.AppendAndGiveOwnership(errorMessage);
1.739 + if(err != KErrNone)
1.740 + {
1.741 + delete errorMessage;
1.742 + User::Leave(err);
1.743 + }
1.744 + }
1.745 +
1.746 + SetActive();
1.747 +
1.748 + }
1.749 +
1.750 +void CSecondaryThread::ConstructL()
1.751 +/**
1.752 + * Contructs and kicks off the secondary thread, while also issuing a request to be informed
1.753 + * if the thread dies, which will run the active object
1.754 + */
1.755 + {
1.756 + CActiveScheduler::Add(this);
1.757 + //Preallocate a shutdown message
1.758 + iShutDownMessage = new(ELeave) CShutDownMessage;
1.759 +
1.760 + StartSecondaryThreadL(EFalse);
1.761 + }
1.762 +
1.763 +TInt CSecondaryThread::RunError(TInt /*aError*/)
1.764 + {
1.765 + CActiveScheduler::Stop(); //What the hell happened! Shut the server down
1.766 + return KErrNone;
1.767 + }
1.768 +
1.769 +CSecondaryThread::~CSecondaryThread()
1.770 + {
1.771 + Cancel();
1.772 + delete iShutDownMessage;
1.773 + iSecondaryThread.Close();
1.774 + }
1.775 +