|
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 |