|
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 flogger utility classes |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @internalComponent |
|
21 */ |
|
22 |
|
23 #include "comsdbgaux.h" |
|
24 #include "comsdbgsvr.h" |
|
25 #include "comsdbgmessages.h" |
|
26 |
|
27 _LIT8(KSubsystemWildCard, "*"); |
|
28 |
|
29 _LIT8(KLogKeyword, "Log"); |
|
30 _LIT8(KMediaKeyword, "Media"); |
|
31 _LIT8(KWin32DbgPortKeyword, "Win32Debug"); |
|
32 _LIT8(KLogPathKeyword, "LogPath"); |
|
33 _LIT8(KCommentKeyword, "//"); |
|
34 _LIT8(KForceFlushKeyword, "Synchronous"); |
|
35 const TUint8 KCarriageReturn = 0x000D; |
|
36 const TUint8 KLineFeed = 0x000A; |
|
37 |
|
38 |
|
39 |
|
40 CIniFileWatcher* CIniFileWatcher::NewL(RFs& aFs, CFileLoggerServer& aServer, const TDesC& aIniFile) |
|
41 { |
|
42 CIniFileWatcher* self = new(ELeave) CIniFileWatcher(aFs, aServer, aIniFile); |
|
43 self->Initialize(); |
|
44 return self; |
|
45 } |
|
46 |
|
47 CIniFileWatcher::CIniFileWatcher(RFs& aFs, CFileLoggerServer& aServer, const TDesC& aIniFile) |
|
48 : CActive(EPriorityStandard), iFs(aFs), iServer(aServer), iWatchedIniFile(aIniFile) |
|
49 {} |
|
50 |
|
51 void CIniFileWatcher::Initialize() |
|
52 { |
|
53 CActiveScheduler::Add(this); |
|
54 NotifyChange(); |
|
55 } |
|
56 |
|
57 void CIniFileWatcher::NotifyChange() |
|
58 /* Listen for change on the CDU ini file. */ |
|
59 { |
|
60 iFs.NotifyChange(ENotifyAll, iStatus, iWatchedIniFile); |
|
61 SetActive(); |
|
62 } |
|
63 |
|
64 void CIniFileWatcher::RunL() |
|
65 { |
|
66 iStatus=KRequestPending; |
|
67 NotifyChange(); |
|
68 iServer.IniFileChanged(iWatchedIniFile); |
|
69 } |
|
70 |
|
71 void CIniFileWatcher::DoCancel() |
|
72 { |
|
73 iFs.NotifyChangeCancel(); |
|
74 } |
|
75 |
|
76 |
|
77 CIniFileWatcher::~CIniFileWatcher() |
|
78 { |
|
79 Cancel(); |
|
80 } |
|
81 |
|
82 ///////////////CIniFileParser////////////////////////////////////////////// |
|
83 |
|
84 TInt CIniFileParser::ParseIniFile(TDesC& aIniFile) |
|
85 /* |
|
86 * Returns: KErrNotFound if file not found or KErrPathNotFound if path not found. |
|
87 */ |
|
88 { |
|
89 TRAPD(err, DoParseIniFileL(aIniFile)); |
|
90 return err; |
|
91 } |
|
92 |
|
93 TInt CIniFileParser::GetNextTokenAndCheck(TLex8& lex, TPtr8& tempPtr) |
|
94 /* |
|
95 Gets next token and ensures the token is simply not the EOF or a linefeed. |
|
96 lex is the lexical string to get the next token from. |
|
97 tempPtr points to the next token |
|
98 Returns KErrGeneral if token is bad or if we've already read past the end. |
|
99 */ |
|
100 { |
|
101 TUint8 ch; |
|
102 TInt len; |
|
103 |
|
104 if (lex.Eos()) |
|
105 { |
|
106 return KErrGeneral; |
|
107 } |
|
108 |
|
109 tempPtr = lex.NextToken(); |
|
110 |
|
111 len = tempPtr.Length(); |
|
112 if (len == 0) |
|
113 { |
|
114 // lex has figured out what is left is just the EOF |
|
115 return KErrGeneral; |
|
116 } |
|
117 |
|
118 // this next part may be superfluous but we've had so much strife with |
|
119 // the parser thus far that for now we're leaving it in |
|
120 |
|
121 ch = tempPtr[0]; |
|
122 if (ch == KCarriageReturn || ch == KLineFeed) |
|
123 { |
|
124 return KErrGeneral; |
|
125 } |
|
126 |
|
127 if (tempPtr.Length() < 2) |
|
128 { |
|
129 return KErrNone; |
|
130 } |
|
131 ch = tempPtr[1]; |
|
132 if (ch == KCarriageReturn || ch == KLineFeed) |
|
133 { |
|
134 return KErrGeneral; |
|
135 } |
|
136 |
|
137 return KErrNone; |
|
138 } |
|
139 |
|
140 void CIniFileParser::DoParseIniFileL(TDesC& aIniFile) |
|
141 /* |
|
142 * |
|
143 * The force flush state is only updated if it is not already set to something other |
|
144 * than ENoValue. If force flush option is not found in ini file, force flush is set |
|
145 * to off. |
|
146 */ |
|
147 { |
|
148 |
|
149 TInt fileLength; |
|
150 TInt ret = KErrNone; |
|
151 RFile iniFile; |
|
152 |
|
153 // Open file |
|
154 User::LeaveIfError(iniFile.Open(iFs, aIniFile, EFileShareAny)); |
|
155 |
|
156 CleanupClosePushL(iniFile); |
|
157 |
|
158 // as we have been able to open the file, set the media to default. |
|
159 // If the ini file is parsed correctly, this then gets overwritten. |
|
160 // Otherwise the caller should pass thru a mesg to get the default enabled. |
|
161 if (iLoggingMediaString.Length() == 0) |
|
162 { |
|
163 iLoggingMediaString = KDefaultMedia; |
|
164 } |
|
165 |
|
166 |
|
167 |
|
168 User::LeaveIfError(iniFile.Size(fileLength)); |
|
169 |
|
170 HBufC8* iniContents = HBufC8::NewLC(fileLength); |
|
171 TPtr8 hbufPtr = iniContents->Des(); |
|
172 User::LeaveIfError(iniFile.Read(hbufPtr)); |
|
173 TLex8 lex(*iniContents); |
|
174 |
|
175 //OK, file is open and ready for parsing. Make a tempory array and if there is a |
|
176 //problem in the ini file leave settings as they were, leave, and |
|
177 //the error will get picked up. |
|
178 |
|
179 delete iIniSettings; |
|
180 iIniSettings = NULL; |
|
181 CIniLoggingPairs* iniSettings = CIniLoggingPairs::NewL(); |
|
182 CleanupStack::PushL(iniSettings); |
|
183 TNameTag tempTag; |
|
184 TNameTag tempTag2; |
|
185 TChar tempChar; |
|
186 |
|
187 FOREVER |
|
188 { |
|
189 ret = GetNextTokenAndCheck(lex,hbufPtr); |
|
190 if (ret != KErrNone) |
|
191 { |
|
192 break; |
|
193 } |
|
194 if (hbufPtr.Find(KCommentKeyword)!=KErrNotFound) //found a Comment |
|
195 { |
|
196 tempChar = lex.Get(); |
|
197 while (!lex.Eos() && TUint(tempChar) != KCarriageReturn && TUint(tempChar) != KLineFeed) |
|
198 { |
|
199 tempChar = lex.Get(); |
|
200 } |
|
201 } |
|
202 else if (hbufPtr.CompareF(KMediaKeyword)==0) //MediaSetting |
|
203 { |
|
204 User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr)); |
|
205 if (hbufPtr.Length()>KMaxMediaStringLength) |
|
206 { |
|
207 User::Leave(KErrGeneral); |
|
208 } |
|
209 iLoggingMediaString = hbufPtr; |
|
210 } |
|
211 else if (hbufPtr.CompareF(KLogKeyword)==0) //LOG |
|
212 { |
|
213 User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr)); |
|
214 |
|
215 if (hbufPtr.Length()>KMaxTagLength) |
|
216 { |
|
217 tempTag = hbufPtr.Left(KMaxTagLength); |
|
218 } |
|
219 else |
|
220 { |
|
221 tempTag = hbufPtr; |
|
222 } |
|
223 User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr)); |
|
224 if (hbufPtr.Length()>KMaxTagLength) |
|
225 { |
|
226 tempTag2 = hbufPtr.Left(KMaxTagLength); |
|
227 } |
|
228 else |
|
229 { |
|
230 tempTag2 = hbufPtr; |
|
231 } |
|
232 iniSettings->AddSettingL(tempTag, tempTag2); |
|
233 } |
|
234 else if (hbufPtr.CompareF(KForceFlushKeyword)==0) //ForceFlush |
|
235 { |
|
236 if (iForceFlushState == ENoValue) |
|
237 { |
|
238 iForceFlushState = EFlushOn; |
|
239 } |
|
240 } |
|
241 else if (hbufPtr.CompareF(KLogPathKeyword) == 0) //LogPath |
|
242 { |
|
243 User::LeaveIfError(GetNextTokenAndCheck(lex,hbufPtr)); |
|
244 if (hbufPtr.Length()>KMaxName) |
|
245 { |
|
246 User::Leave(KErrOverflow); |
|
247 } |
|
248 iLoggingPathString.Copy(hbufPtr); |
|
249 } |
|
250 else if (hbufPtr.CompareF(KWin32DbgPortKeyword)==0) //Win32DebugPort |
|
251 { |
|
252 iWin32DebugEnabled = ETrue; |
|
253 } |
|
254 else |
|
255 User::Leave(KErrBadName); |
|
256 |
|
257 if (lex.Eos()) |
|
258 { |
|
259 break; |
|
260 } |
|
261 } |
|
262 iIniSettings = iniSettings; |
|
263 CleanupStack::Pop(iniSettings); |
|
264 CleanupStack::PopAndDestroy(); //iniContents |
|
265 CleanupStack::PopAndDestroy(); //iniFile |
|
266 |
|
267 if (iForceFlushState == ENoValue) |
|
268 { |
|
269 iForceFlushState = EFlushOff; |
|
270 } |
|
271 } |
|
272 |
|
273 CIniFileParser* CIniFileParser::NewL(RFs& aFs) |
|
274 { |
|
275 return new(ELeave) CIniFileParser(aFs); |
|
276 } |
|
277 |
|
278 CIniFileParser::~CIniFileParser() |
|
279 { |
|
280 delete iIniSettings; |
|
281 } |
|
282 |
|
283 TBool CIniFileParser::LogValid(const TDesC8& aSubsystem, const TDesC8& aComponent) const |
|
284 // If no memory, this operation will return EFalse so user will not get logs, nor a msg to say so. |
|
285 { |
|
286 if (iIniSettings) |
|
287 { |
|
288 TBool result = iIniSettings->SettingValid(aSubsystem, aComponent); |
|
289 return result; |
|
290 } |
|
291 else |
|
292 { |
|
293 return EFalse; |
|
294 } |
|
295 } |
|
296 |
|
297 void CIniFileParser::LogMediaSetting(TDes8& aString) const |
|
298 { |
|
299 aString=iLoggingMediaString; |
|
300 } |
|
301 |
|
302 void CIniFileParser::LogPathSetting(TDes8& aString) const |
|
303 { |
|
304 aString.Copy(iLoggingPathString); |
|
305 } |
|
306 |
|
307 void CIniFileParser::FlushingOn(TBool& aFlushingOn) const |
|
308 /* |
|
309 * Return whether flushing is on or off. |
|
310 */ |
|
311 { |
|
312 if (iForceFlushState == EFlushOn) |
|
313 { |
|
314 aFlushingOn = ETrue; |
|
315 } |
|
316 else |
|
317 { |
|
318 aFlushingOn = EFalse; |
|
319 } |
|
320 } |
|
321 |
|
322 void CIniFileParser::FinaliseFlushSetting() |
|
323 /* |
|
324 * It is not safe to switch flush modes once we begin logging, so this is called |
|
325 * to let fileparser know that system is about to commence logging. |
|
326 * If the file parser has still not determined whether it should be logging or not, |
|
327 * then set flushing to off. |
|
328 */ |
|
329 { |
|
330 if (iForceFlushState == ENoValue) |
|
331 { |
|
332 iForceFlushState = EFlushOff; |
|
333 } |
|
334 } |
|
335 |
|
336 CIniFileParser::CIniFileParser(RFs& aFs) |
|
337 : iFs(aFs) |
|
338 { |
|
339 iForceFlushState = ENoValue; |
|
340 } |
|
341 |
|
342 ///////////////////////////////////////////// |
|
343 |
|
344 CSubsystemSettings::~CSubsystemSettings() |
|
345 { |
|
346 iComponentArray.Close(); |
|
347 } |
|
348 |
|
349 TInt CSubsystemSettings::AddComponent(const TDesC8& aComponent) |
|
350 { |
|
351 return iComponentArray.InsertInOrder(TNameTag(aComponent), |
|
352 TLinearOrder<TNameTag>(CompareTComponent)); |
|
353 } |
|
354 |
|
355 TBool CSubsystemSettings::ElementExistsInArray(const TDesC8& aComponent) const |
|
356 { |
|
357 return (iComponentArray.FindInOrder(aComponent, TLinearOrder<TNameTag>(CSubsystemSettings::CompareTComponent))!=KErrNotFound); |
|
358 } |
|
359 |
|
360 CSubsystemSettings::CSubsystemSettings(const TDesC8& aName) |
|
361 : iSubsystemName(aName) |
|
362 {} |
|
363 |
|
364 void CSubsystemSettings::SetSubsystemName(const TDesC8& aName) |
|
365 { |
|
366 iSubsystemName = aName; |
|
367 } |
|
368 TInt CSubsystemSettings::CompareCSubsystemSettings(const CSubsystemSettings& aFirst, const CSubsystemSettings& aSecond) |
|
369 { |
|
370 return aFirst.iSubsystemName.CompareF(aSecond.iSubsystemName); |
|
371 } |
|
372 |
|
373 TInt CSubsystemSettings::CompareTComponent(const TNameTag& aFirst, const TNameTag& aSecond) |
|
374 { |
|
375 return aFirst.CompareF(aSecond); |
|
376 } |
|
377 |
|
378 void CSubsystemSettings::SetWildCarded(TBool aWildCarded) |
|
379 { |
|
380 iSubsystemWildcarded = aWildCarded; |
|
381 } |
|
382 |
|
383 CIniLoggingPairs* CIniLoggingPairs::NewL() |
|
384 { |
|
385 CIniLoggingPairs* self = new(ELeave) CIniLoggingPairs; |
|
386 if((self->iProbeSubsystem = new CSubsystemSettings(KNullDesC8)) == NULL) |
|
387 { |
|
388 delete self; |
|
389 User::Leave(KErrNoMemory); |
|
390 } |
|
391 return self; |
|
392 } |
|
393 |
|
394 CIniLoggingPairs::~CIniLoggingPairs() |
|
395 { |
|
396 iSubsystems.ResetAndDestroy(); |
|
397 delete iProbeSubsystem; |
|
398 } |
|
399 |
|
400 void CIniLoggingPairs::AddSettingL(const TDesC8& aSubsystem, const TDesC8& aComponent) |
|
401 { |
|
402 TBool subsystemIsNewInList(EFalse); |
|
403 CSubsystemSettings* subsystemSetting; |
|
404 iProbeSubsystem->SetSubsystemName(aSubsystem); |
|
405 TInt subsysPos = iSubsystems.FindInOrder(iProbeSubsystem, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings)); |
|
406 if (subsysPos == KErrNotFound) |
|
407 { |
|
408 subsystemSetting = new(ELeave) CSubsystemSettings(aSubsystem); |
|
409 CleanupStack::PushL(subsystemSetting); |
|
410 iSubsystems.InsertInOrderL(subsystemSetting, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings)); |
|
411 subsystemIsNewInList = ETrue; |
|
412 CleanupStack::Pop(subsystemSetting); |
|
413 } |
|
414 else |
|
415 { |
|
416 ASSERT(subsysPos >= KErrNone); |
|
417 subsystemSetting = iSubsystems[subsysPos]; |
|
418 } |
|
419 //subsystemSetting is now owned in the array, so we don't need to worry about any leaves from here on. |
|
420 if (aComponent.CompareF(KSubsystemWildCard)==0) |
|
421 { |
|
422 subsystemSetting->SetWildCarded(ETrue); |
|
423 return; |
|
424 } |
|
425 TInt err; |
|
426 if ((err = subsystemSetting->AddComponent(aComponent))!=KErrNone) |
|
427 { |
|
428 if (subsystemIsNewInList) |
|
429 { |
|
430 delete subsystemSetting; |
|
431 iSubsystems.Remove(subsysPos); |
|
432 User::Leave(err); |
|
433 } |
|
434 } |
|
435 } |
|
436 |
|
437 TBool CIniLoggingPairs::SettingValid(const TDesC8& aSubsystem, const TDesC8& aComponent) const |
|
438 { |
|
439 iProbeSubsystem->SetSubsystemName(aSubsystem); |
|
440 TBool settingValid; |
|
441 TInt positionInArray; |
|
442 if (iSubsystems.FindInOrder(iProbeSubsystem, positionInArray, TLinearOrder<CSubsystemSettings>(CSubsystemSettings::CompareCSubsystemSettings))==KErrNotFound) |
|
443 { |
|
444 settingValid = EFalse; |
|
445 } |
|
446 else if (iSubsystems[positionInArray]->IsWildCarded()) |
|
447 { |
|
448 settingValid = ETrue; |
|
449 } |
|
450 else |
|
451 { |
|
452 settingValid = iSubsystems[positionInArray]->ElementExistsInArray(aComponent); |
|
453 } |
|
454 return settingValid; |
|
455 } |
|
456 |
|
457 ///////////////////////////////////////////// |
|
458 |
|
459 CTimeManager* CTimeManager::NewL(MLogArrayAccess& aArrayAccess) |
|
460 { |
|
461 CTimeManager* self = new(ELeave) CTimeManager(aArrayAccess); |
|
462 CleanupStack::PushL(self); |
|
463 self->ConstructL(); |
|
464 CleanupStack::Pop(self); |
|
465 return self; |
|
466 } |
|
467 |
|
468 void CTimeManager::Beat() |
|
469 /* |
|
470 * Called by kernel every second if we're synchronised. |
|
471 * Updates the variable recording the current time, and sends it to the log queue. |
|
472 */ |
|
473 { |
|
474 iTime+=TTimeIntervalSeconds(1); |
|
475 SendTimeUpdate(); |
|
476 } |
|
477 |
|
478 void CTimeManager::Synchronize() |
|
479 /* |
|
480 * Called by kernel when it finds synchronisation is lost (a heartbeat was missed - maybe |
|
481 * device has been off for a while). |
|
482 * Updates the variable recording the current time, and sends it to the log queue. |
|
483 */ |
|
484 { |
|
485 iTime.HomeTime(); |
|
486 SendTimeUpdate(); |
|
487 } |
|
488 |
|
489 CTimeManager::CTimeManager(MLogArrayAccess& aArrayAccess) |
|
490 : iArrayAccess(aArrayAccess) |
|
491 {} |
|
492 |
|
493 void CTimeManager::SendTimeUpdate() |
|
494 /* |
|
495 * append to queue a time update message |
|
496 */ |
|
497 { |
|
498 CTimeUpdateMessage* timeMessage = new CTimeUpdateMessage(iTime); |
|
499 if (timeMessage) |
|
500 { |
|
501 if (iArrayAccess.AppendAndGiveOwnership(timeMessage)!=KErrNone) |
|
502 { |
|
503 delete timeMessage; //We failed to get a time update in. Ahh well. |
|
504 } |
|
505 } |
|
506 } |
|
507 |
|
508 void CTimeManager::ConstructL() |
|
509 /* |
|
510 * Start heartbeat active object to trigger every second, passing in this class |
|
511 * for kernel to callback to. |
|
512 */ |
|
513 { |
|
514 iTime.HomeTime(); |
|
515 iHeartbeat = CHeartbeat::NewL(EPriorityHigh); |
|
516 iHeartbeat->Start(ETwelveOClock, this); // 12 1/12th intervals |
|
517 SendTimeUpdate(); |
|
518 } |
|
519 |
|
520 CTimeManager::~CTimeManager() |
|
521 { |
|
522 delete iHeartbeat; |
|
523 } |
|
524 |