|
1 // Copyright (c) 2005-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 // e32test\debug\d_tracecore.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <kernel/kern_priv.h> |
|
19 #include <kernel/kernel.h> |
|
20 |
|
21 #include <e32btrace.h> |
|
22 #include <opensystemtrace_types.h> |
|
23 |
|
24 #ifndef __SMP__ |
|
25 #include <nkern/nkern.h> |
|
26 #else |
|
27 #include <nkernsmp/nkern.h> |
|
28 #endif //__SMP__ |
|
29 #include <TraceCoreTraceActivationIf.h> |
|
30 #include <TraceCoreNotificationReceiver.h> |
|
31 #include "TraceCore.h" |
|
32 #include "d_tracecore.h" |
|
33 |
|
34 |
|
35 #include "TraceCoreTestWriter.h" |
|
36 #include "TestDataWriterNotifier.h" |
|
37 |
|
38 const TInt KFrameBufferLength = 4096; |
|
39 |
|
40 class DTraceCoreTestFactory : public DLogicalDevice |
|
41 { |
|
42 public: |
|
43 virtual TInt Install(); |
|
44 virtual void GetCaps(TDes8& aDes) const; |
|
45 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
46 }; |
|
47 |
|
48 class DTraceCoreTestChannel : public DLogicalChannel, MTestWriterNotifier, MTraceCoreNotificationReceiver |
|
49 { |
|
50 public: |
|
51 DTraceCoreTestChannel(); |
|
52 virtual ~DTraceCoreTestChannel(); |
|
53 // Inherited from DObject |
|
54 virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType); |
|
55 // Inherited from DLogicalChannelBase |
|
56 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); |
|
57 virtual void HandleMsg(TMessageBase* aMsg); |
|
58 TInt DoControl(TInt aFunction, TAny* a1, TAny* a2); |
|
59 TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); |
|
60 |
|
61 // Virtual from MTraceCoreNotificationReceiver. Called from TraceCore. |
|
62 void TraceActivated( TUint32 aComponentId, TUint16 aGroupId ); |
|
63 void TraceDeactivated( TUint32 aComponentId, TUint16 aGroupId ); |
|
64 |
|
65 |
|
66 private: |
|
67 DThread* iClient; |
|
68 |
|
69 private: |
|
70 void ActivateTrace(TcDriverParameters& aDriverParameters, TInt aNumTraces); |
|
71 void DeactivateTrace(TcDriverParameters& aDriverParameters, TInt aNumTraces); |
|
72 TInt RefreshActivations(); |
|
73 TInt ValidateFilterSync(TcDriverParameters& aDriverParams); |
|
74 void DropNextTrace(TBool aDrop); |
|
75 void RegisterActivationNotification(TcDriverParameters& aDriverParameters, TBool aRegister); |
|
76 TInt CheckActivationNotificationOk(TBool aShouldBeNotified); |
|
77 |
|
78 TInt CreateWriter(); |
|
79 // from MTestWriterNotifier |
|
80 virtual void WriteComplete(TNotifyData aData); |
|
81 virtual void WriteStart(); |
|
82 private: |
|
83 |
|
84 TRequestStatus* iTraceDataRequestStatus; // request status for asynct trace requests |
|
85 TDes8* iTraceDataDestination; // pointer to write trace data to |
|
86 TDynamicDfcQue* iOstTestDriverDfcQ; // Dedicated non-realtime DfcQ |
|
87 TBool iDropTrace; // if test doesn't want trace to actually be sent |
|
88 TInt iFrameCount; // Number of frames to capture before notify is issued |
|
89 TBuf8<KFrameBufferLength> iFrameBuffer; // the frame buffer |
|
90 TBool iFilterInSyncWhenNotified; // If true, filter in TraceCore was in sync with the notification |
|
91 TBool iNotificationReceived; // If true, trace activation notification was received |
|
92 }; |
|
93 |
|
94 const TInt KTestOstDriverThreadPriority = 24; |
|
95 _LIT(KTestOstDriverThread,"d_tracecore_dfcq"); |
|
96 |
|
97 |
|
98 // |
|
99 // DTraceCoreTestFactory |
|
100 // |
|
101 |
|
102 TInt DTraceCoreTestFactory::Install() |
|
103 { |
|
104 return SetName(&RTraceCoreTest::Name()); |
|
105 } |
|
106 |
|
107 void DTraceCoreTestFactory::GetCaps(TDes8& aDes) const |
|
108 { |
|
109 Kern::InfoCopy(aDes,0,0); |
|
110 } |
|
111 |
|
112 TInt DTraceCoreTestFactory::Create(DLogicalChannelBase*& aChannel) |
|
113 { |
|
114 aChannel=new DTraceCoreTestChannel(); |
|
115 if(!aChannel) |
|
116 return KErrNoMemory; |
|
117 return KErrNone; |
|
118 } |
|
119 |
|
120 |
|
121 // |
|
122 // DTraceCoreTestChannel |
|
123 // |
|
124 |
|
125 DTraceCoreTestChannel::DTraceCoreTestChannel() |
|
126 : iTraceDataRequestStatus(NULL) |
|
127 , iTraceDataDestination(NULL) |
|
128 , iDropTrace(EFalse) |
|
129 , iFilterInSyncWhenNotified(EFalse) |
|
130 { |
|
131 } |
|
132 |
|
133 DTraceCoreTestChannel::~DTraceCoreTestChannel() |
|
134 { |
|
135 // Detatch (stop notifications) from writer |
|
136 DTraceCoreTestWriter* testWriter = DTraceCoreTestWriter::GetInstance(); |
|
137 if(testWriter) |
|
138 { |
|
139 testWriter->SetNotifier(NULL); |
|
140 } |
|
141 delete testWriter; |
|
142 |
|
143 //destroy dfcq |
|
144 if (iOstTestDriverDfcQ) |
|
145 { |
|
146 iOstTestDriverDfcQ->Destroy(); |
|
147 } |
|
148 } |
|
149 |
|
150 TInt DTraceCoreTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) |
|
151 { |
|
152 TDynamicDfcQue* q; |
|
153 TInt ret = Kern::DynamicDfcQCreate(q, KTestOstDriverThreadPriority , KTestOstDriverThread); |
|
154 if (ret==KErrNone) |
|
155 { |
|
156 //disable real-time state of the dfcq |
|
157 q->SetRealtimeState(ERealtimeStateOff); |
|
158 iOstTestDriverDfcQ=q; |
|
159 SetDfcQ(iOstTestDriverDfcQ); |
|
160 iMsgQ.Receive(); |
|
161 } |
|
162 else |
|
163 { |
|
164 Kern::Printf("Kern::DynamicDfcQCreate returned with error: %d",ret); |
|
165 return ret; |
|
166 } |
|
167 iClient = &Kern::CurrentThread(); |
|
168 return CreateWriter(); |
|
169 } |
|
170 |
|
171 void DTraceCoreTestChannel::WriteStart() |
|
172 { |
|
173 } |
|
174 |
|
175 void DTraceCoreTestChannel::WriteComplete(TNotifyData aNotifyData) |
|
176 { |
|
177 |
|
178 if(iTraceDataRequestStatus && iFrameCount > 0 ) |
|
179 { |
|
180 |
|
181 // append the data into the frame buffer if it fits |
|
182 if( iFrameBuffer.Length() + aNotifyData.iLen < KFrameBufferLength) |
|
183 { |
|
184 iFrameBuffer.Append(TPtrC8((TUint8*)aNotifyData.iAddr, aNotifyData.iLen )); |
|
185 } |
|
186 else |
|
187 { |
|
188 // force a send of what we have |
|
189 iFrameCount = 1; |
|
190 } |
|
191 |
|
192 if( --iFrameCount == 0) |
|
193 { |
|
194 if (iDropTrace) |
|
195 { |
|
196 // test client is requesting we force tracecore to drop the next trace |
|
197 // so we call the same function that a writer would call ( SetPreviousTraceDropped ) |
|
198 // in order to notify tracecore that a trace has been dropped |
|
199 DTraceCore* tracecore = DTraceCore::GetInstance(); |
|
200 tracecore->SetPreviousTraceDropped(ETrue); |
|
201 } |
|
202 else//send the trace |
|
203 { |
|
204 Kern::KUDesPut(*iTraceDataDestination,iFrameBuffer); |
|
205 } |
|
206 |
|
207 // complete the clients request |
|
208 Kern::RequestComplete(iTraceDataRequestStatus, 0); |
|
209 iTraceDataRequestStatus = NULL; |
|
210 iFrameBuffer.Zero(); |
|
211 } |
|
212 } |
|
213 } |
|
214 |
|
215 TInt DTraceCoreTestChannel::CreateWriter() |
|
216 { |
|
217 TInt r = KErrNoMemory; |
|
218 DTraceCoreTestWriter* testWriter = DTraceCoreTestWriter::GetInstance(); |
|
219 if(testWriter) |
|
220 { |
|
221 r = KErrNone; |
|
222 testWriter->SetNotifier(this); |
|
223 } |
|
224 return r; |
|
225 } |
|
226 |
|
227 TInt DTraceCoreTestChannel::RequestUserHandle(DThread* aThread, TOwnerType aType) |
|
228 { |
|
229 if (aType!=EOwnerThread || aThread!=iClient) |
|
230 return KErrAccessDenied; |
|
231 return KErrNone; |
|
232 } |
|
233 |
|
234 void DTraceCoreTestChannel::HandleMsg(TMessageBase* aMsg) |
|
235 { |
|
236 TThreadMessage& msg = *(static_cast<TThreadMessage*>(aMsg)); |
|
237 TInt id = msg.iValue; |
|
238 |
|
239 if ( id == static_cast<TInt>( ECloseMsg ) ) |
|
240 { |
|
241 |
|
242 // Don't receive any more messages |
|
243 msg.Complete( KErrNone, EFalse ); |
|
244 |
|
245 // Complete all outstanding messages on this queue |
|
246 iMsgQ.CompleteAll( KErrServerTerminated ); |
|
247 } |
|
248 else if ( id == KMaxTInt ) |
|
249 { |
|
250 // 'DoCancel' message |
|
251 TRequestStatus* pS = reinterpret_cast<TRequestStatus*>( msg.Ptr0() ); |
|
252 Kern::RequestComplete(iClient,pS,KErrCancel); |
|
253 msg.Complete( KErrNone, ETrue ); |
|
254 } |
|
255 else if ( id < 0 ) |
|
256 { |
|
257 // DoRequest |
|
258 TRequestStatus* pS = reinterpret_cast<TRequestStatus*>( msg.Ptr0() ); |
|
259 |
|
260 TInt ret = DoRequest( ~id, pS, msg.Ptr1(), msg.Ptr2()); |
|
261 if ( ret != KErrNone ) |
|
262 { |
|
263 Kern::RequestComplete( iClient, pS, ret ); |
|
264 }//noelse |
|
265 |
|
266 msg.Complete( KErrNone, ETrue ); |
|
267 } |
|
268 else |
|
269 { |
|
270 // DoControl |
|
271 TInt ret = DoControl( id, msg.Ptr0(), msg.Ptr1() ); |
|
272 msg.Complete( ret, ETrue ); |
|
273 } |
|
274 |
|
275 } |
|
276 |
|
277 TInt DTraceCoreTestChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) |
|
278 { |
|
279 switch(aFunction) |
|
280 { |
|
281 // test functions |
|
282 case RTraceCoreTest::EActivateTrace: |
|
283 { |
|
284 // Kern::Printf("DTraceCoreTestChannel::DoControl() RTraceCoreTest::EActivateTrace"); |
|
285 TcDriverParameters* tcDriverParameters = static_cast<TcDriverParameters*>(a1); |
|
286 __ASSERT_ALWAYS(tcDriverParameters!=NULL, Kern::Fault("DTraceCoreTestChannel::DoControl: NULL parameter!", __LINE__) ); |
|
287 ActivateTrace(*tcDriverParameters, (TInt)(a2)); |
|
288 return KErrNone; |
|
289 } |
|
290 case RTraceCoreTest::EDeactivateTrace: |
|
291 { |
|
292 // Kern::Printf("DTraceCoreTestChannel::DoControl() RTraceCoreTest::EDeactivateTrace"); |
|
293 TcDriverParameters* tcDriverParameters = static_cast<TcDriverParameters*>(a1); |
|
294 __ASSERT_ALWAYS(tcDriverParameters!=NULL, Kern::Fault("DTraceCoreTestChannel::DoControl: NULL parameter!", __LINE__) ); |
|
295 DeactivateTrace(*tcDriverParameters, (TInt)(a2)); |
|
296 return KErrNone; |
|
297 } |
|
298 case RTraceCoreTest::ERefreshActivations: |
|
299 { |
|
300 // Kern::Printf("DTraceCoreTestChannel::DoControl() RTraceCoreTest::ERefreshActivations"); |
|
301 return RefreshActivations(); |
|
302 } |
|
303 |
|
304 case RTraceCoreTest::EValidateFilterSync: |
|
305 { |
|
306 // Kern::Printf("DTraceCoreTestChannel::ReqDoControluest() RTraceCoreTest::EValidateFilterSync"); |
|
307 TcDriverParameters* tcDriverParameters = static_cast<TcDriverParameters*>(a1); |
|
308 __ASSERT_ALWAYS(tcDriverParameters!=NULL, Kern::Fault("DTraceCoreTestChannel::DoControl: NULL parameter!", __LINE__) ); |
|
309 return ValidateFilterSync(*tcDriverParameters); |
|
310 } |
|
311 |
|
312 case RTraceCoreTest::EDropNextTrace: |
|
313 { |
|
314 // Kern::Printf("DTraceCoreTestChannel::DoControl() RTraceCoreTest::EDropNextTrace"); |
|
315 DropNextTrace(TBool(a1)); |
|
316 return KErrNone; |
|
317 } |
|
318 case RTraceCoreTest::ERegisterActivationNotification: |
|
319 { |
|
320 // Kern::Printf("DTraceCoreTestChannel::DoControl() RTraceCoreTest::ERegisterActivationNotification"); |
|
321 TcDriverParameters* tcDriverParameters = static_cast<TcDriverParameters*>(a1); |
|
322 __ASSERT_ALWAYS(tcDriverParameters!=NULL, Kern::Fault("DTraceCoreTestChannel::DoControl: NULL parameter!", __LINE__) ); |
|
323 RegisterActivationNotification(*tcDriverParameters, (TBool)(a2)); |
|
324 return KErrNone; |
|
325 } |
|
326 case RTraceCoreTest::ECheckActivationNotificationOk: |
|
327 { |
|
328 // Kern::Printf("DTraceCoreTestChannel::DoControl() RTraceCoreTest::ECheckActivationNotificationOk"); |
|
329 return CheckActivationNotificationOk((TBool)(a1)); |
|
330 } |
|
331 |
|
332 default: |
|
333 break; |
|
334 } |
|
335 return KErrNotSupported; |
|
336 } |
|
337 |
|
338 TInt DTraceCoreTestChannel::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2) |
|
339 { |
|
340 switch(aId) |
|
341 { |
|
342 case RTraceCoreTest::ERequestTraceData: // async request |
|
343 { |
|
344 iTraceDataRequestStatus = aStatus; |
|
345 if(a1) |
|
346 { |
|
347 TDes8* p = NULL; |
|
348 XTRAPD(r, XT_DEFAULT, kumemget(&p, &a1, sizeof(TAny*)); ) |
|
349 iTraceDataDestination = (r == KErrNone) ? p : NULL; |
|
350 } |
|
351 |
|
352 iFrameCount = (a2) ? (TInt)a2 : 1; |
|
353 iFrameBuffer.Zero(); |
|
354 |
|
355 return KErrNone; |
|
356 } |
|
357 |
|
358 default: |
|
359 break; |
|
360 } |
|
361 return KErrNotSupported; |
|
362 } |
|
363 |
|
364 void DTraceCoreTestChannel::ActivateTrace(TcDriverParameters& aDriverParameters, TInt aNumTraces) |
|
365 { |
|
366 TcDriverParameters tcDriverParams; |
|
367 TInt ret = Kern::ThreadRawRead(iClient, (const TAny *)&aDriverParameters,(TAny*)&tcDriverParams, sizeof(TcDriverParameters) ); |
|
368 __ASSERT_ALWAYS(KErrDied!=ret, Kern::Fault("DTraceCoreTestChannel::ActivateTrace: ThreadRawRead: iClient died!", __LINE__) ); |
|
369 |
|
370 NKern::ThreadEnterCS(); |
|
371 for (TInt i=0; i<aNumTraces; i++) |
|
372 { |
|
373 DTraceActivationIf::ActivateTrace((tcDriverParams.iComponentId)+i,(tcDriverParams.iGroupId)+i); |
|
374 } |
|
375 NKern::ThreadLeaveCS(); |
|
376 } |
|
377 |
|
378 void DTraceCoreTestChannel::DeactivateTrace(TcDriverParameters& aDriverParameters, TInt aNumTraces) |
|
379 { |
|
380 TcDriverParameters tcDriverParams; |
|
381 TInt ret = Kern::ThreadRawRead(iClient, (const TAny *)&aDriverParameters,(TAny*)&tcDriverParams, sizeof(TcDriverParameters) ); |
|
382 __ASSERT_ALWAYS(KErrDied!=ret,Kern::Fault("DTraceCoreTestChannel::DeactivateTrace: ThreadRawRead: iClient died!", __LINE__) ); |
|
383 |
|
384 NKern::ThreadEnterCS(); |
|
385 for (TInt i=0; i<aNumTraces; i++) |
|
386 { |
|
387 DTraceActivationIf::DeactivateTrace((tcDriverParams.iComponentId)+i,(tcDriverParams.iGroupId)+i); |
|
388 } |
|
389 NKern::ThreadLeaveCS(); |
|
390 } |
|
391 |
|
392 TInt DTraceCoreTestChannel::RefreshActivations() |
|
393 { |
|
394 NKern::ThreadEnterCS(); |
|
395 TInt err = DTraceActivationIf::RefreshActivations(); |
|
396 NKern::ThreadLeaveCS(); |
|
397 return err; |
|
398 } |
|
399 |
|
400 /** |
|
401 * Validate that the BTrace::Filter matches the tracecore filters |
|
402 * for all OST categories |
|
403 * |
|
404 * returns KErrNone if filters match - KErrGeneral otherwise |
|
405 */ |
|
406 TInt DTraceCoreTestChannel::ValidateFilterSync(TcDriverParameters& aDriverParameters) |
|
407 { |
|
408 TcDriverParameters tcDriverParams; |
|
409 TInt ret = Kern::ThreadRawRead(iClient, (const TAny *)&aDriverParameters,(TAny*)&tcDriverParams, sizeof(TcDriverParameters) ); |
|
410 __ASSERT_ALWAYS(ret == KErrNone, Kern::Fault("DTraceCoreTestChannel::ValidateFilterSync: ThreadRawRead: iClient died!", __LINE__) ); |
|
411 |
|
412 TBool tcFilter = DTraceActivationIf::IsTraceActivated(tcDriverParams.iComponentId, tcDriverParams.iGroupId); |
|
413 TBool btFilter = BTrace::CheckFilter(tcDriverParams.iGroupId); |
|
414 if( tcFilter != btFilter) |
|
415 { |
|
416 ret = KErrGeneral; |
|
417 } |
|
418 |
|
419 return ret; |
|
420 } |
|
421 |
|
422 /** |
|
423 * Adds or removes a activation notification listener |
|
424 * |
|
425 * returns KErrNone if filters match - KErrGeneral otherwise |
|
426 */ |
|
427 void DTraceCoreTestChannel::RegisterActivationNotification(TcDriverParameters& aDriverParameters, TBool aRegister) |
|
428 { |
|
429 TcDriverParameters tcDriverParams; |
|
430 TInt ret = Kern::ThreadRawRead(iClient, (const TAny *)&aDriverParameters,(TAny*)&tcDriverParams, sizeof(TcDriverParameters) ); |
|
431 __ASSERT_ALWAYS(ret == KErrNone, Kern::Fault("DTraceCoreTestChannel::ValidateFilterSync: ThreadRawRead: iClient died!", __LINE__) ); |
|
432 |
|
433 if (aRegister) |
|
434 { |
|
435 MTraceCoreNotificationReceiver::RegisterNotificationReceiver(tcDriverParams.iComponentId, tcDriverParams.iGroupId); |
|
436 } |
|
437 else |
|
438 { |
|
439 MTraceCoreNotificationReceiver::UnregisterNotificationReceiver(tcDriverParams.iComponentId, tcDriverParams.iGroupId); |
|
440 } |
|
441 } |
|
442 |
|
443 /** |
|
444 * Add a activation notification listener, then activate a trace group and check if the activation |
|
445 * has really happened when the notification arrives |
|
446 * |
|
447 * returns KErrNone if filters match - KErrGeneral otherwise |
|
448 */ |
|
449 TInt DTraceCoreTestChannel::CheckActivationNotificationOk(TBool aShouldBeNotified) |
|
450 { |
|
451 TInt ret = KErrGeneral; |
|
452 |
|
453 // Everything OK if we should've got notification and we got and filters were in sync |
|
454 if (aShouldBeNotified && iNotificationReceived && iFilterInSyncWhenNotified) |
|
455 { |
|
456 ret = KErrNone; |
|
457 } |
|
458 |
|
459 // Everything OK if we should NOT got notification and we didn't |
|
460 else if (!aShouldBeNotified && !iNotificationReceived) |
|
461 { |
|
462 ret = KErrNone; |
|
463 } |
|
464 |
|
465 // Reset the variables for next test |
|
466 iFilterInSyncWhenNotified = EFalse; |
|
467 iNotificationReceived = EFalse; |
|
468 |
|
469 return ret; |
|
470 } |
|
471 |
|
472 /** |
|
473 * Callback function from TraceCore when the trace is activated |
|
474 */ |
|
475 void DTraceCoreTestChannel::TraceActivated( TUint32 aComponentId, TUint16 aGroupId ) |
|
476 { |
|
477 TBool tcFilter = DTraceActivationIf::IsTraceActivated(aComponentId, aGroupId); |
|
478 iFilterInSyncWhenNotified = tcFilter; |
|
479 iNotificationReceived = ETrue; |
|
480 } |
|
481 |
|
482 /** |
|
483 * Callback function from TraceCore when the trace is deactivated |
|
484 */ |
|
485 void DTraceCoreTestChannel::TraceDeactivated( TUint32 aComponentId, TUint16 aGroupId ) |
|
486 { |
|
487 TBool tcFilter = DTraceActivationIf::IsTraceActivated(aComponentId, aGroupId); |
|
488 iFilterInSyncWhenNotified = !tcFilter; |
|
489 iNotificationReceived = ETrue; |
|
490 } |
|
491 |
|
492 /* |
|
493 * Tells the test writer that we don't actually want to |
|
494 * send a trace... this is to test that the handlers |
|
495 * are formatting the data to include "missing" info. |
|
496 */ |
|
497 void DTraceCoreTestChannel::DropNextTrace(TBool aDrop) |
|
498 { |
|
499 iDropTrace=aDrop; |
|
500 } |
|
501 |
|
502 DECLARE_STANDARD_LDD() |
|
503 { |
|
504 Kern::Printf("d_tracecore.ldd creating DTraceCoreTestFactory"); |
|
505 return new DTraceCoreTestFactory; |
|
506 } |
|
507 |
|
508 |