|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32cons.h> |
|
20 #include <e32base.h> |
|
21 #include <f32file.h> |
|
22 #include <c32comm.h> |
|
23 #include <s32file.h> |
|
24 #include <pathinfo.h> |
|
25 #include <s32mem.h> |
|
26 #include <bautils.h> |
|
27 #include <sysutil.h> |
|
28 #include <piprofiler/ProfilerConfig.h> |
|
29 #include "ProfilerEngine.h" |
|
30 #include <piprofiler/ProfilerTraces.h> |
|
31 |
|
32 // properties |
|
33 const TUid KEngineStatusPropertyCat={0x2001E5AD}; |
|
34 enum TEnginePropertyKeys |
|
35 { |
|
36 EProfilerEngineStatus = 8, |
|
37 EProfilerErrorStatus |
|
38 }; |
|
39 |
|
40 static _LIT_SECURITY_POLICY_PASS( KAllowAllPolicy ); |
|
41 |
|
42 // CONSTANTS |
|
43 const TInt KStreamBufferSize = 32768; |
|
44 const TInt KSavedLineCount = 64; |
|
45 const TInt KFileNameBufSize = 128; |
|
46 // Use this UID if plugin belongs to DebOutWriterPlugin: |
|
47 const TUid KDebOutWriterPluginUid = { 0x2001E5BA }; |
|
48 // Use this UID if plugin belongs to MmcOutWriterPlugin: |
|
49 const TUid KDiskWriterPluginUid = { 0x2001E5BB }; |
|
50 |
|
51 // LITERALS |
|
52 _LIT8(KGenericTraceOutput, "output_type"); |
|
53 _LIT8(KGenericTraceFilePrefix, "file_prefix"); |
|
54 _LIT8(KGenericTraceFileSaveDrive, "save_file_location"); |
|
55 _LIT8(KGenericTimedProfilingPeriod, "profiling_period"); |
|
56 _LIT8(KEquals, "="); |
|
57 _LIT8(KNewLineSeparator, "\n"); |
|
58 _LIT8(KProfilerVersionTag, "version"); |
|
59 _LIT8(KEndMark, "[end]"); |
|
60 _LIT8(KOutputToDebugOutput, "debug_output"); |
|
61 |
|
62 /** |
|
63 * |
|
64 * The controller class used to provide the Profiler functions. |
|
65 * This runs as a server in the engine thread |
|
66 * |
|
67 */ |
|
68 class CPServer : public CServer2, public MProfilerController |
|
69 { |
|
70 public: |
|
71 static MProfilerController* NewL(TInt aPriority, MProfilerEngine& aEngine); |
|
72 |
|
73 private: |
|
74 CPServer(TInt aPriority, MProfilerEngine& aEngine); |
|
75 void Release(); |
|
76 CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const; |
|
77 |
|
78 public: |
|
79 static TInt iClientCount; |
|
80 }; |
|
81 |
|
82 TInt CPServer::iClientCount = 0; |
|
83 |
|
84 // The session class used by the server controller |
|
85 class CPSession : public CSession2 |
|
86 { |
|
87 private: |
|
88 inline const CPServer& Server() const; |
|
89 void ServiceL(const RMessage2& aMessage); |
|
90 }; |
|
91 |
|
92 /* |
|
93 * |
|
94 * CProfiler class implementation |
|
95 * |
|
96 */ |
|
97 // -------------------------------------------------------------------------------------------- |
|
98 CProfiler* CProfiler::NewLC(const TDesC& aSettingsFile) |
|
99 { |
|
100 CProfiler* self = new(ELeave) CProfiler(aSettingsFile); |
|
101 CleanupStack::PushL(self); |
|
102 self->ConstructL(); |
|
103 return self; |
|
104 } |
|
105 |
|
106 // -------------------------------------------------------------------------------------------- |
|
107 CProfiler::CProfiler(const TDesC& aSettingsFile) : |
|
108 iSettingsFileLocation(aSettingsFile) |
|
109 { |
|
110 // define property for Profiler Engine status, UI may read it for control purposes |
|
111 if ( RProperty::Define(KEngineStatusPropertyCat, |
|
112 EProfilerEngineStatus, |
|
113 RProperty::EInt, |
|
114 KAllowAllPolicy, |
|
115 KAllowAllPolicy, |
|
116 0) != KErrAlreadyExists ) |
|
117 { |
|
118 LOGTEXT(_L("CProfiler::CProfiler - status property already defined")); |
|
119 } |
|
120 |
|
121 if ( RProperty::Define(KEngineStatusPropertyCat, |
|
122 EProfilerErrorStatus, |
|
123 RProperty::EInt, |
|
124 KAllowAllPolicy, |
|
125 KAllowAllPolicy, |
|
126 0) != KErrAlreadyExists ) |
|
127 { |
|
128 LOGTEXT(_L("CProfiler::CProfiler - status property already defined")); |
|
129 } |
|
130 |
|
131 // attach to own property |
|
132 iEngineStatus.Attach(KEngineStatusPropertyCat, EProfilerEngineStatus); |
|
133 // set status idle |
|
134 iEngineStatus.Set(KEngineStatusPropertyCat, EProfilerEngineStatus, RProfiler::EIdle); |
|
135 |
|
136 // attach to own property |
|
137 iUpdateStatus.Attach(KEngineStatusPropertyCat, EProfilerErrorStatus); |
|
138 // set status idle |
|
139 iUpdateStatus.Set(KEngineStatusPropertyCat, EProfilerErrorStatus, EFalse); |
|
140 } |
|
141 |
|
142 // -------------------------------------------------------------------------------------------- |
|
143 CProfiler::~CProfiler() |
|
144 { |
|
145 LOGTEXT(_L("CProfiler::~CProfiler - Enter")); |
|
146 |
|
147 // delete error checker |
|
148 if(iErrorChecker) |
|
149 { |
|
150 iErrorChecker->Cancel(); |
|
151 delete iErrorChecker; |
|
152 iErrorChecker = NULL; |
|
153 } |
|
154 |
|
155 // delete settings array |
|
156 if(iDefaultSamplerAttributesArray) |
|
157 { |
|
158 iDefaultSamplerAttributesArray->Reset(); |
|
159 delete iDefaultSamplerAttributesArray; |
|
160 iDefaultSamplerAttributesArray = NULL; |
|
161 } |
|
162 |
|
163 // delete settings file raw line array |
|
164 if(iSavedLineArray) |
|
165 { |
|
166 iSavedLineArray->Reset(); |
|
167 delete iSavedLineArray; |
|
168 iSavedLineArray = NULL; |
|
169 } |
|
170 |
|
171 // delete sampler controller, cleans up the sampler plugin instances |
|
172 if(iSamplerHandler) |
|
173 { |
|
174 delete iSamplerHandler; |
|
175 iSamplerHandler = NULL; |
|
176 } |
|
177 // delete writer controller, cleans up the writer plugin instances |
|
178 if(iWriterHandler) |
|
179 { |
|
180 delete iWriterHandler; |
|
181 iWriterHandler = NULL; |
|
182 } |
|
183 |
|
184 // delete user side sampler stream |
|
185 if(iUserStream) |
|
186 { |
|
187 delete iUserStream; |
|
188 iUserStream = NULL; |
|
189 } |
|
190 |
|
191 // close engine status property |
|
192 iEngineStatus.Close(); |
|
193 if (RProperty::Delete(KEngineStatusPropertyCat, EProfilerEngineStatus) != KErrNotFound) |
|
194 { |
|
195 LOGTEXT(_L("CProfiler::~CProfiler - cannot close status property")); |
|
196 } |
|
197 // close engine update property |
|
198 iUpdateStatus.Close(); |
|
199 if (RProperty::Delete(KEngineStatusPropertyCat, EProfilerErrorStatus) != KErrNotFound) |
|
200 { |
|
201 LOGTEXT(_L("CProfiler::~CProfiler - cannot close update property")); |
|
202 } |
|
203 |
|
204 // close server process |
|
205 if (iServer) |
|
206 { |
|
207 LOGTEXT(_L("CProfiler::~CProfiler - Releasing server")); |
|
208 iServer->Release(); |
|
209 } |
|
210 |
|
211 if( iTimer ) |
|
212 { |
|
213 iTimer->Cancel(); |
|
214 delete iTimer; |
|
215 iTimer = 0; |
|
216 } |
|
217 |
|
218 LOGTEXT(_L("CProfiler::~CProfiler - Finished")); |
|
219 } |
|
220 |
|
221 // -------------------------------------------------------------------------------------------- |
|
222 void CProfiler::ConstructL() |
|
223 { |
|
224 LOGTEXT(_L("CProfiler::ConstructL - Enter")); |
|
225 TInt err(0); |
|
226 TLex lex; |
|
227 |
|
228 if ( iSettingsFileLocation.CompareF(KNullDesC) != 0 ) |
|
229 { |
|
230 lex=(iSettingsFileLocation); |
|
231 // parse the first command line argument, the command itself |
|
232 lex.Mark(); |
|
233 lex.SkipCharacters(); |
|
234 if(lex.TokenLength() != 0) |
|
235 { |
|
236 // there is another item in the list |
|
237 TPtrC filename = lex.MarkedToken(); |
|
238 LOGSTRING2("filename %S", &filename); |
|
239 lex.SkipSpace(); |
|
240 lex.Mark(); |
|
241 lex.SkipCharacters(); |
|
242 if(lex.TokenLength() != 0) |
|
243 { |
|
244 TPtrC boot = lex.MarkedToken(); |
|
245 LOGTEXT(_L("boot mode")); |
|
246 } |
|
247 } |
|
248 } |
|
249 |
|
250 // create new sampler stream instance |
|
251 iUserStream = CProfilerSampleStream::NewL(KStreamBufferSize); |
|
252 if(!iUserStream) |
|
253 { |
|
254 LOGTEXT(_L("Profiler engine cannot reserve memory")); |
|
255 User::Leave(KErrCancel); // operation cancelled |
|
256 } |
|
257 |
|
258 // engine status checker |
|
259 iErrorChecker = CProfilerErrorChecker::NewL(); |
|
260 iErrorChecker->SetObserver(this); |
|
261 |
|
262 // create and initiate plug-in controller instances |
|
263 iSamplerHandler = CSamplerController::NewL(*iUserStream); |
|
264 iWriterHandler = CWriterController::NewL(*iUserStream); |
|
265 |
|
266 iWriterHandler->InitialiseWriterListL(); |
|
267 |
|
268 // set engine as an observer to sampler controller to get the notification of plugin load has ended |
|
269 iSamplerHandler->SetObserver(this); |
|
270 |
|
271 // default settings from sampler plugins, maximum 20 sampler plugins |
|
272 iDefaultSamplerAttributesArray = new(ELeave) CArrayFixFlat<TSamplerAttributes>(20); |
|
273 |
|
274 // set profiler status to initializing |
|
275 iState = RProfiler::EInitializing; |
|
276 iEngineStatus.Set(RProfiler::EInitializing); |
|
277 |
|
278 // set default general settings, will be overdriven if changed in settings file |
|
279 iGeneralAttributes.iTraceOutput.Copy(KDefaultTraceOutput); |
|
280 iGeneralAttributes.iTraceFilePrefix.Copy(KDefaultTraceFilePrefix); |
|
281 iGeneralAttributes.iSaveFileDrive.Copy(KDefaultTraceFileSaveDrive); |
|
282 iGeneralAttributes.iTimedSamplingPeriod = KDefaultTimedSamplingPeriod; |
|
283 |
|
284 RThread me; |
|
285 |
|
286 me.SetPriority(EPriorityRealTime); |
|
287 |
|
288 err = KErrGeneral; |
|
289 TInt count = 0; |
|
290 |
|
291 while(err != KErrNone && count < 30) |
|
292 { |
|
293 err = User::RenameThread(KProfilerName); |
|
294 if(err != KErrNone) |
|
295 { |
|
296 LOGSTRING2("CProfiler: error renaming the thread, err %d", err); |
|
297 User::Leave(err); |
|
298 } |
|
299 else break; |
|
300 } |
|
301 |
|
302 // set settings file loading preferences |
|
303 iSettingsFileLoaded = EFalse; |
|
304 |
|
305 // change status property to idle since initialization successfull |
|
306 iState = RProfiler::EIdle; |
|
307 if( iEngineStatus.Set((TInt)RProfiler::EIdle) != KErrNone ) |
|
308 { |
|
309 LOGTEXT(_L("CProfiler::ConstructL - engine status property change failed")); |
|
310 } |
|
311 |
|
312 if( iUpdateStatus.Set(EFalse) != KErrNone ) |
|
313 { |
|
314 LOGTEXT(_L("CProfiler::ConstructL - engine status property change failed")); |
|
315 } |
|
316 |
|
317 // create a server instance for clients to communicate with |
|
318 iServer = CPServer::NewL(10,*this); |
|
319 |
|
320 // close the handle |
|
321 me.Close(); |
|
322 |
|
323 iTimer = CProfilerTimer::NewL(CActive::EPriorityStandard, *this); |
|
324 |
|
325 LOGTEXT(_L("CProfiler::ConstructL - Exit")); |
|
326 |
|
327 } |
|
328 |
|
329 CProfilerSampleStream* CProfiler::GetSamplerStream() |
|
330 { |
|
331 return iUserStream; |
|
332 } |
|
333 |
|
334 void CProfiler::HandleSamplerControllerReadyL() |
|
335 { |
|
336 // load settings |
|
337 // check if settings file already loaded |
|
338 if(!iSettingsFileLoaded) |
|
339 { |
|
340 // load default settings file |
|
341 LoadSettingsL(); |
|
342 |
|
343 iSettingsFileLoaded = ETrue; |
|
344 } |
|
345 |
|
346 // notify engine's launcher(UI or PIProfilerLauncher) to continue launch |
|
347 RProcess::Rendezvous(KErrNone); |
|
348 } |
|
349 |
|
350 void CProfiler::NotifyRequesterForSettingsUpdate() |
|
351 { |
|
352 // set update status P&S property true => update needed on UI side |
|
353 iUpdateStatus.Set(ETrue); |
|
354 } |
|
355 |
|
356 void CProfiler::HandleProfilerErrorChangeL(TInt aError) |
|
357 { |
|
358 LOGSTRING2("CProfiler::HandleProfilerErrorChangeL() - error received, %d", aError); |
|
359 |
|
360 // check if profiler running |
|
361 if(iState == RProfiler::ERunning) |
|
362 { |
|
363 // stop profiler if error occurred during the trace |
|
364 iEngineStatus.Set(aError); |
|
365 |
|
366 // stop samplers, NOTE! Writer plugins not stopped since |
|
367 iSamplerHandler->StopSamplerPlugins(); |
|
368 |
|
369 // stop debug output plugin and write the rest of the trace data to output |
|
370 if(iGeneralAttributes.iTraceOutput.CompareF(KOutputToDebugOutput) == 0) |
|
371 { |
|
372 // write the rest of trace data only if debug output selected |
|
373 iWriterHandler->StopSelectedPlugin(); |
|
374 } |
|
375 LOGSTRING2("CProfiler::HandleProfilerErrorChangeL - sampling stopped, going to state %d", RProfiler::EIdle); |
|
376 } |
|
377 } |
|
378 |
|
379 // ---------------------------------------------------------------------------- |
|
380 // Gets a value from settings file for certain attribute. |
|
381 // ---------------------------------------------------------------------------- |
|
382 void CProfiler::DoGetValueFromSettingsArray(CDesC8ArrayFlat* aLineArray, const TDesC8& aAttribute, TDes8& aValue) |
|
383 { |
|
384 LOGTEXT(_L("CProfiler::DoGetValueFromSettingsFile()")); |
|
385 _LIT8(KSettingItemSeparator, "="); |
|
386 |
|
387 // read a line of given array |
|
388 for (TInt i=0; i<aLineArray->MdcaCount(); i++) |
|
389 { |
|
390 // check if this line has a separator |
|
391 TInt sepPos = aLineArray->MdcaPoint(i).Find(KSettingItemSeparator); |
|
392 if (sepPos > 0) |
|
393 { |
|
394 // check that the element matches |
|
395 if (aLineArray->MdcaPoint(i).Left(sepPos).CompareF(aAttribute) == 0) |
|
396 { |
|
397 // get the value |
|
398 aValue.Copy(aLineArray->MdcaPoint(i).Right(aLineArray->MdcaPoint(i).Length()-sepPos-1)); |
|
399 break; |
|
400 } |
|
401 } |
|
402 } |
|
403 } |
|
404 |
|
405 void CProfiler::DoGetValueFromSettingsArray(CDesC8ArrayFlat* aLineArray, const TDesC8& aAttribute, TInt& aValue) |
|
406 { |
|
407 LOGTEXT(_L("CProfiler::DoGetValueFromSettingsFile()")); |
|
408 _LIT8(KSettingItemSeparator, "="); |
|
409 |
|
410 // read a line of given array |
|
411 for (TInt i=0; i<aLineArray->MdcaCount(); i++) |
|
412 { |
|
413 // check if this line has a separator |
|
414 TInt sepPos = aLineArray->MdcaPoint(i).Find(KSettingItemSeparator); |
|
415 if (sepPos > 0) |
|
416 { |
|
417 // check that the element matches |
|
418 if (aLineArray->MdcaPoint(i).Left(sepPos).CompareF(aAttribute) == 0) |
|
419 { |
|
420 // get the value |
|
421 TLex8 parser(aLineArray->MdcaPoint(i).Right(aLineArray->MdcaPoint(i).Length()-sepPos-1)); |
|
422 parser.Val(aValue); |
|
423 break; |
|
424 } |
|
425 } |
|
426 } |
|
427 } |
|
428 |
|
429 // -------------------------------------------------------------------------------------------- |
|
430 TInt CProfiler::GetSamplerAttributesL(const RMessage2& aMessage) |
|
431 { |
|
432 TInt err(KErrNone); |
|
433 TInt pos(0); |
|
434 |
|
435 // get sampler count |
|
436 TInt count(iDefaultSamplerAttributesArray->Count()); |
|
437 |
|
438 // write each of the default sampler plugin setting attributes over client-server session |
|
439 for (TInt i(0); i<count; ++i) |
|
440 { |
|
441 TSamplerAttributes attr = iDefaultSamplerAttributesArray->At(i); |
|
442 TPckgC<TSamplerAttributes> attrPckg(attr); |
|
443 |
|
444 // write a TSamplerAttributes container at a time |
|
445 aMessage.WriteL(0, attrPckg, pos); |
|
446 pos += attrPckg.Length(); |
|
447 } |
|
448 |
|
449 aMessage.Complete(err); |
|
450 return err; |
|
451 } |
|
452 |
|
453 // -------------------------------------------------------------------------------------------- |
|
454 TInt CProfiler::SetSamplerAttributesL(const RMessage2& aMessage) |
|
455 { |
|
456 TSamplerAttributes attr; |
|
457 TPckg<TSamplerAttributes> inAttr(attr); |
|
458 |
|
459 TInt err = aMessage.Read(0, inAttr, 0); |
|
460 |
|
461 // apply the changes directly to a plugin |
|
462 iSamplerHandler->SetSamplerSettingsL(attr.iUid, attr); |
|
463 |
|
464 aMessage.Complete(err); |
|
465 return err; |
|
466 } |
|
467 |
|
468 // -------------------------------------------------------------------------------------------- |
|
469 TInt CProfiler::GetGeneralAttributesL(const RMessage2& aMessage) |
|
470 { |
|
471 TPckgBuf<TGeneralAttributes> generalSettings( iGeneralAttributes ); |
|
472 |
|
473 // write general attributes over client-server session |
|
474 TInt err = aMessage.Write(0, generalSettings); |
|
475 |
|
476 aMessage.Complete(err); |
|
477 return err; |
|
478 } |
|
479 |
|
480 // -------------------------------------------------------------------------------------------- |
|
481 TInt CProfiler::SetGeneralAttributesL(const RMessage2& aMessage) |
|
482 { |
|
483 // read the general settings from message |
|
484 TGeneralAttributes attr; |
|
485 TPckg<TGeneralAttributes> inPckg(attr); |
|
486 TInt err = aMessage.Read(0, inPckg, 0); |
|
487 |
|
488 // copy to the general attributes |
|
489 iGeneralAttributes.iSaveFileDrive.Copy(attr.iSaveFileDrive); |
|
490 iGeneralAttributes.iTraceFilePrefix.Copy(attr.iTraceFilePrefix); |
|
491 iGeneralAttributes.iTraceOutput.Copy(attr.iTraceOutput); |
|
492 iGeneralAttributes.iTimedSamplingPeriod = attr.iTimedSamplingPeriod; |
|
493 |
|
494 aMessage.Complete(err); |
|
495 return err; |
|
496 } |
|
497 |
|
498 TInt CProfiler::GetSamplerAttributeCountL(const RMessage2& aMessage) |
|
499 { |
|
500 // get the plugin array count and wrap it to TPckgBuf<> |
|
501 TPckgBuf<TInt> attributeCount(iDefaultSamplerAttributesArray->Count()); |
|
502 |
|
503 // write general attributes over client-server session |
|
504 TInt err = aMessage.Write(0, attributeCount); |
|
505 |
|
506 aMessage.Complete(err); |
|
507 return err; |
|
508 } |
|
509 |
|
510 TInt CProfiler::RefreshStatus(const RMessage2& aMessage) |
|
511 { |
|
512 TInt err(KErrNone); |
|
513 |
|
514 // update profiler status for requester |
|
515 iEngineStatus.Set(iState); |
|
516 |
|
517 aMessage.Complete(err); |
|
518 return err; |
|
519 } |
|
520 |
|
521 // -------------------------------------------------------------------------------------------- |
|
522 TInt CProfiler::LoadSettingsL(/*const TDesC& configFile*/) |
|
523 { |
|
524 RFs fileServer; |
|
525 RFile file; |
|
526 TInt err(KErrNone); |
|
527 |
|
528 // connect to file server |
|
529 err = fileServer.Connect(); |
|
530 |
|
531 // check if file server can be connected |
|
532 if (err != KErrNone) |
|
533 { |
|
534 // file server couldn't be connected |
|
535 return KErrGeneral; |
|
536 } |
|
537 |
|
538 // check if settings file location length reasonable |
|
539 if ( iSettingsFileLocation.CompareF(KNullDesC) == 0 ) |
|
540 { |
|
541 // open the file with the default path and name |
|
542 TBuf<256> pathAndName; |
|
543 pathAndName.Append(PathInfo::PhoneMemoryRootPath()); |
|
544 pathAndName.Append(KProfilerSettingsFileName); |
|
545 iSettingsFileLocation.Copy(pathAndName); |
|
546 LOGTEXT(_L("CProfiler::LoadSettings - Opening settings file with name (with the default path)")); |
|
547 LOGTEXT(pathAndName); |
|
548 } |
|
549 |
|
550 // open the file with the given path and name |
|
551 err = file.Open(fileServer,iSettingsFileLocation,EFileRead); |
|
552 |
|
553 |
|
554 // check if RFile::Open() returned error |
|
555 if (err != KErrNone) |
|
556 { |
|
557 // file couldn't be opened |
|
558 LOGTEXT(_L("CProfiler::LoadSettings - Failed to open settings, using default")); |
|
559 |
|
560 // check if settings already loaded |
|
561 if(iDefaultSamplerAttributesArray->Count() > 0) |
|
562 { |
|
563 // reset default settings array |
|
564 iDefaultSamplerAttributesArray->Reset(); |
|
565 } |
|
566 |
|
567 // load default settings, instead of settings file ones |
|
568 iSamplerHandler->GetSamplerAttributesL(iDefaultSamplerAttributesArray); |
|
569 |
|
570 fileServer.Close(); |
|
571 return KErrNone; |
|
572 } |
|
573 |
|
574 // initialize iSavedLineArray, initial settings file lines 64 |
|
575 if(iSavedLineArray) |
|
576 { |
|
577 iSavedLineArray->Reset(); |
|
578 } |
|
579 else |
|
580 { |
|
581 iSavedLineArray = new (ELeave) CDesC8ArrayFlat(KSavedLineCount); |
|
582 } |
|
583 |
|
584 iSavedLinesCount = KSavedLineCount; |
|
585 |
|
586 // get size of the file |
|
587 TInt fileSize(0); |
|
588 err = file.Size(fileSize); |
|
589 // check if an error occurred reading the file size |
|
590 if(err != KErrNone) |
|
591 { |
|
592 return KErrGeneral; // could not find the size |
|
593 } |
|
594 |
|
595 // sanity check for the file size |
|
596 if (fileSize < 3 || fileSize > 20000) |
|
597 { |
|
598 fileSize = KSettingsFileSize; |
|
599 return KErrNotSupported; |
|
600 } |
|
601 |
|
602 // read the contents of the file to buffer. |
|
603 iSettingsBuffer.Zero(); |
|
604 file.Read(iSettingsBuffer, fileSize); |
|
605 file.Close(); |
|
606 fileServer.Close(); |
|
607 LOGSTRING2("CProfiler::LoadSettings: read %d bytes",iSettingsBuffer.Length()); |
|
608 |
|
609 // append end mark "[end]" |
|
610 iSettingsBuffer.Append(KEndMark); |
|
611 // force an ending newline |
|
612 iSettingsBuffer.Append('\n'); |
|
613 |
|
614 // next fill the saved settings array (CDesC8ArrayFlat) for further comparison with changes and default values |
|
615 TBuf8<384> tmpBuf; |
|
616 TInt lineCount(0); |
|
617 TBool commentFound(EFalse); |
|
618 for (TInt i(0); i<iSettingsBuffer.Length(); i++) // loop all chars |
|
619 { |
|
620 // if new line char found, create a new text line |
|
621 if (iSettingsBuffer[i]=='\r' || iSettingsBuffer[i]=='\n') |
|
622 { |
|
623 // check if collected string has reasonable length |
|
624 if (tmpBuf.Length() > 0) |
|
625 { |
|
626 // remove extra spaces |
|
627 tmpBuf.TrimAll(); |
|
628 // check if the size of the array too small |
|
629 if(lineCount >= iSavedLinesCount) |
|
630 { |
|
631 iSavedLineArray->ExpandL(20); // expand by 20 lines |
|
632 iSavedLinesCount += 20; |
|
633 } |
|
634 iSavedLineArray->AppendL(tmpBuf); |
|
635 tmpBuf.Copy(KNullDesC8); |
|
636 lineCount++; |
|
637 } |
|
638 commentFound = EFalse; |
|
639 } |
|
640 // check if comment mark ';' is found on the line, skip the rest of the line |
|
641 else if(iSettingsBuffer[i]==';') |
|
642 { |
|
643 commentFound = ETrue; |
|
644 } |
|
645 // otherwise append a char to the temp line buffer if it is a wanted ASCII char |
|
646 else if (iSettingsBuffer[i]>=32 && iSettingsBuffer[i]<=127 && !commentFound) |
|
647 { |
|
648 tmpBuf.Append(iSettingsBuffer[i]); |
|
649 } |
|
650 } |
|
651 |
|
652 // empty tmpBuf |
|
653 tmpBuf.Copy(KNullDesC8); |
|
654 // check settings file version |
|
655 DoGetValueFromSettingsArray(iSavedLineArray, KProfilerVersionTag, tmpBuf); |
|
656 |
|
657 TBuf8<32> version; |
|
658 version.Copy(PROFILER_VERSION_SHORT); |
|
659 |
|
660 // check if settings file version is |
|
661 if(tmpBuf.CompareF(version) >= 0) |
|
662 { |
|
663 // update general attributes |
|
664 UpdateSavedGeneralAttributes(iSavedLineArray); |
|
665 |
|
666 // update settings to sampler plugins and save the attributes to default array |
|
667 iSamplerHandler->UpdateSavedSamplerAttributesL(iSavedLineArray, iDefaultSamplerAttributesArray); |
|
668 } |
|
669 else |
|
670 { |
|
671 // check if settings already loaded |
|
672 if(iDefaultSamplerAttributesArray) |
|
673 { |
|
674 // reset default settings array |
|
675 iDefaultSamplerAttributesArray->Reset(); |
|
676 |
|
677 // get the default settings if settings file version too old |
|
678 iSamplerHandler->GetSamplerAttributesL(iDefaultSamplerAttributesArray); |
|
679 } |
|
680 } |
|
681 |
|
682 return err; |
|
683 } |
|
684 |
|
685 // -------------------------------------------------------------------------------------------- |
|
686 void CProfiler::UpdateSavedGeneralAttributes(CDesC8ArrayFlat* aSavedAttributes) |
|
687 { |
|
688 // get saved general settings |
|
689 DoGetValueFromSettingsArray(aSavedAttributes, KGenericTraceOutput, iGeneralAttributes.iTraceOutput); |
|
690 DoGetValueFromSettingsArray(aSavedAttributes, KGenericTraceFilePrefix, iGeneralAttributes.iTraceFilePrefix); |
|
691 DoGetValueFromSettingsArray(aSavedAttributes, KGenericTraceFileSaveDrive, iGeneralAttributes.iSaveFileDrive); |
|
692 DoGetValueFromSettingsArray(aSavedAttributes, KGenericTimedProfilingPeriod, iGeneralAttributes.iTimedSamplingPeriod); |
|
693 } |
|
694 |
|
695 TBool CProfiler::CheckLocationSanity(RFs& fs, const TDesC8& aLocation) |
|
696 { |
|
697 TBool ret(EFalse); |
|
698 TBool noDiskSpace(EFalse); |
|
699 TBuf<32> drive; |
|
700 |
|
701 CnvUtfConverter::ConvertToUnicodeFromUtf8(drive, aLocation); |
|
702 TDriveUnit driveUnit = TDriveUnit(drive); |
|
703 |
|
704 // check that the root folder is correct |
|
705 if (drive.Length() > 2 && BaflUtils::CheckFolder(fs, drive.Left(3)) == KErrNone) |
|
706 { |
|
707 // test available disk space |
|
708 TRAP_IGNORE((noDiskSpace = SysUtil::DiskSpaceBelowCriticalLevelL(&fs, 0, driveUnit))); |
|
709 if(!noDiskSpace) |
|
710 ret = ETrue; |
|
711 } |
|
712 |
|
713 return ret; |
|
714 } |
|
715 |
|
716 TInt CProfiler::HandleGeneralSettingsChange() |
|
717 { |
|
718 // local literals |
|
719 _LIT8(KBackSlash, "\\"); |
|
720 _LIT8(KTraceFileExtension, ".dat"); |
|
721 |
|
722 TBuf8<KFileNameBufSize> fileNameBuf; |
|
723 TBuf8<10> number; |
|
724 TInt result(0); |
|
725 TInt index(1); |
|
726 TInt hashLocation(0); |
|
727 TParse parse; |
|
728 |
|
729 // check if plugin writer changed |
|
730 if(iGeneralAttributes.iTraceOutput.CompareF(KOutputToDebugOutput) == 0) |
|
731 { |
|
732 iWriterHandler->SetPluginActive( KDebOutWriterPluginUid, EWriterPluginEnabled ); |
|
733 } |
|
734 else |
|
735 { |
|
736 RFs fileServer; |
|
737 RFile file; |
|
738 |
|
739 // connect to the file server |
|
740 result = fileServer.Connect(); |
|
741 if(result == KErrNone) |
|
742 { |
|
743 // disk writer plugin will be activated |
|
744 iWriterHandler->SetPluginActive( KDiskWriterPluginUid, EWriterPluginEnabled ); |
|
745 |
|
746 // fix the trace data file location as well |
|
747 iTotalPrefix.Zero(); |
|
748 iTotalPrefix.Append(iGeneralAttributes.iSaveFileDrive); |
|
749 |
|
750 // check that trace file location sane |
|
751 if(!CProfiler::CheckLocationSanity(fileServer, iTotalPrefix)) |
|
752 { |
|
753 fileServer.Close(); |
|
754 return KErrPathNotFound; |
|
755 } |
|
756 |
|
757 // remove extra spaces |
|
758 iTotalPrefix.TrimAll(); |
|
759 |
|
760 // check the directory contains a trailing backlash |
|
761 if(iTotalPrefix.Right(1) != _L8("\\") && |
|
762 iTotalPrefix.Right(1) != _L8("/")) |
|
763 { |
|
764 // append backslash to end |
|
765 iTotalPrefix.Append(KBackSlash); |
|
766 } |
|
767 |
|
768 // append trace file name prefix e.g. PIProfiler_# |
|
769 iTotalPrefix.Append(iGeneralAttributes.iTraceFilePrefix); |
|
770 |
|
771 // locate '#' mark for finding the next free trace file name, e.g. E:\data\PIProfiler_4.dat |
|
772 hashLocation = iTotalPrefix.Locate('#'); |
|
773 if( hashLocation == KErrNotFound ) |
|
774 { |
|
775 // append simply at the end of the trace file prefix, no need to inform user |
|
776 iTotalPrefix.Append('#'); |
|
777 // get new hash mark location |
|
778 hashLocation = iTotalPrefix.Locate('#'); |
|
779 } |
|
780 |
|
781 // add the file extension |
|
782 iTotalPrefix.Append(KTraceFileExtension); |
|
783 |
|
784 // search for files with different indices |
|
785 // until a free filename is found |
|
786 while(result != KErrNotFound) |
|
787 { |
|
788 fileNameBuf.Zero(); |
|
789 // start with the original prefix |
|
790 fileNameBuf.Append(iTotalPrefix); |
|
791 // convert the number to a descriptor |
|
792 number.Num(index); |
|
793 // replace the hashmark with the real number |
|
794 fileNameBuf.Replace(hashLocation,1,number); |
|
795 |
|
796 // make a copy to the iFileNameStream descriptor |
|
797 iFileNameStream.Zero(); |
|
798 CnvUtfConverter::ConvertToUnicodeFromUtf8(iFileNameStream, fileNameBuf); |
|
799 |
|
800 LOGSTRING2("CProfiler::HandleGeneralSettingsChange() - trying to open files %S ",&iFileNameStream); |
|
801 |
|
802 if((result = parse.Set(iFileNameStream, NULL, NULL)) != KErrNone) |
|
803 { |
|
804 // break loop if fails, problems in file name => change to log into debug output |
|
805 break; |
|
806 } |
|
807 |
|
808 // create directory for trace files if not exists |
|
809 result = fileServer.MkDirAll(parse.FullName()); |
|
810 |
|
811 // check that file server responded with KErrNone or KErrAlreadyExists |
|
812 if( result != KErrNone && result != KErrAlreadyExists) |
|
813 { |
|
814 // if some other result, e.g. memory full => break |
|
815 break; |
|
816 } |
|
817 |
|
818 // attempt opening the file |
|
819 result = file.Open(fileServer,parse.FullName(),EFileShareReadersOnly); |
|
820 if(result != KErrNotFound) |
|
821 { |
|
822 if( result != KErrNotReady && |
|
823 result != KErrServerBusy ) |
|
824 { |
|
825 // close the file if it could be opened |
|
826 LOGSTRING2("Found STREAM file with index %d",index); |
|
827 index++; |
|
828 } |
|
829 else |
|
830 { |
|
831 // in boot measurements the file system might not be ready yet. |
|
832 LOGSTRING2("Problem in opening STREAM file %d",index); |
|
833 } |
|
834 file.Close(); |
|
835 } |
|
836 } // while |
|
837 } |
|
838 else |
|
839 { |
|
840 // return error code |
|
841 return result; |
|
842 } |
|
843 |
|
844 TUint32 id(iWriterHandler->GetActiveWriter()->GetWriterType()); |
|
845 |
|
846 // check if a file name is one that does not exist and selected plugin is disk writer |
|
847 if(result == KErrNotFound && id == KDiskWriterPluginUid.iUid) |
|
848 { |
|
849 // write right trace data file name to disk writer plugin |
|
850 iWriterHandler->SetPluginSettings( KDiskWriterPluginUid, iFileNameStream ); |
|
851 } |
|
852 else |
|
853 { |
|
854 // return error if could not create trace log file |
|
855 return result; |
|
856 } |
|
857 // close file server |
|
858 fileServer.Close(); |
|
859 } // if output == KOutputToDebugOutput |
|
860 return KErrNone; |
|
861 } |
|
862 |
|
863 // -------------------------------------------------------------------------------------------- |
|
864 void CProfiler::HandleTimerExpiresL(TInt aError) |
|
865 { |
|
866 LOGSTRING2("CProfiler::HandleTimerExpiresL - Error: %d", aError); |
|
867 this->ControlL(RProfiler::EStopSampling); |
|
868 if( CPServer::iClientCount <= 0 ) |
|
869 { |
|
870 LOGSTRING("CProfiler::HandleTimerExpiresL - No clients attached, shutting down server..."); |
|
871 this->ControlL(RProfiler::EExitProfiler); |
|
872 } |
|
873 } |
|
874 |
|
875 // -------------------------------------------------------------------------------------------- |
|
876 void CProfiler::SaveSettingsL() |
|
877 { |
|
878 LOGTEXT(_L("CProfiler::SaveSettings()")); |
|
879 |
|
880 // local literal |
|
881 _LIT(KGeneralHeader, "[general]"); |
|
882 _LIT(KVersionHeader, "version"); |
|
883 _LIT8(KPIProfilerSettingsHeader, "; PI Profiler Settings File"); |
|
884 _LIT8(KGeneralSettingsHeader, "; general settings"); |
|
885 _LIT8(KOutputFileDescription,"; \"output_type=file_system\" writes *.dat file to external memory"); |
|
886 _LIT8(KOutputDebugDescription,"; \"output_type=debug_output\" writes *.dat file to debug port"); |
|
887 _LIT8(KOutputFilePrefixDescription,"; if writing to file, prefix of the *.dat file\r\n; first '#' in the prefix is replaced with an integer"); |
|
888 _LIT8(KOutputSaveDriveDescription,"; if writing to file, the location to store the *.dat file"); |
|
889 _LIT8(KTimedProfilingPeriod,"; period (in seconds) used when using timed profiling"); |
|
890 |
|
891 RFs fs; |
|
892 RFile settingsFile; |
|
893 TInt err(KErrNone); |
|
894 TBuf8<384> line; |
|
895 |
|
896 // connect to file server |
|
897 err = fs.Connect(); |
|
898 if( err != KErrNone ) |
|
899 { |
|
900 // failed to write settings to settings file |
|
901 return; |
|
902 } |
|
903 |
|
904 // create and set the private path |
|
905 fs.CreatePrivatePath(EDriveC); |
|
906 fs.SetSessionToPrivate(EDriveC); |
|
907 |
|
908 // create the new settings file |
|
909 err = settingsFile.Replace(fs, iSettingsFileLocation, EFileWrite); |
|
910 if(err != KErrNone) |
|
911 return; |
|
912 |
|
913 CleanupClosePushL(settingsFile); |
|
914 |
|
915 // write the header |
|
916 line.Copy(KPIProfilerSettingsHeader); |
|
917 line.Append(KNewLineSeparator); |
|
918 line.Append(KNewLineSeparator); |
|
919 settingsFile.Write(line); |
|
920 |
|
921 // write the header |
|
922 line.Copy(KGeneralSettingsHeader); |
|
923 line.Append(KNewLineSeparator); |
|
924 settingsFile.Write(line); |
|
925 |
|
926 // write all generic settings |
|
927 line.Copy(KGeneralHeader); |
|
928 line.Append(KNewLineSeparator); |
|
929 settingsFile.Write(line); |
|
930 |
|
931 // write version info |
|
932 line.Copy(KVersionHeader); |
|
933 line.Append(KEquals); |
|
934 line.Append(PROFILER_VERSION_SHORT); |
|
935 line.Append(KNewLineSeparator); |
|
936 settingsFile.Write(line); |
|
937 |
|
938 // output explanation |
|
939 line.Copy(KOutputFileDescription); |
|
940 line.Append(KNewLineSeparator); |
|
941 line.Append(KOutputDebugDescription); |
|
942 line.Append(KNewLineSeparator); |
|
943 settingsFile.Write(line); |
|
944 |
|
945 // write trace output |
|
946 line.Copy(KGenericTraceOutput); |
|
947 line.Append(KEquals); |
|
948 line.Append(iGeneralAttributes.iTraceOutput); |
|
949 line.Append(KNewLineSeparator); |
|
950 settingsFile.Write(line); |
|
951 |
|
952 // file prefix explanation |
|
953 line.Copy(KOutputFilePrefixDescription); |
|
954 line.Append(KNewLineSeparator); |
|
955 settingsFile.Write(line); |
|
956 |
|
957 // write trace file prefix |
|
958 line.Copy(KGenericTraceFilePrefix); |
|
959 line.Append(KEquals); |
|
960 line.Append(iGeneralAttributes.iTraceFilePrefix); |
|
961 line.Append(KNewLineSeparator); |
|
962 settingsFile.Write(line); |
|
963 |
|
964 // file prefix explanation |
|
965 line.Copy(KOutputSaveDriveDescription); |
|
966 line.Append(KNewLineSeparator); |
|
967 settingsFile.Write(line); |
|
968 |
|
969 // write trace file location |
|
970 line.Copy(KGenericTraceFileSaveDrive); |
|
971 line.Append(KEquals); |
|
972 line.Append(iGeneralAttributes.iSaveFileDrive); |
|
973 line.Append(KNewLineSeparator); |
|
974 settingsFile.Write(line); |
|
975 |
|
976 // timed profiling period explanation |
|
977 line.Copy(KTimedProfilingPeriod); |
|
978 line.Append(KNewLineSeparator); |
|
979 settingsFile.Write(line); |
|
980 |
|
981 // Write timed profiling period value |
|
982 line.Copy(KGenericTimedProfilingPeriod); |
|
983 line.Append(KEquals); |
|
984 TBuf<16> tmpNum; |
|
985 tmpNum.AppendNum(iGeneralAttributes.iTimedSamplingPeriod); |
|
986 line.Append(tmpNum); |
|
987 line.Append(KNewLineSeparator); |
|
988 settingsFile.Write(line); |
|
989 |
|
990 // reset the default attributes array |
|
991 iDefaultSamplerAttributesArray->Reset(); |
|
992 |
|
993 // update the latest changes from plugins |
|
994 iSamplerHandler->GetSamplerAttributesL(iDefaultSamplerAttributesArray); |
|
995 |
|
996 // call CSamplerController to write all sampler settings |
|
997 iSamplerHandler->ComposeAttributesToSettingsFileFormat(settingsFile, iDefaultSamplerAttributesArray); |
|
998 |
|
999 CleanupStack::PopAndDestroy(); //settingsFile |
|
1000 // close file |
|
1001 fs.Close(); |
|
1002 } |
|
1003 |
|
1004 TInt CProfiler::CheckOldProfilerRunning() |
|
1005 { |
|
1006 TFindProcess procName; |
|
1007 procName.Find(_L("BappeaProf.exe*")); |
|
1008 TFullName aResult; |
|
1009 TInt err(KErrNone); |
|
1010 RProcess proc; |
|
1011 |
|
1012 // now check if old Profiler is still running on |
|
1013 err = procName.Next(aResult); |
|
1014 // check if old profiler process found |
|
1015 if(err == KErrNone) |
|
1016 { |
|
1017 // other process found, i.e. right process to communicate with, in case started from eshell |
|
1018 err = proc.Open(procName); |
|
1019 if(err == KErrNone) |
|
1020 { |
|
1021 if(proc.ExitCategory().Length() > 0) |
|
1022 { |
|
1023 proc.Close(); |
|
1024 // process already exited => create a new one |
|
1025 return KErrNotFound; |
|
1026 } |
|
1027 proc.Close(); |
|
1028 } |
|
1029 // return error for error handling |
|
1030 return KErrAlreadyExists; |
|
1031 } |
|
1032 return err; |
|
1033 } |
|
1034 |
|
1035 // -------------------------------------------------------------------------------------------- |
|
1036 void CProfiler::HandleError(TInt aErr) |
|
1037 { |
|
1038 // write error to status property to inform requester |
|
1039 TInt err(iEngineStatus.Set(KEngineStatusPropertyCat, EProfilerEngineStatus, aErr)); |
|
1040 if(err != KErrNone) |
|
1041 RDebug::Print(_L("CProfiler::HandleError() - error setting status: %d"), err); |
|
1042 } |
|
1043 |
|
1044 // -------------------------------------------------------------------------------------------- |
|
1045 TInt CProfiler::ControlDataL(TInt aCommand,TAny* value1,TAny* /*value2*/) |
|
1046 { |
|
1047 LOGSTRING3("CProfiler::ControlData %d, 0x%x",aCommand,value1); |
|
1048 |
|
1049 _LIT(KDebugOutput, "debug_output"); |
|
1050 _LIT(KFileOutput, "file_system"); |
|
1051 _LIT8(KOutputToDebugOutput, "debug_output"); |
|
1052 |
|
1053 TDes* desc; |
|
1054 TPtrC ptrDesc; |
|
1055 |
|
1056 switch(aCommand) |
|
1057 { |
|
1058 // new controls |
|
1059 case RProfiler::EGetFileName: |
|
1060 { |
|
1061 LOGTEXT(_L("Profiler::EGetFileName - start")); |
|
1062 LOGSTRING2("Profiler::EGetFileName - total file name is: %S",(TDes*)value1); |
|
1063 desc = (TDes*)value1; |
|
1064 desc->Zero(); |
|
1065 desc->Append(iFileNameStream); |
|
1066 LOGSTRING2("Profiler::EGetFileName - now total file name is: %S",(TDes*)value1); |
|
1067 return KErrNone; |
|
1068 } |
|
1069 case RProfiler::EGetActiveWriter: |
|
1070 { |
|
1071 LOGTEXT(_L("Profiler::EGetActiveWriter - start")); |
|
1072 desc = (TDes*)value1; |
|
1073 desc->Zero(); |
|
1074 if(iGeneralAttributes.iTraceOutput.CompareF(KOutputToDebugOutput) == 0) |
|
1075 { |
|
1076 desc->Append(KDebugOutput); |
|
1077 } |
|
1078 else |
|
1079 { |
|
1080 desc->Append(KFileOutput); |
|
1081 } |
|
1082 return KErrNone; |
|
1083 } |
|
1084 } |
|
1085 |
|
1086 return KErrNone; |
|
1087 } |
|
1088 |
|
1089 // -------------------------------------------------------------------------------------------- |
|
1090 TInt CProfiler::ControlL(TInt aCommand) |
|
1091 { |
|
1092 LOGSTRING2("CProfiler::Control - Controlling ProfilerEngine %d",aCommand); |
|
1093 TInt err(KErrNone); |
|
1094 |
|
1095 switch (aCommand) |
|
1096 { |
|
1097 case RProfiler::EStartSampling: |
|
1098 case RProfiler::EStartTimedSampling: |
|
1099 { |
|
1100 // check first if old Profiler already running |
|
1101 err = CheckOldProfilerRunning(); |
|
1102 if(err == KErrAlreadyExists) |
|
1103 { |
|
1104 // if exists do not start a profiling process since corrupts the collected trace data |
|
1105 HandleError(err); |
|
1106 err = KErrNone; |
|
1107 return err; |
|
1108 } |
|
1109 |
|
1110 // save settings before launching the profiler |
|
1111 // reason: the profiling may have set to the background => need for get right settings |
|
1112 SaveSettingsL(); |
|
1113 |
|
1114 // set the general settings to writer plugins to reflect the latest changes |
|
1115 err = HandleGeneralSettingsChange(); |
|
1116 if(err == KErrNone) |
|
1117 { |
|
1118 // reset the buffers before new profiling |
|
1119 iUserStream->ResetBuffers(); |
|
1120 |
|
1121 // give the CProfilerSampleStream a handle to current writer |
|
1122 iUserStream->SetWriter(*iWriterHandler->GetActiveWriter()); |
|
1123 |
|
1124 // set initially debug output writer active |
|
1125 err = iWriterHandler->StartSelectedPlugin(); |
|
1126 |
|
1127 // check that writer plugin started |
|
1128 if(err != KErrNone) |
|
1129 { |
|
1130 // if not started handle error |
|
1131 HandleError(err); |
|
1132 } |
|
1133 else |
|
1134 { |
|
1135 // start activated sampler plug-in, NOTE: plugins check if errors occur in startup for some reason |
|
1136 iSamplerHandler->StartSamplerPluginsL(); |
|
1137 |
|
1138 // set engine state P&S property to running, e.g. for PIProfiler UI to read |
|
1139 iState = RProfiler::ERunning; |
|
1140 |
|
1141 // set the engine into running mode |
|
1142 iEngineStatus.Set(iState); |
|
1143 } |
|
1144 } |
|
1145 else |
|
1146 { |
|
1147 // handle error and notify requester |
|
1148 HandleError(err); |
|
1149 } |
|
1150 |
|
1151 if( aCommand == RProfiler::EStartTimedSampling ) |
|
1152 { |
|
1153 iTimer->After(iGeneralAttributes.iTimedSamplingPeriod); |
|
1154 LOGTEXT(_L("CProfiler::Control - Finished processing EStartTimedSampling!")); |
|
1155 } |
|
1156 else |
|
1157 { |
|
1158 LOGTEXT(_L("CProfiler::Control - Finished processing EStartSampling!")); |
|
1159 } |
|
1160 |
|
1161 return err; |
|
1162 } |
|
1163 case RProfiler::EStopSampling: |
|
1164 LOGTEXT(_L("CProfiler::Control - Starting to stop sampling...")); |
|
1165 // stop sampler plugins |
|
1166 if(iState == RProfiler::ERunning) |
|
1167 { |
|
1168 iState = RProfiler::EStopping; |
|
1169 iEngineStatus.Set(RProfiler::EStopping); |
|
1170 |
|
1171 iSamplerHandler->StopSamplerPlugins(); |
|
1172 |
|
1173 // finalize the filled buffer writing |
|
1174 iUserStream->Finalise(); |
|
1175 |
|
1176 // stop output plugin and write the rest of the trace data to output |
|
1177 LOGTEXT(_L("CProfiler::Control - stopping writer")); |
|
1178 iWriterHandler->StopSelectedPlugin(); |
|
1179 |
|
1180 // set engine state P&S property idle |
|
1181 iState = RProfiler::EIdle; |
|
1182 iEngineStatus.Set(RProfiler::EIdle); |
|
1183 |
|
1184 LOGSTRING2("CProfiler::Control - sampling stopped, going to state %d", RProfiler::EIdle); |
|
1185 } |
|
1186 return KErrNone; |
|
1187 |
|
1188 case RProfiler::EExitProfiler: |
|
1189 { |
|
1190 // save settings into settings file when exiting |
|
1191 SaveSettingsL(); |
|
1192 |
|
1193 if(iUserStream) |
|
1194 { |
|
1195 delete iUserStream; |
|
1196 iUserStream = NULL; |
|
1197 } |
|
1198 |
|
1199 // set engine state P&S property idle |
|
1200 iState = RProfiler::EIdle; |
|
1201 iEngineStatus.Set(RProfiler::EIdle); |
|
1202 |
|
1203 LOGTEXT(_L("Stopping Activer Scheduler")); |
|
1204 CActiveScheduler::Stop(); |
|
1205 LOGTEXT(_L("Stopped Activer Scheduler")); |
|
1206 |
|
1207 return KErrNone; |
|
1208 } |
|
1209 |
|
1210 case RProfiler::EAttachClient: |
|
1211 { |
|
1212 // Increase client reference count |
|
1213 ++CPServer::iClientCount; |
|
1214 LOGSTRING2("Increased client reference count to: %d", CPServer::iClientCount); |
|
1215 return KErrNone; |
|
1216 } |
|
1217 case RProfiler::ERemoveClient: |
|
1218 { |
|
1219 // Decrease client reference count |
|
1220 --CPServer::iClientCount; |
|
1221 LOGSTRING2("Decreasing client reference count to: %d", CPServer::iClientCount); |
|
1222 return KErrNone; |
|
1223 } |
|
1224 } |
|
1225 |
|
1226 LOGTEXT(_L("CProfiler::Control - returning")); |
|
1227 |
|
1228 return err; |
|
1229 } |
|
1230 |
|
1231 // -------------------------------------------------------------------------------------------- |
|
1232 void CProfiler::Finalise() |
|
1233 { |
|
1234 LOGTEXT(_L("CProfiler::Finalise - Finished processing EStopSampling!")); |
|
1235 } |
|
1236 |
|
1237 // -------------------------------------------------------------------------------------------- |
|
1238 RProfiler::TSamplerState CProfiler::State() const |
|
1239 { |
|
1240 return iState; |
|
1241 } |
|
1242 |
|
1243 /* |
|
1244 * |
|
1245 * Class CPServer definition |
|
1246 * |
|
1247 */ |
|
1248 // -------------------------------------------------------------------------------------------- |
|
1249 inline const CPServer& CPSession::Server() const |
|
1250 { |
|
1251 return *static_cast<const CPServer*>(CSession2::Server()); |
|
1252 } |
|
1253 |
|
1254 // -------------------------------------------------------------------------------------------- |
|
1255 void CPSession::ServiceL(const RMessage2& aMessage) |
|
1256 { |
|
1257 LOGTEXT(_L("CPSession::ServiceL - Starting to process message")); |
|
1258 TInt err(KErrNone); |
|
1259 |
|
1260 if(aMessage.Function() == RProfiler::EGetGeneralAttributes) |
|
1261 { |
|
1262 Server().GetGeneralAttributesL(aMessage); |
|
1263 } |
|
1264 else if(aMessage.Function() == RProfiler::ESetGeneralAttributes) |
|
1265 { |
|
1266 Server().SetGeneralAttributesL(aMessage); |
|
1267 } |
|
1268 else if(aMessage.Function() == RProfiler::EGetSamplerAttributes) |
|
1269 { |
|
1270 Server().GetSamplerAttributesL(aMessage); |
|
1271 } |
|
1272 else if(aMessage.Function() == RProfiler::EGetSamplerAttributeCount) |
|
1273 { |
|
1274 Server().GetSamplerAttributeCountL(aMessage); |
|
1275 } |
|
1276 else if(aMessage.Function() == RProfiler::ESetSamplerAttributes) |
|
1277 { |
|
1278 Server().SetSamplerAttributesL(aMessage); |
|
1279 } |
|
1280 else if(aMessage.Function() == RProfiler::ERefreshProfilerStatus) |
|
1281 { |
|
1282 Server().RefreshStatus(aMessage); |
|
1283 } |
|
1284 else if(aMessage.Ptr0() == 0 && aMessage.Ptr1() == 0 && aMessage.Ptr2() == 0) |
|
1285 { |
|
1286 LOGTEXT(_L("Ptr0 && Ptr1 == 0 && Ptr2 == 0")); |
|
1287 aMessage.Complete(Server().ControlL(RProfiler::TCommand(aMessage.Function()))); |
|
1288 LOGTEXT(_L("CPSession::ServiceL - Message completed")); |
|
1289 } |
|
1290 else if(aMessage.Ptr0() != 0 && aMessage.Ptr1() != 0 && aMessage.Ptr2() != 0) |
|
1291 { |
|
1292 LOGTEXT(_L("Error with message, all pointers contain data!")); |
|
1293 } |
|
1294 |
|
1295 else if (aMessage.Ptr0() != 0) |
|
1296 { |
|
1297 if(aMessage.Ptr1() == 0) |
|
1298 { |
|
1299 LOGTEXT(_L("ServiceL: Ptr0 != 0 && Ptr1 == 0")); |
|
1300 // provided value is a descriptor |
|
1301 TBuf<64>* dst = new TBuf<64>; |
|
1302 aMessage.ReadL(0,*dst,0); |
|
1303 |
|
1304 err = Server().ControlDataL(aMessage.Function(),(TAny*)dst); |
|
1305 delete dst; |
|
1306 aMessage.Complete(err); |
|
1307 LOGTEXT(_L("CPSession::ServiceL - Message completed")); |
|
1308 } |
|
1309 else |
|
1310 { |
|
1311 LOGTEXT(_L("ServiceL: Ptr0 != 0 && Ptr1 != 0")); |
|
1312 // provided value is a descriptor |
|
1313 TBuf<64>* dst = new TBuf<64>; |
|
1314 aMessage.ReadL(0,*dst,0); |
|
1315 |
|
1316 TUint32 num1 = (TUint32)aMessage.Ptr1(); |
|
1317 |
|
1318 err = Server().ControlDataL(aMessage.Function(),(TAny*)dst, (TAny*)num1); |
|
1319 delete dst; |
|
1320 aMessage.Complete(err); |
|
1321 LOGTEXT(_L("CPSession::ServiceL - Message completed")); |
|
1322 } |
|
1323 } |
|
1324 else if (aMessage.Ptr1() != 0) |
|
1325 { |
|
1326 LOGTEXT(_L("ServiceL: Ptr1 != 0")); |
|
1327 // provided value is a TUint32 |
|
1328 if( ((TUint32)aMessage.Ptr3()) == 0xffffffff) |
|
1329 { |
|
1330 TUint32 num = (TUint32)aMessage.Ptr1(); |
|
1331 err = Server().ControlDataL(aMessage.Function(),(TAny*)num); |
|
1332 aMessage.Complete(err); |
|
1333 LOGTEXT(_L("CPSession::ServiceL - Message completed")); |
|
1334 } |
|
1335 else |
|
1336 { |
|
1337 LOGTEXT(_L("ServiceL: Ptr3 != 0xffffffff")); |
|
1338 TUint32 num1 = (TUint32)aMessage.Ptr1(); |
|
1339 TUint32 num2 = (TUint32)aMessage.Ptr3(); |
|
1340 err = Server().ControlDataL(aMessage.Function(),(TAny*)num1,(TAny*)num2); |
|
1341 aMessage.Complete(err); |
|
1342 LOGTEXT(_L("CPSession::ServiceL - Message completed")); |
|
1343 } |
|
1344 } |
|
1345 else if (aMessage.Ptr2() != 0) |
|
1346 { |
|
1347 // command requests for data, provided |
|
1348 // value should be a descriptor |
|
1349 if( ((TUint32)aMessage.Ptr3()) == 0xffffffff) |
|
1350 { |
|
1351 LOGTEXT(_L("ServiceL: Ptr2 != 0 && Ptr3 == 0xffffffff")); |
|
1352 |
|
1353 TBuf<256>* src = new TBuf<256>; |
|
1354 src->Zero(); |
|
1355 err = Server().ControlDataL(aMessage.Function(),(TAny*)src); |
|
1356 |
|
1357 LOGSTRING2("Got sampler data %S",src); |
|
1358 |
|
1359 aMessage.WriteL(2, *src, 0); |
|
1360 |
|
1361 delete src; |
|
1362 aMessage.Complete(err); |
|
1363 LOGTEXT(_L("CPSession::ServiceL - Message completed")); |
|
1364 } |
|
1365 else |
|
1366 { |
|
1367 LOGTEXT(_L("ServiceL: Ptr2 != 0 && Ptr3 != 0xffffffff")); |
|
1368 |
|
1369 TUint32 num1 = (TUint32)aMessage.Ptr2(); // containing id |
|
1370 TBuf<256>* buffer = new TBuf<256>; // Text data, e.g. plug-in name or description |
|
1371 |
|
1372 LOGSTRING3("Getting data for sampler: 0x%X, buffer max len %d",num1, aMessage.GetDesMaxLength(3)); |
|
1373 |
|
1374 err = Server().ControlDataL(aMessage.Function(), (TAny*)num1, (TAny*)buffer); |
|
1375 |
|
1376 LOGSTRING2("Got sampler data %S",&buffer); |
|
1377 |
|
1378 // write back to same parameter |
|
1379 aMessage.WriteL(3, *buffer, 0); |
|
1380 |
|
1381 delete buffer; |
|
1382 aMessage.Complete(err); |
|
1383 LOGTEXT(_L("CPSession::ServiceL - Message completed")); |
|
1384 } |
|
1385 } |
|
1386 LOGTEXT(_L("CPSession::ServiceL - Message processed")); |
|
1387 } |
|
1388 |
|
1389 // -------------------------------------------------------------------------------------------- |
|
1390 MProfilerController* CPServer::NewL(TInt aPriority, MProfilerEngine& aEngine) |
|
1391 { |
|
1392 LOGTEXT(_L("CPServer::NewL - Enter")); |
|
1393 CPServer* self = new(ELeave) CPServer(aPriority, aEngine); |
|
1394 CleanupStack::PushL(self); |
|
1395 self->StartL(KProfilerName); |
|
1396 CleanupStack::Pop(); |
|
1397 LOGTEXT(_L("CPSession::NewL - Exit")); |
|
1398 return self; |
|
1399 } |
|
1400 |
|
1401 // -------------------------------------------------------------------------------------------- |
|
1402 CPServer::CPServer(TInt aPriority, MProfilerEngine& aEngine) |
|
1403 : CServer2(aPriority), MProfilerController(aEngine) |
|
1404 { |
|
1405 |
|
1406 } |
|
1407 |
|
1408 // -------------------------------------------------------------------------------------------- |
|
1409 void CPServer::Release() |
|
1410 { |
|
1411 delete this; |
|
1412 } |
|
1413 |
|
1414 // -------------------------------------------------------------------------------------------- |
|
1415 CSession2* CPServer::NewSessionL(const TVersion&,const RMessage2&) const |
|
1416 { |
|
1417 return new(ELeave) CPSession(); |
|
1418 } |
|
1419 |
|
1420 /* |
|
1421 * |
|
1422 * Static methods for controlling the profiler |
|
1423 * through command line |
|
1424 * |
|
1425 */ |
|
1426 // -------------------------------------------------------------------------------------------- |
|
1427 static void RunEngineServerL(const TDesC& aSettingsFile) |
|
1428 { |
|
1429 RDebug::Print(_L("Profiler: RunEngineServerL() - Install active scheduler")); |
|
1430 CActiveScheduler* pS = new CActiveScheduler; |
|
1431 CActiveScheduler::Install(pS); |
|
1432 CProfiler* p = CProfiler::NewLC(aSettingsFile); |
|
1433 CActiveScheduler::Start(); |
|
1434 p->Finalise(); |
|
1435 CleanupStack::PopAndDestroy(p); |
|
1436 delete pS; |
|
1437 } |
|
1438 |
|
1439 // -------------------------------------------------------------------------------------------- |
|
1440 static TInt TestSettingsFile(const TDesC& configFile) |
|
1441 { |
|
1442 RFs fs; |
|
1443 LOGSTRING2("TestSettingsFile: entry %S", &configFile); |
|
1444 // check if file server can be connected |
|
1445 if (fs.Connect() != KErrNone) |
|
1446 { |
|
1447 LOGTEXT(_L("TestSettingsFile: could not connect file server")); |
|
1448 // file server couldn't be connected, return false |
|
1449 return KErrNotFound; |
|
1450 } |
|
1451 |
|
1452 // check if config file name length is > 0 |
|
1453 if (configFile.Length() > 0) |
|
1454 { |
|
1455 LOGTEXT(_L("TestSettingsFile: checking location sanity")); |
|
1456 // check sanity of settings file location |
|
1457 if(BaflUtils::CheckFolder(fs, configFile) != KErrNone) |
|
1458 { |
|
1459 LOGTEXT(_L("TestSettingsFile: location sanity check failed")); |
|
1460 fs.Close(); |
|
1461 return KErrGeneral; |
|
1462 } |
|
1463 } |
|
1464 else |
|
1465 { |
|
1466 // configFile length 0, return false |
|
1467 LOGTEXT(_L("TestSettingsFile: config file string null length")); |
|
1468 fs.Close(); |
|
1469 return KErrNotFound; |
|
1470 } |
|
1471 // return true if tests passed |
|
1472 LOGTEXT(_L("TestSettingsFile: exiting...")); |
|
1473 fs.Close(); |
|
1474 return KErrNone; |
|
1475 } |
|
1476 |
|
1477 // -------------------------------------------------------------------------------------------- |
|
1478 GLDEF_C TInt E32Main() |
|
1479 { |
|
1480 // parse command line arguments |
|
1481 TBuf<256> c; |
|
1482 TInt err(KErrNone); |
|
1483 |
|
1484 // copy the full command line with arguments into a buffer |
|
1485 User::CommandLine(c); |
|
1486 |
|
1487 TBuf<256> fileName; |
|
1488 fileName.Append(c); // only one settings param should be |
|
1489 LOGSTRING3("Filename is %S, response %d 1", &fileName, err); |
|
1490 err = TestSettingsFile(fileName); |
|
1491 if(err != KErrNone) |
|
1492 { |
|
1493 LOGSTRING3("Filename is %S, response %d 2", &fileName, err); |
|
1494 // settings file does not exist, copy null desc to file name |
|
1495 fileName.Copy(KNullDesC); |
|
1496 } |
|
1497 |
|
1498 LOGSTRING3("Filename is %S, response %d 3", &fileName, err); |
|
1499 |
|
1500 // if no command line arguments found just start the profiler process |
|
1501 __UHEAP_MARK; |
|
1502 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
1503 TInt ret(KErrNoMemory); |
|
1504 if( cleanup ) |
|
1505 { |
|
1506 TRAPD( ret, RunEngineServerL(fileName) ); |
|
1507 RDebug::Print(_L("Profiler: E32Main() - ret %d"), ret); |
|
1508 delete cleanup; |
|
1509 } |
|
1510 __UHEAP_MARKEND; |
|
1511 |
|
1512 return ret; |
|
1513 } |
|
1514 |
|
1515 |