|
1 // Copyright (c) 2007-2010 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 // Trace Core main instance implementation |
|
15 // |
|
16 // |
|
17 |
|
18 #include <e32def.h> |
|
19 #include <e32btrace.h> |
|
20 #include <trace_certification.h> |
|
21 |
|
22 #include "TraceCore.h" |
|
23 #include "TraceCoreSendReceive.h" |
|
24 #include "TraceCoreRouter.h" |
|
25 #include "TraceCoreDebug.h" |
|
26 #include "TraceCoreBTraceHandler.h" |
|
27 #include "TraceCorePrintfTraceHandler.h" |
|
28 #include "TraceCoreNotifier.h" |
|
29 #include "TraceCoreConfiguration.h" |
|
30 #include "TraceCoreInternalMessageHandler.h" |
|
31 #include "TraceCoreActivation.h" |
|
32 |
|
33 #include "OstTraceDefinitions.h" |
|
34 #ifdef OST_TRACE_COMPILER_IN_USE |
|
35 #include "TraceCoreTraces.h" |
|
36 #endif |
|
37 |
|
38 /** |
|
39 * TraceCore global instance |
|
40 */ |
|
41 DTraceCore* DTraceCore::iInstance = NULL; |
|
42 |
|
43 |
|
44 /** |
|
45 * Gets the TraceCore instance, |
|
46 * @return DTraceCore object or NULL if TraceCore is not created yet. |
|
47 */ |
|
48 EXPORT_C DTraceCore* DTraceCore::GetInstance() |
|
49 { |
|
50 return iInstance; |
|
51 } |
|
52 |
|
53 /** |
|
54 * Returns ETrue if tracecore is loaded already EFalse otherwies |
|
55 */ |
|
56 EXPORT_C TBool DTraceCore::IsLoaded() |
|
57 { |
|
58 return ( iInstance != NULL ); |
|
59 } |
|
60 |
|
61 /** |
|
62 * Gets the BTrace handler |
|
63 */ |
|
64 DTraceCoreBTraceHandler* DTraceCore::GetBTraceHandler() |
|
65 { |
|
66 DTraceCoreBTraceHandler* retval = NULL; |
|
67 DTraceCore* traceCore = DTraceCore::GetInstance(); |
|
68 // BTrace handler is the first one to be registered |
|
69 if ( traceCore != NULL && traceCore->iHandlers.Count() > 0 ) |
|
70 { |
|
71 retval = ( DTraceCoreBTraceHandler* )traceCore->iHandlers[ 0 ]; |
|
72 } |
|
73 return retval; |
|
74 } |
|
75 |
|
76 /** |
|
77 * Constructor |
|
78 */ |
|
79 DTraceCore::DTraceCore() |
|
80 : iRouter( NULL ) |
|
81 , iSendReceive( NULL ) |
|
82 , iNotifier( NULL ) |
|
83 , iConfiguration( NULL ) |
|
84 , iInternalMessageHandler( NULL ) |
|
85 , iBTrace( NULL ) |
|
86 , iPrintf( NULL ) |
|
87 , iTraceCoreSettings( NULL ) |
|
88 , iActiveWriter( NULL ) |
|
89 , iActivationQ(NULL) |
|
90 , iPreviousTraceDropped(EFalse) |
|
91 , iTraceCertified(EFalse) |
|
92 { |
|
93 } |
|
94 |
|
95 /** |
|
96 * Destructor |
|
97 */ |
|
98 DTraceCore::~DTraceCore() |
|
99 { |
|
100 // Writers and handlers are deleted first |
|
101 // -> They call unregister functions |
|
102 delete iBTrace; |
|
103 delete iPrintf; |
|
104 |
|
105 iHandlers.Reset(); |
|
106 iWriters.Reset(); |
|
107 iActivations.Reset(); |
|
108 |
|
109 delete iRouter; |
|
110 delete iSendReceive; |
|
111 delete iNotifier; |
|
112 delete iConfiguration; |
|
113 //destroy iActivationQue |
|
114 if (iActivationQ) |
|
115 iActivationQ->Destroy(); |
|
116 } |
|
117 |
|
118 |
|
119 /* |
|
120 * Init TraceCore |
|
121 */ |
|
122 TInt DTraceCore::Init() |
|
123 { |
|
124 TC_TRACE( ETraceLevelFlow, Kern::Printf( ">DTraceCore::Init()" ) ); |
|
125 TInt ret; |
|
126 |
|
127 //TODO: measure how much time it takes to boot up |
|
128 //TODO: measure how much memory is consumed by TraceCore |
|
129 //TODO: check granularity of internal RArrays - update this for most used use case |
|
130 |
|
131 //TODO: check dfc que (if we have any) that deals with pulling trace data from buffer |
|
132 |
|
133 // Store the trace certified flag, used to suppress tracing on production images. |
|
134 // This stored value is used throughout the session, even if the status of the certificate changes. |
|
135 // This is done to avoid performance issues when performing the check with every trace outputted. |
|
136 iTraceCertified = TraceCertification::IsTraceCertified(); |
|
137 |
|
138 //create activation/deactivation queue |
|
139 const TInt KTCDfcThreadPriority = 24; // Kern::DfcQ0 is 27 |
|
140 //TODO: put this const to a header |
|
141 //TODO: check if I can use constants for this (DFCQ0-1) ? |
|
142 _LIT(KTCDfcQueue, "TraceCoreActivationDfcQ"); |
|
143 Kern::Printf("Creating TC dfc - %S...", &KTCDfcQueue); |
|
144 ret = Kern::DynamicDfcQCreate(iActivationQ, KTCDfcThreadPriority, KTCDfcQueue); |
|
145 Kern::Printf("returned code: %d, ptr: 0x%x", ret, iActivationQ); |
|
146 if (ret==KErrNone) |
|
147 //disable real-time state of the dfcq |
|
148 iActivationQ->SetRealtimeState(ERealtimeStateOff); |
|
149 |
|
150 // Disable Component ID filtering in BTrace |
|
151 BTrace::SetFilter2(1); |
|
152 |
|
153 // Create needed components |
|
154 iRouter = new DTraceCoreRouter(); |
|
155 iSendReceive = new DTraceCoreSendReceive(); |
|
156 iNotifier = new DTraceCoreNotifier(); |
|
157 iConfiguration = new DTraceCoreConfiguration(); |
|
158 iInternalMessageHandler = new DTraceCoreInternalMessageHandler(); |
|
159 |
|
160 // Check that creating of the components was succesfull |
|
161 if ( iRouter != NULL && iSendReceive != NULL && iNotifier != NULL && iConfiguration != NULL ) |
|
162 { |
|
163 ret = iSendReceive->Init( *iRouter ); |
|
164 if ( ret == KErrNone ) |
|
165 { |
|
166 ret = iRouter->Init( *iSendReceive ); |
|
167 if ( ret == KErrNone ) |
|
168 { |
|
169 ret = iConfiguration->Init(); |
|
170 if ( ret == KErrNone ) |
|
171 { |
|
172 ret = iInternalMessageHandler->Init(); |
|
173 } |
|
174 } |
|
175 } |
|
176 } |
|
177 else |
|
178 { |
|
179 ret = KErrNoMemory; |
|
180 } |
|
181 |
|
182 // BTrace handler is integrated to TraceCore |
|
183 if ( ret == KErrNone ) |
|
184 { |
|
185 ret = StartBTrace(); |
|
186 } |
|
187 |
|
188 // Printf handler is integrated to TraceCore |
|
189 if ( ret == KErrNone ) |
|
190 { |
|
191 ret = StartPrintfTraceHandler(); |
|
192 } |
|
193 TC_TRACE( ETraceLevelFlow, Kern::Printf( "<DTraceCore::Init() - %d", ret ) ); |
|
194 |
|
195 return ret; |
|
196 } |
|
197 |
|
198 /** |
|
199 * Starts the BTrace handler |
|
200 */ |
|
201 TInt DTraceCore::StartBTrace() |
|
202 { |
|
203 TInt ret = KErrNone; |
|
204 |
|
205 // Create BTrace handler |
|
206 iBTrace = new DTraceCoreBTraceHandler(); |
|
207 if ( iBTrace != NULL ) |
|
208 { |
|
209 // Init calls RegisterHandler |
|
210 ret = iBTrace->Init(); |
|
211 } |
|
212 else |
|
213 { |
|
214 ret = KErrNoMemory; |
|
215 } |
|
216 TC_TRACE( ETraceLevelFlow, Kern::Printf( "<DTraceCore::StartBTrace() - %d", ret ) ); |
|
217 return ret; |
|
218 } |
|
219 |
|
220 |
|
221 /** |
|
222 * Starts the Printf trace handler |
|
223 */ |
|
224 TInt DTraceCore::StartPrintfTraceHandler() |
|
225 { |
|
226 TInt ret; |
|
227 |
|
228 // Create PrintF handler |
|
229 iPrintf = new DTraceCorePrintfTraceHandler(); |
|
230 if ( iPrintf != NULL ) |
|
231 { |
|
232 // Init calls RegisterHandler |
|
233 ret = iPrintf->Init(); |
|
234 } |
|
235 else |
|
236 { |
|
237 ret = KErrNoMemory; |
|
238 } |
|
239 TC_TRACE( ETraceLevelFlow, Kern::Printf( "<DTraceCore::StartPrintfTraceHandler() - %d", ret ) ); |
|
240 return ret; |
|
241 } |
|
242 |
|
243 |
|
244 /** |
|
245 * Registers an activation interface |
|
246 */ |
|
247 TInt DTraceCore::RegisterActivation( MTraceCoreActivation& aActivation ) |
|
248 { |
|
249 return iActivations.Append( &aActivation ); |
|
250 } |
|
251 |
|
252 |
|
253 /** |
|
254 * Gets an activation interface. |
|
255 * Tracing from this method is not allowed. |
|
256 */ |
|
257 MTraceCoreActivation* DTraceCore::GetActivation( TUint32 aComponentId ) |
|
258 { |
|
259 MTraceCoreActivation* retval = NULL; |
|
260 |
|
261 // Find the correct activation interface from the list |
|
262 for ( int i = 0; i < iActivations.Count(); i++ ) |
|
263 { |
|
264 if ( iActivations[ i ]->IsComponentSupported( aComponentId ) ) |
|
265 { |
|
266 retval = iActivations[ i ]; |
|
267 } |
|
268 } |
|
269 |
|
270 return retval; |
|
271 } |
|
272 |
|
273 |
|
274 /** |
|
275 * Registers a handler |
|
276 * |
|
277 * @param aHandler The handler |
|
278 */ |
|
279 TInt DTraceCore::RegisterHandler( DTraceCoreHandler& aHandler ) |
|
280 { |
|
281 OstTrace1( TRACE_FLOW, DTRACECORE_REGISTERHANDLER_ENTRY, "> DTraceCore::RegisterHandler 0x%x", ( TUint )&( aHandler ) ); |
|
282 TInt ret = iHandlers.Append( &aHandler ); |
|
283 |
|
284 // If there is not yet active writer, set the new one |
|
285 if ( ret == KErrNone && iActiveWriter != NULL ) |
|
286 { |
|
287 aHandler.SetWriter( iActiveWriter ); |
|
288 } |
|
289 |
|
290 // Set settings to the handler |
|
291 if ( ret == KErrNone && iTraceCoreSettings != NULL ) |
|
292 { |
|
293 aHandler.SetSettings( iTraceCoreSettings ); |
|
294 } |
|
295 OstTrace1( TRACE_FLOW, DTRACECORE_REGISTERHANDLER_EXIT, "< DTraceCore::RegisterHandler. Ret:%d", ret ); |
|
296 |
|
297 return ret; |
|
298 } |
|
299 |
|
300 |
|
301 /** |
|
302 * Unregisters a handler |
|
303 * |
|
304 * @param aHandler The handler |
|
305 */ |
|
306 void DTraceCore::UnregisterHandler( DTraceCoreHandler& aHandler ) |
|
307 { |
|
308 // Find thiss handler from the list of handlers |
|
309 for ( TInt i = 0; i < iHandlers.Count(); i++ ) |
|
310 { |
|
311 if ( iHandlers[ i ] == &aHandler ) |
|
312 { |
|
313 OstTrace1( TRACE_NORMAL, DTRACECORE_UNREGISTERHANDLER_HANDLER_REMOVED, "DTraceCore::UnregisterHandler - Handler removed 0x%x", ( TUint )&aHandler ); |
|
314 iHandlers.Remove( i ); |
|
315 i = iHandlers.Count(); |
|
316 } |
|
317 } |
|
318 } |
|
319 |
|
320 /** |
|
321 * Registers the settings |
|
322 * |
|
323 * @param aSettings The settings saver |
|
324 * @return KErrNone if registration successful |
|
325 */ |
|
326 TInt DTraceCore::RegisterSettings( DTraceCoreSettings& aSettings ) |
|
327 { |
|
328 iTraceCoreSettings = &aSettings; |
|
329 for ( TInt i = 0; i < iHandlers.Count(); i++ ) |
|
330 { |
|
331 iHandlers[ i ]->SetSettings( iTraceCoreSettings ); |
|
332 } |
|
333 return KErrNone; |
|
334 } |
|
335 |
|
336 |
|
337 /** |
|
338 * Unregisters the settings |
|
339 * |
|
340 * @param aSettings The settings |
|
341 */ |
|
342 void DTraceCore::UnregisterSettings( DTraceCoreSettings& aSettings ) |
|
343 { |
|
344 if ( &aSettings == iTraceCoreSettings ) |
|
345 { |
|
346 iTraceCoreSettings = NULL; |
|
347 |
|
348 // Remove settings from all the handlers |
|
349 for ( TInt i = 0; i < iHandlers.Count(); i++ ) |
|
350 { |
|
351 iHandlers[ i ]->SetSettings( NULL ); |
|
352 } |
|
353 } |
|
354 } |
|
355 |
|
356 |
|
357 /** |
|
358 * Registers a writer |
|
359 * |
|
360 * @param aWriter The writer |
|
361 */ |
|
362 TInt DTraceCore::RegisterWriter( DTraceCoreWriter& aWriter ) |
|
363 { |
|
364 OstTrace1( TRACE_FLOW, DTRACECORE_REGISTERWRITER_ENTRY, "> DTraceCore::RegisterWriter 0x%x", ( TUint )&( aWriter ) ); |
|
365 |
|
366 TInt ret = iWriters.Append( &aWriter ); |
|
367 if ( ret == KErrNone ) |
|
368 { |
|
369 // First writer that registers is selected as the active one |
|
370 if ( iActiveWriter == NULL ) |
|
371 { |
|
372 iActiveWriter = &aWriter; |
|
373 SetWriterToHandlers(); |
|
374 } |
|
375 } |
|
376 |
|
377 OstTrace1( TRACE_FLOW, DTRACECORE_REGISTERWRITER_EXIT, "< DTraceCore::RegisterWriter %d", ret ); |
|
378 return ret; |
|
379 } |
|
380 |
|
381 |
|
382 /** |
|
383 * Unregisters a writer |
|
384 * |
|
385 * @param aWriter The writer |
|
386 */ |
|
387 void DTraceCore::UnregisterWriter( DTraceCoreWriter& aWriter ) |
|
388 { |
|
389 for ( TInt i = 0; i < iWriters.Count(); i++ ) |
|
390 { |
|
391 if ( iWriters[ i ] == &aWriter ) |
|
392 { |
|
393 OstTraceExt2( TRACE_NORMAL, DTRACECORE_UNREGISTERHANDLER_WRITER_UNREGISTERED, "DTraceCore::UnregisterWriter - Writer unregistered WriterType:%d Addr:0x%x", ( TInt )aWriter.GetWriterType(), ( TUint )&aWriter ); |
|
394 iWriters.Remove( i ); |
|
395 i = iWriters.Count(); |
|
396 // If the active writer was removed, another writer needs to be activated |
|
397 if ( &aWriter == iActiveWriter ) |
|
398 { |
|
399 SwitchToFirstWriter(); |
|
400 } |
|
401 } |
|
402 } |
|
403 } |
|
404 |
|
405 |
|
406 /** |
|
407 * Starts to use the first writer from the writers list |
|
408 */ |
|
409 void DTraceCore::SwitchToFirstWriter() |
|
410 { |
|
411 if ( iWriters.Count() > 0 ) |
|
412 { |
|
413 iActiveWriter = iWriters[ 0 ]; |
|
414 } |
|
415 else |
|
416 { |
|
417 iActiveWriter = NULL; |
|
418 } |
|
419 SetWriterToHandlers(); |
|
420 } |
|
421 |
|
422 |
|
423 /** |
|
424 * Starts to use a writer of the specific type. Does nothing if the writer is already active |
|
425 */ |
|
426 EXPORT_C TInt DTraceCore::SwitchToWriter( TWriterType aWriterType ) |
|
427 { |
|
428 OstTrace1( TRACE_FLOW, DTRACECORE_SWITCHTOWRITER_ENTRY,"> DTraceCore::SwitchToWriter WriterType:%d", ( TUint )( aWriterType ) ); |
|
429 TInt retval( KErrNone ); |
|
430 |
|
431 // Remove writer |
|
432 if ( aWriterType == EWriterTypeNone ) |
|
433 { |
|
434 if ( iActiveWriter != NULL ) |
|
435 { |
|
436 iActiveWriter = NULL; |
|
437 SetWriterToHandlers(); |
|
438 } |
|
439 } |
|
440 else |
|
441 { |
|
442 if ( iActiveWriter == NULL || iActiveWriter->GetWriterType() != aWriterType ) |
|
443 { |
|
444 retval = KErrNotSupported; |
|
445 |
|
446 // Find the correct writer from the list |
|
447 for ( int i = 0; i < iWriters.Count() && retval != KErrNone; i++ ) |
|
448 { |
|
449 DTraceCoreWriter* writer = iWriters[ i ]; |
|
450 |
|
451 // revert this |
|
452 TWriterType wt = writer->GetWriterType(); |
|
453 |
|
454 if ( wt == aWriterType ) |
|
455 { |
|
456 iActiveWriter = writer; |
|
457 retval = KErrNone; |
|
458 } |
|
459 } |
|
460 |
|
461 // Set writer to all handlers |
|
462 if ( retval == KErrNone ) |
|
463 { |
|
464 SetWriterToHandlers(); |
|
465 } |
|
466 } |
|
467 } |
|
468 OstTrace1( TRACE_FLOW, DTRACECORE_SWITCHTOWRITER_EXIT, "< DTraceCore::SwitchToWriter %d", retval ); |
|
469 return retval; |
|
470 } |
|
471 |
|
472 /** |
|
473 * Sets the active writer to all registered handlers |
|
474 */ |
|
475 void DTraceCore::SetWriterToHandlers() |
|
476 { |
|
477 if ( iActiveWriter != NULL ) |
|
478 { |
|
479 OstTraceExt2( TRACE_NORMAL, DTRACECORE_SETWRITERTOHANDLERS_WRITER_SELECTED, "DTraceCore::SetWriterToHandlers - Writer selected 0x%x WriterType:%d", (TUint) iActiveWriter, (TInt) iActiveWriter->GetWriterType() ); |
|
480 } |
|
481 |
|
482 // PrepareSetWriter method is called with interrupts enabled |
|
483 // SetWriter is called with interrupts disabled to prevent tracing |
|
484 // while switching the writer |
|
485 for ( TInt i = 0; i < iHandlers.Count(); i++ ) |
|
486 { |
|
487 iHandlers[ i ]->PrepareSetWriter( iActiveWriter ); |
|
488 } |
|
489 //TODO: this is not SMP safe but it's rare case - update it later |
|
490 TInt interrupts = NKern::DisableAllInterrupts(); |
|
491 for ( TInt j = 0; j < iHandlers.Count(); j++ ) |
|
492 { |
|
493 iHandlers[ j ]->SetWriter( iActiveWriter ); |
|
494 } |
|
495 NKern::RestoreInterrupts( interrupts ); |
|
496 } |
|
497 |
|
498 /** |
|
499 * Get current writer type |
|
500 * |
|
501 * @return Current writer type |
|
502 */ |
|
503 EXPORT_C TInt DTraceCore::GetCurrentWriterType() |
|
504 { |
|
505 TInt ret(0); |
|
506 ret = iActiveWriter->GetWriterType(); |
|
507 return ret; |
|
508 } |
|
509 |
|
510 /* |
|
511 * Destroy the static instance of tracecore |
|
512 */ |
|
513 EXPORT_C void DTraceCore::DestroyTraceCore() |
|
514 { |
|
515 TC_TRACE( ETraceLevelNormal, Kern::Printf( "StopTraceCore started" ) ); |
|
516 delete DTraceCore::GetInstance(); |
|
517 DTraceCore::iInstance = NULL; |
|
518 TC_TRACE( ETraceLevelNormal, Kern::Printf( "StopTraceCore Finished" ) ); |
|
519 } |
|
520 |
|
521 |
|
522 /** |
|
523 * Sets the "Trace Dropped" flag |
|
524 * |
|
525 * @param aTraceDropped ETrue if Trace Dropped, EFalse Otherwise |
|
526 */ |
|
527 EXPORT_C void DTraceCore::SetPreviousTraceDropped(TBool aTraceDropped) |
|
528 { |
|
529 iPreviousTraceDropped = aTraceDropped; |
|
530 } |
|
531 |
|
532 /** |
|
533 * returns the state of the "Trace Dropped" flag |
|
534 * |
|
535 * @param none |
|
536 */ |
|
537 EXPORT_C TBool DTraceCore::PreviousTraceDropped() const |
|
538 { |
|
539 return iPreviousTraceDropped; |
|
540 } |
|
541 |
|
542 |
|
543 EXPORT_C DTraceCore* DTraceCore::CreateInstance() |
|
544 { |
|
545 if(iInstance == NULL) |
|
546 { |
|
547 DTraceCore* instance = new DTraceCore(); |
|
548 if ( instance != NULL ) |
|
549 { |
|
550 iInstance = instance; |
|
551 TInt ret = iInstance->Init(); |
|
552 if(ret != KErrNone) |
|
553 { |
|
554 delete iInstance; |
|
555 iInstance = NULL; |
|
556 } |
|
557 } |
|
558 } |
|
559 |
|
560 return iInstance; |
|
561 } |
|
562 |
|
563 |
|
564 EXPORT_C DTraceCoreWriter* DTraceCore::GetActiveWriter() |
|
565 { |
|
566 return iActiveWriter; |
|
567 } |
|
568 |
|
569 /** |
|
570 * Reactivate all currently activated traces |
|
571 * |
|
572 * @param none |
|
573 * @return KErrNone if refresh successful |
|
574 */ |
|
575 TInt DTraceCore::RefreshActivations() |
|
576 { |
|
577 TInt ret = KErrNone; |
|
578 // Go through all activation interfaces from the list |
|
579 TInt activationsCount = iActivations.Count(); |
|
580 for ( int i = 0; i < activationsCount; i++ ) |
|
581 { |
|
582 TInt err = iActivations[ i ]->RefreshActivations(); |
|
583 if (err != KErrNone) |
|
584 { |
|
585 ret = err; |
|
586 } |
|
587 } |
|
588 return ret; |
|
589 } |