|
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 #include <memspy/engine/memspyengineobjectcontainer.h> |
|
19 |
|
20 // System includes |
|
21 #include <e32svr.h> |
|
22 |
|
23 // Driver includes |
|
24 #include <memspy/driver/memspydriverclient.h> |
|
25 |
|
26 // User includes |
|
27 #include <memspy/engine/memspyengine.h> |
|
28 #include <memspy/engine/memspyengineutils.h> |
|
29 #include <memspy/engine/memspyengineobjectprocess.h> |
|
30 #include <memspy/engine/memspyengineobjectthread.h> |
|
31 #include <memspy/engine/memspyenginehelperheap.h> |
|
32 #include <memspy/engine/memspyenginehelperstack.h> |
|
33 #include <memspy/engine/memspyenginehelpercodesegment.h> |
|
34 |
|
35 // Literal constants |
|
36 _LIT(KProcessFilter, "*"); |
|
37 _LIT(KEKernProcessName, "ekern"); |
|
38 |
|
39 |
|
40 CMemSpyEngineObjectContainer::CMemSpyEngineObjectContainer( CMemSpyEngine& aEngine ) |
|
41 : iEngine( aEngine ) |
|
42 { |
|
43 /* |
|
44 TFindProcess procFinder( KProcessFilter ); |
|
45 TFullName nextMatch; |
|
46 // |
|
47 while( procFinder.Next( nextMatch ) == KErrNone ) |
|
48 { |
|
49 _LIT(KProcListing, "%S"); |
|
50 RDebug::Print(KProcListing, &nextMatch); |
|
51 |
|
52 |
|
53 _LIT(KFindMask, "*"); |
|
54 nextMatch += KFindMask; |
|
55 // |
|
56 TFindThread threadFinder( nextMatch ); |
|
57 // |
|
58 while( threadFinder.Next( nextMatch ) == KErrNone ) |
|
59 { |
|
60 _LIT(KThreadListing, "+--- %S"); |
|
61 RDebug::Print(KThreadListing, &nextMatch); |
|
62 } |
|
63 } |
|
64 */ |
|
65 } |
|
66 |
|
67 |
|
68 CMemSpyEngineObjectContainer::~CMemSpyEngineObjectContainer() |
|
69 { |
|
70 DestroyProcesses( iGarbage ); |
|
71 DestroyProcesses( iProcesses ); |
|
72 delete iUndertaker; |
|
73 delete iMidwife; |
|
74 delete iIdleNotifyContainerChanged; |
|
75 } |
|
76 |
|
77 |
|
78 void CMemSpyEngineObjectContainer::ConstructL( const TDesC& aFilter ) |
|
79 { |
|
80 iUndertaker = CMemSpyEngineUndertaker::NewL( iEngine.Driver() ); |
|
81 iUndertaker->AddObserverL( *this ); |
|
82 // |
|
83 iMidwife = CMemSpyEngineMidwife::NewL( iEngine.Driver() ); |
|
84 iMidwife->AddObserverL( *this ); |
|
85 // |
|
86 iIdleNotifyContainerChanged = CIdle::NewL( CActive::EPriorityIdle ); |
|
87 // |
|
88 RefreshL( aFilter ); |
|
89 } |
|
90 |
|
91 |
|
92 CMemSpyEngineObjectContainer* CMemSpyEngineObjectContainer::NewL( CMemSpyEngine& aEngine ) |
|
93 { |
|
94 return NewL( KProcessFilter, aEngine ); |
|
95 } |
|
96 |
|
97 |
|
98 CMemSpyEngineObjectContainer* CMemSpyEngineObjectContainer::NewL( const TDesC& aFilter, CMemSpyEngine& aEngine ) |
|
99 { |
|
100 CMemSpyEngineObjectContainer* self = new(ELeave) CMemSpyEngineObjectContainer( aEngine ); |
|
101 CleanupStack::PushL( self ); |
|
102 self->ConstructL( aFilter ); |
|
103 CleanupStack::Pop( self ); |
|
104 return self; |
|
105 } |
|
106 |
|
107 |
|
108 EXPORT_C TInt CMemSpyEngineObjectContainer::Count() const |
|
109 { |
|
110 return iProcesses.Count(); |
|
111 } |
|
112 |
|
113 |
|
114 EXPORT_C TInt CMemSpyEngineObjectContainer::CountAll() const |
|
115 { |
|
116 TInt ret = 0; |
|
117 // |
|
118 const TInt count = iProcesses.Count(); |
|
119 for( TInt i=0; i<count; i++ ) |
|
120 { |
|
121 CMemSpyProcess* process = iProcesses[ i ]; |
|
122 ret += process->Count(); |
|
123 } |
|
124 // |
|
125 return ret; |
|
126 } |
|
127 |
|
128 |
|
129 EXPORT_C void CMemSpyEngineObjectContainer::RefreshL() |
|
130 { |
|
131 RefreshL( KProcessFilter ); |
|
132 } |
|
133 |
|
134 |
|
135 EXPORT_C void CMemSpyEngineObjectContainer::RefreshL( const TDesC& aFilter ) |
|
136 { |
|
137 LocateProcessesL( aFilter ); |
|
138 } |
|
139 |
|
140 |
|
141 EXPORT_C CMemSpyProcess& CMemSpyEngineObjectContainer::At( TInt aIndex ) const |
|
142 { |
|
143 CMemSpyProcess* ret = iProcesses[ aIndex ]; |
|
144 return *ret; |
|
145 } |
|
146 |
|
147 |
|
148 EXPORT_C CMemSpyProcess& CMemSpyEngineObjectContainer::ProcessByIdL( TProcessId aId ) const |
|
149 { |
|
150 CMemSpyProcess* ret = NULL; |
|
151 // |
|
152 const TInt count = iProcesses.Count(); |
|
153 for( TInt i=0; i<count; i++ ) |
|
154 { |
|
155 CMemSpyProcess* process = iProcesses[ i ]; |
|
156 if ( process->Id() == aId ) |
|
157 { |
|
158 ret = process; |
|
159 break; |
|
160 } |
|
161 } |
|
162 // |
|
163 if ( ret == NULL ) |
|
164 { |
|
165 User::Leave( KErrNotFound ); |
|
166 } |
|
167 // |
|
168 return *ret; |
|
169 } |
|
170 |
|
171 |
|
172 EXPORT_C TInt CMemSpyEngineObjectContainer::ProcessIndexById( TProcessId aId ) const |
|
173 { |
|
174 TInt index = KErrNotFound; |
|
175 // |
|
176 const TInt count = iProcesses.Count(); |
|
177 for( TInt i=0; i<count; i++ ) |
|
178 { |
|
179 const CMemSpyProcess* process = iProcesses[ i ]; |
|
180 if ( process->Id() == aId ) |
|
181 { |
|
182 index = i; |
|
183 break; |
|
184 } |
|
185 } |
|
186 // |
|
187 return index; |
|
188 } |
|
189 |
|
190 |
|
191 EXPORT_C TInt CMemSpyEngineObjectContainer::ProcessAndThreadByThreadId( TThreadId aTid, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread ) const |
|
192 { |
|
193 aProcess = NULL; |
|
194 aThread = NULL; |
|
195 TInt error = KErrNotFound; |
|
196 // |
|
197 const TInt count = iProcesses.Count(); |
|
198 for( TInt i=0; i<count; i++ ) |
|
199 { |
|
200 CMemSpyProcess* process = iProcesses[ i ]; |
|
201 |
|
202 // Check whether this process contains the thread we are looking for... |
|
203 const TInt index = process->ThreadIndexById( aTid ); |
|
204 if ( index >= 0 ) |
|
205 { |
|
206 // Found it |
|
207 aProcess = process; |
|
208 aThread = &process->At( index ); |
|
209 error = KErrNone; |
|
210 break; |
|
211 } |
|
212 } |
|
213 // |
|
214 if ( error == KErrNotFound ) |
|
215 { |
|
216 CMemSpyEngineObjectContainer* self = const_cast< CMemSpyEngineObjectContainer* >( this ); |
|
217 TRAP( error, self->TryToCreateProcessAndThreadL( aTid, aProcess, aThread ) ); |
|
218 } |
|
219 // |
|
220 return error; |
|
221 } |
|
222 |
|
223 |
|
224 EXPORT_C TInt CMemSpyEngineObjectContainer::ProcessAndThreadByFullName( const TDesC& aFullName, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread ) const |
|
225 { |
|
226 aProcess = NULL; |
|
227 aThread = NULL; |
|
228 TInt error = KErrNotFound; |
|
229 // |
|
230 const TInt count = iProcesses.Count(); |
|
231 for( TInt i=0; i<count && aThread == NULL; i++ ) |
|
232 { |
|
233 CMemSpyProcess& process = *iProcesses[ i ]; |
|
234 const TInt threadCount = process.Count(); |
|
235 // |
|
236 for(TInt j=0; j<threadCount; j++) |
|
237 { |
|
238 CMemSpyThread& thread = process.At( j ); |
|
239 const TFullName threadName( thread.FullName() ); |
|
240 // |
|
241 if ( threadName.CompareF( aFullName ) == 0 ) |
|
242 { |
|
243 // Found it |
|
244 aProcess = &process; |
|
245 aThread = &thread; |
|
246 error = KErrNone; |
|
247 break; |
|
248 } |
|
249 } |
|
250 |
|
251 } |
|
252 // |
|
253 if ( error == KErrNotFound ) |
|
254 { |
|
255 // NB: cannot use driver API as we must open thread by name, and that only supports opening |
|
256 // by id. |
|
257 RThread thread; |
|
258 error = thread.Open( aFullName ); |
|
259 if ( error == KErrNone ) |
|
260 { |
|
261 const TThreadId threadId = thread.Id(); |
|
262 thread.Close(); |
|
263 |
|
264 CMemSpyEngineObjectContainer* self = const_cast< CMemSpyEngineObjectContainer* >( this ); |
|
265 TRAP( error, self->TryToCreateProcessAndThreadL( threadId, aProcess, aThread ) ); |
|
266 } |
|
267 } |
|
268 // |
|
269 return error; |
|
270 } |
|
271 |
|
272 |
|
273 EXPORT_C TInt CMemSpyEngineObjectContainer::ProcessAndThreadByPartialName( const TDesC& aPartialName, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread ) const |
|
274 { |
|
275 aProcess = NULL; |
|
276 aThread = NULL; |
|
277 TInt error = KErrNotFound; |
|
278 // |
|
279 const TInt count = iProcesses.Count(); |
|
280 for( TInt i=0; i<count && aThread == NULL; i++ ) |
|
281 { |
|
282 CMemSpyProcess& process = *iProcesses[ i ]; |
|
283 const TInt threadCount = process.Count(); |
|
284 // |
|
285 for(TInt j=0; j<threadCount; j++) |
|
286 { |
|
287 CMemSpyThread& thread = process.At( j ); |
|
288 const TFullName threadName( thread.FullName() ); |
|
289 // |
|
290 if ( threadName.FindF( aPartialName ) >= 0 ) |
|
291 { |
|
292 // Found it |
|
293 aProcess = &process; |
|
294 aThread = &thread; |
|
295 error = KErrNone; |
|
296 break; |
|
297 } |
|
298 } |
|
299 |
|
300 } |
|
301 // |
|
302 return error; |
|
303 } |
|
304 |
|
305 |
|
306 EXPORT_C TBool CMemSpyEngineObjectContainer::IsAlive( TProcessId aPid ) const |
|
307 { |
|
308 const TInt processIndex = ProcessIndexById( aPid ); |
|
309 return ( processIndex >= 0 ); |
|
310 } |
|
311 |
|
312 |
|
313 EXPORT_C TBool CMemSpyEngineObjectContainer::IsAlive( TProcessId aPid, TThreadId aTid ) const |
|
314 { |
|
315 TBool isAlive = IsAlive( aPid ); |
|
316 if ( isAlive ) |
|
317 { |
|
318 const TInt processIndex = ProcessIndexById( aPid ); |
|
319 const CMemSpyProcess& process = At( processIndex ); |
|
320 |
|
321 // Check whether the thread is alive |
|
322 isAlive = ( process.ThreadIndexById( aTid ) >= 0 ); |
|
323 } |
|
324 // |
|
325 return isAlive; |
|
326 } |
|
327 |
|
328 |
|
329 EXPORT_C TInt CMemSpyEngineObjectContainer::MdcaCount() const |
|
330 { |
|
331 return iProcesses.Count(); |
|
332 } |
|
333 |
|
334 |
|
335 EXPORT_C TPtrC CMemSpyEngineObjectContainer::MdcaPoint(TInt aIndex) const |
|
336 { |
|
337 const CMemSpyProcess* process = iProcesses[ aIndex ]; |
|
338 return TPtrC( process->NameForListBox() ); |
|
339 } |
|
340 |
|
341 |
|
342 void CMemSpyEngineObjectContainer::LocateProcessesL( const TDesC& aFilter ) |
|
343 { |
|
344 #ifdef _DEBUG |
|
345 RDebug::Printf( "CMemSpyEngineObjectContainer::LocateProcessesL() - START" ); |
|
346 #endif |
|
347 DestroyProcesses( iProcesses ); |
|
348 // |
|
349 const TProcessId myProcessId = RProcess().Id(); |
|
350 // |
|
351 TFindProcess finder( aFilter ); |
|
352 TFullName nextMatch; |
|
353 // |
|
354 while( finder.Next( nextMatch ) == KErrNone ) |
|
355 { |
|
356 if ( nextMatch.FindF(KEKernProcessName) == KErrNotFound ) |
|
357 { |
|
358 #ifdef _DEBUG |
|
359 RDebug::Print(_L( "CMemSpyEngineObjectContainer::LocateProcessesL() - found Proc: %S"), &nextMatch ); |
|
360 #endif |
|
361 |
|
362 RProcess p; |
|
363 const TInt r = p.Open( nextMatch ); |
|
364 TProcessId processId( KNullProcessId ); |
|
365 if ( r == KErrNone ) |
|
366 { |
|
367 processId = p.Id(); |
|
368 } |
|
369 p.Close(); |
|
370 |
|
371 #ifdef _DEBUG |
|
372 RDebug::Printf( "CMemSpyEngineObjectContainer::LocateProcessesL() - open err: %d", r ); |
|
373 #endif |
|
374 |
|
375 if ( r == KErrNone ) |
|
376 { |
|
377 if ( processId != myProcessId ) |
|
378 { |
|
379 TRAPD( err, CreateProcessL( processId ) ); |
|
380 #ifdef _DEBUG |
|
381 RDebug::Printf( "CMemSpyEngineObjectContainer::LocateProcessesL() - CreateProcessL err: %d", err ); |
|
382 #endif |
|
383 err = err; |
|
384 } |
|
385 } |
|
386 } |
|
387 } |
|
388 // |
|
389 SortByName(); |
|
390 |
|
391 #ifdef _DEBUG |
|
392 RDebug::Printf( "CMemSpyEngineObjectContainer::LocateProcessesL() - END" ); |
|
393 #endif |
|
394 } |
|
395 |
|
396 |
|
397 CMemSpyProcess* CMemSpyEngineObjectContainer::CreateProcessL( const TProcessId& aId ) |
|
398 { |
|
399 #ifdef _DEBUG |
|
400 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::CreateProcessL() - START - pid: 0x%04x", (TUint) aId ); |
|
401 #endif |
|
402 |
|
403 CMemSpyProcess* processObj = CMemSpyProcess::NewLC( aId, iEngine ); |
|
404 const TPtrC pName( processObj->Name() ); |
|
405 |
|
406 if ( pName.FindF( KEKernProcessName ) == KErrNotFound ) |
|
407 { |
|
408 if ( processObj->Count() == 0 ) |
|
409 { |
|
410 // Calls delete |
|
411 #ifdef _DEBUG |
|
412 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::CreateProcessL() - process has no threads... deleting it!" ); |
|
413 #endif |
|
414 processObj->Close(); |
|
415 processObj = NULL; |
|
416 } |
|
417 else |
|
418 { |
|
419 // Make sure we don't add duplicate processes... |
|
420 AppendL( processObj ); |
|
421 } |
|
422 } |
|
423 else |
|
424 { |
|
425 // We don't support kernel-side threads |
|
426 #ifdef _DEBUG |
|
427 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::CreateProcessL() - kernel process... deleting it!" ); |
|
428 #endif |
|
429 processObj->Close(); |
|
430 processObj = NULL; |
|
431 } |
|
432 |
|
433 CleanupStack::Pop(); |
|
434 |
|
435 #ifdef _DEBUG |
|
436 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::CreateProcessL() - END - pid: 0x%04x, processObj: 0x%08x", (TUint) aId, processObj ); |
|
437 #endif |
|
438 return processObj; |
|
439 } |
|
440 |
|
441 |
|
442 void CMemSpyEngineObjectContainer::DestroyProcesses( RArray< CMemSpyProcess* >& aList ) |
|
443 { |
|
444 while( aList.Count() ) |
|
445 { |
|
446 CMemSpyProcess* process = aList[ 0 ]; |
|
447 aList.Remove( 0 ); |
|
448 process->Close(); |
|
449 } |
|
450 |
|
451 aList.Close(); |
|
452 } |
|
453 |
|
454 |
|
455 void CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL( const TThreadId& aTid, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread ) |
|
456 { |
|
457 #ifdef _DEBUG |
|
458 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(1) - START - aTid: 0x%04x", (TUint) aTid ); |
|
459 #endif |
|
460 |
|
461 // Must open thread and process in order to get process id. |
|
462 RThread thread; |
|
463 User::LeaveIfError( iEngine.Driver().OpenThread( aTid, thread ) ); |
|
464 CleanupClosePushL( thread ); |
|
465 RProcess process; |
|
466 User::LeaveIfError( thread.Process( process ) ); |
|
467 const TProcessId processId = process.Id(); |
|
468 process.Close(); |
|
469 |
|
470 // Call overload |
|
471 TryToCreateProcessAndThreadL( thread, aProcess, aThread ); |
|
472 |
|
473 CleanupStack::PopAndDestroy( &thread ); |
|
474 |
|
475 #ifdef _DEBUG |
|
476 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(1) - END - aTid: 0x%04x", (TUint) aTid ); |
|
477 #endif |
|
478 } |
|
479 |
|
480 |
|
481 void CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL( const RThread& aRThread, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread ) |
|
482 { |
|
483 #ifdef _DEBUG |
|
484 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - START - aTid: 0x%04x", (TUint) aRThread.Id() ); |
|
485 #endif |
|
486 |
|
487 // Full name of process |
|
488 TFullName* name = new(ELeave) TFullName(); |
|
489 CleanupStack::PushL( name ); |
|
490 |
|
491 // Must open thread and process in order to get process id. |
|
492 RProcess process; |
|
493 User::LeaveIfError( aRThread.Process( process ) ); |
|
494 process.FullName( *name ); |
|
495 const TProcessId processId = process.Id(); |
|
496 process.Close(); |
|
497 |
|
498 const TBool isKernel = ( name->FindF( KEKernProcessName ) >= KErrNone ); |
|
499 |
|
500 #ifdef _DEBUG |
|
501 RDebug::Print( _L("[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - pid: 0x%04x, name: %S"), (TUint) processId, name ); |
|
502 #endif |
|
503 |
|
504 CleanupStack::PopAndDestroy( name ); |
|
505 |
|
506 // See if we have already created a process for this process id... |
|
507 CMemSpyProcess* processObj = NULL; |
|
508 const TInt procIndex = ProcessIndexById( processId ); |
|
509 |
|
510 #ifdef _DEBUG |
|
511 RDebug::Print( _L("[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - pid: 0x%04x, index: %d"), (TUint) processId, procIndex ); |
|
512 #endif |
|
513 |
|
514 if ( isKernel ) |
|
515 { |
|
516 #ifdef _DEBUG |
|
517 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - caller requested a kernel thread/process..." ); |
|
518 #endif |
|
519 __ASSERT_ALWAYS( procIndex == KErrNotFound, MemSpyEngineUtils::Panic( EMemSpyEnginePanicEncounteredKernelUnexpectedly ) ); |
|
520 |
|
521 #ifdef _DEBUG |
|
522 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - leaving with KErrNotSupported" ); |
|
523 #endif |
|
524 User::Leave( KErrNotSupported ); |
|
525 } |
|
526 else if ( aRThread.Id() == RThread().Id() ) |
|
527 { |
|
528 TRACE( RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - trying to create MemSpy -> leaving with KErrNotSupported" ) ); |
|
529 User::Leave( KErrNotSupported ); |
|
530 } |
|
531 else |
|
532 { |
|
533 if ( procIndex >= 0 ) |
|
534 { |
|
535 // Existing process, but new thread? |
|
536 processObj = iProcesses[ procIndex ]; |
|
537 |
|
538 // Make new thread |
|
539 processObj->HandleThreadIsBornL( aRThread.Id() ); |
|
540 } |
|
541 else |
|
542 { |
|
543 // Must also create a new process. This should, in theory, ensure |
|
544 // the thread is also created. |
|
545 processObj = CMemSpyProcess::NewLC( processId, iEngine ); |
|
546 if ( processObj->Count() == 0 ) |
|
547 { |
|
548 // No threads, discard process and leave |
|
549 User::Leave( KErrNotFound ); |
|
550 } |
|
551 else |
|
552 { |
|
553 // Save process |
|
554 AppendL( processObj ); |
|
555 } |
|
556 |
|
557 // Tidy up |
|
558 CleanupStack::Pop(); |
|
559 } |
|
560 |
|
561 // Check to see if the process contains the specified thread (it should do, since we just found |
|
562 // the process using it). |
|
563 CMemSpyThread& threadObj = processObj->ThreadByIdL( aRThread.Id() ); |
|
564 |
|
565 // We're done now. |
|
566 aProcess = processObj; |
|
567 aThread = &threadObj; |
|
568 |
|
569 // Update sort order |
|
570 Resort(); |
|
571 |
|
572 // Signal UI |
|
573 AsyncNotifyUiOfContainerChanges(); |
|
574 } |
|
575 |
|
576 #ifdef _DEBUG |
|
577 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - END - aTid: 0x%04x, pid: 0x%04x", (TUint) aRThread.Id(), (TUint) processId ); |
|
578 #endif |
|
579 } |
|
580 |
|
581 |
|
582 void CMemSpyEngineObjectContainer::Resort() |
|
583 { |
|
584 switch( iSortType ) |
|
585 { |
|
586 case ESortById: |
|
587 { |
|
588 TLinearOrder< CMemSpyProcess* > comparer( CompareById ); |
|
589 iProcesses.Sort( comparer ); |
|
590 } |
|
591 break; |
|
592 default: |
|
593 case ESortByName: |
|
594 { |
|
595 TLinearOrder< CMemSpyProcess* > comparer( CompareByName ); |
|
596 iProcesses.Sort( comparer ); |
|
597 } |
|
598 break; |
|
599 case ESortByThreadCount: |
|
600 { |
|
601 TLinearOrder< CMemSpyProcess* > comparer( CompareByThreadCount ); |
|
602 iProcesses.Sort( comparer ); |
|
603 } |
|
604 break; |
|
605 case ESortByCodeSegs: |
|
606 { |
|
607 TLinearOrder< CMemSpyProcess* > comparer( CompareByCodeSegs ); |
|
608 iProcesses.Sort( comparer ); |
|
609 } |
|
610 break; |
|
611 case ESortByHeapUsage: |
|
612 { |
|
613 TLinearOrder< CMemSpyProcess* > comparer( CompareByHeapUsage ); |
|
614 iProcesses.Sort( comparer ); |
|
615 } |
|
616 break; |
|
617 case ESortByStackUsage: |
|
618 { |
|
619 TLinearOrder< CMemSpyProcess* > comparer( CompareByStackUsage ); |
|
620 iProcesses.Sort( comparer ); |
|
621 } |
|
622 break; |
|
623 } |
|
624 } |
|
625 |
|
626 |
|
627 EXPORT_C void CMemSpyEngineObjectContainer::SortById() |
|
628 { |
|
629 iSortType = ESortById; |
|
630 Resort(); |
|
631 } |
|
632 |
|
633 |
|
634 EXPORT_C void CMemSpyEngineObjectContainer::SortByName() |
|
635 { |
|
636 iSortType = ESortByName; |
|
637 Resort(); |
|
638 } |
|
639 |
|
640 |
|
641 EXPORT_C void CMemSpyEngineObjectContainer::SortByThreadCount() |
|
642 { |
|
643 iSortType = ESortByThreadCount; |
|
644 Resort(); |
|
645 } |
|
646 |
|
647 |
|
648 EXPORT_C void CMemSpyEngineObjectContainer::SortByCodeSegs() |
|
649 { |
|
650 iSortType = ESortByCodeSegs; |
|
651 Resort(); |
|
652 } |
|
653 |
|
654 |
|
655 EXPORT_C void CMemSpyEngineObjectContainer::SortByHeapUsage() |
|
656 { |
|
657 iSortType = ESortByHeapUsage; |
|
658 Resort(); |
|
659 } |
|
660 |
|
661 |
|
662 EXPORT_C void CMemSpyEngineObjectContainer::SortByStackUsage() |
|
663 { |
|
664 iSortType = ESortByStackUsage; |
|
665 Resort(); |
|
666 } |
|
667 |
|
668 |
|
669 void CMemSpyEngineObjectContainer::Remove( CMemSpyProcess& aProcess ) |
|
670 { |
|
671 const TInt index = ProcessIndexById( aProcess.Id() ); |
|
672 if ( index >= 0 ) |
|
673 { |
|
674 iProcesses.Remove( index ); |
|
675 } |
|
676 } |
|
677 |
|
678 |
|
679 void CMemSpyEngineObjectContainer::AppendL( CMemSpyProcess* aProcess ) |
|
680 { |
|
681 const TInt error = iProcesses.Append( aProcess ); |
|
682 User::LeaveIfError( error ); |
|
683 } |
|
684 |
|
685 |
|
686 TInt CMemSpyEngineObjectContainer::CompareById( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight ) |
|
687 { |
|
688 TInt ret = 1; |
|
689 // |
|
690 if ( aLeft->Id() < aRight->Id() ) |
|
691 { |
|
692 ret = -1; |
|
693 } |
|
694 else if ( aLeft->Id() == aRight->Id() ) |
|
695 { |
|
696 ret = 0; |
|
697 } |
|
698 // |
|
699 return ret; |
|
700 } |
|
701 |
|
702 |
|
703 TInt CMemSpyEngineObjectContainer::CompareByThreadCount( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight ) |
|
704 { |
|
705 TInt ret = -1; |
|
706 // |
|
707 if ( aLeft->Count() < aRight->Count() ) |
|
708 { |
|
709 ret = 1; |
|
710 } |
|
711 else if ( aLeft->Count() == aRight->Count() ) |
|
712 { |
|
713 // Sort by name when thread counts are the same |
|
714 ret = aLeft->Name().CompareF( aRight->Name() ); |
|
715 } |
|
716 // |
|
717 return ret; |
|
718 } |
|
719 |
|
720 |
|
721 TInt CMemSpyEngineObjectContainer::CompareByName( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight ) |
|
722 { |
|
723 return aLeft->Name().CompareF( aRight->Name() ); |
|
724 } |
|
725 |
|
726 |
|
727 TInt CMemSpyEngineObjectContainer::CompareByCodeSegs( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight ) |
|
728 { |
|
729 CMemSpyEngine& engine = aLeft->Engine(); |
|
730 CMemSpyEngineHelperCodeSegment& helper = engine.HelperCodeSegment(); |
|
731 // |
|
732 TInt leftCount = 0; |
|
733 TInt rightCount = 0; |
|
734 // |
|
735 TRAP_IGNORE( |
|
736 CMemSpyEngineCodeSegList* leftList = helper.CodeSegmentListL( aLeft->Id() ); |
|
737 leftCount = leftList->Count(); |
|
738 delete leftList; |
|
739 // |
|
740 CMemSpyEngineCodeSegList* rightList = helper.CodeSegmentListL( aRight->Id() ); |
|
741 rightCount = rightList->Count(); |
|
742 delete rightList; |
|
743 ); |
|
744 // |
|
745 TInt ret = -1; |
|
746 // |
|
747 if ( leftCount < rightCount ) |
|
748 { |
|
749 ret = 1; |
|
750 } |
|
751 else if ( leftCount == rightCount ) |
|
752 { |
|
753 ret = 0; |
|
754 } |
|
755 // |
|
756 return ret; |
|
757 } |
|
758 |
|
759 |
|
760 TInt CMemSpyEngineObjectContainer::CompareByHeapUsage( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight ) |
|
761 { |
|
762 CMemSpyEngine& engine = aLeft->Engine(); |
|
763 CMemSpyEngineHelperHeap& helper = engine.HelperHeap(); |
|
764 // |
|
765 TInt leftSize = 0; |
|
766 TInt rightSize = 0; |
|
767 // |
|
768 TRAP_IGNORE( |
|
769 RArray< TMemSpyHeapInfo > leftInfos; |
|
770 CleanupClosePushL( leftInfos ); |
|
771 helper.GetHeapInfoUserL( *aLeft, leftInfos ); |
|
772 const TInt leftCount = leftInfos.Count(); |
|
773 for( TInt i=0; i<leftCount; i++ ) |
|
774 { |
|
775 const TMemSpyHeapInfo& info = leftInfos[ i ]; |
|
776 if ( info.Type() == TMemSpyHeapInfo::ETypeRHeap ) |
|
777 { |
|
778 leftSize += (TInt) info.AsRHeap().ObjectData().Size(); |
|
779 } |
|
780 } |
|
781 CleanupStack::PopAndDestroy( &leftInfos ); |
|
782 ); |
|
783 // |
|
784 TRAP_IGNORE( |
|
785 RArray< TMemSpyHeapInfo > rightInfos; |
|
786 CleanupClosePushL( rightInfos ); |
|
787 helper.GetHeapInfoUserL( *aRight, rightInfos ); |
|
788 const TInt rightCount = rightInfos.Count(); |
|
789 for( TInt i=0; i<rightCount; i++ ) |
|
790 { |
|
791 const TMemSpyHeapInfo& info = rightInfos[ i ]; |
|
792 if ( info.Type() == TMemSpyHeapInfo::ETypeRHeap ) |
|
793 { |
|
794 rightSize += (TInt) info.AsRHeap().ObjectData().Size(); |
|
795 } |
|
796 } |
|
797 CleanupStack::PopAndDestroy( &rightInfos ); |
|
798 ); |
|
799 // |
|
800 TInt ret = -1; |
|
801 // |
|
802 if ( leftSize < rightSize ) |
|
803 { |
|
804 ret = 1; |
|
805 } |
|
806 else if ( leftSize == rightSize ) |
|
807 { |
|
808 ret = 0; |
|
809 } |
|
810 // |
|
811 return ret; |
|
812 } |
|
813 |
|
814 |
|
815 TInt CMemSpyEngineObjectContainer::CompareByStackUsage( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight ) |
|
816 { |
|
817 CMemSpyEngine& engine = aLeft->Engine(); |
|
818 CMemSpyEngineHelperStack& helper = engine.HelperStack(); |
|
819 // |
|
820 const TInt leftCount = helper.CalculateStackSizes( *aLeft ); |
|
821 const TInt rightCount = helper.CalculateStackSizes( *aRight ); |
|
822 // |
|
823 TInt ret = -1; |
|
824 // |
|
825 if ( leftCount < rightCount ) |
|
826 { |
|
827 ret = 1; |
|
828 } |
|
829 else if ( leftCount == rightCount ) |
|
830 { |
|
831 ret = 0; |
|
832 } |
|
833 // |
|
834 return ret; |
|
835 } |
|
836 |
|
837 |
|
838 TBool CMemSpyEngineObjectContainer::MoveToGarbageL( const TProcessId& aId ) |
|
839 { |
|
840 const TInt pos = ProcessIndexById( aId ); |
|
841 |
|
842 if ( pos >= 0 ) |
|
843 { |
|
844 CMemSpyProcess* proc = iProcesses[ pos ]; |
|
845 |
|
846 #ifdef _DEBUG |
|
847 const TPtrC pName( proc->Name() ); |
|
848 RDebug::Print( _L("[MemSpy] CMemSpyEngineObjectContainer::MoveToGarbageL() - pid: 0x%04x, proc: 0x%08x, pos: %d, id: 0x%04x, name: %S"), (TUint) aId, proc, pos, (TUint) proc->Id(), &pName ); |
|
849 #endif |
|
850 |
|
851 User::LeaveIfError( iGarbage.Append( proc ) ); |
|
852 iProcesses.Remove( pos ); |
|
853 } |
|
854 else |
|
855 { |
|
856 #ifdef _DEBUG |
|
857 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::MoveToGarbageL() - pid: 0x%04x, pos: KErrNotFound", (TUint) aId ); |
|
858 #endif |
|
859 } |
|
860 |
|
861 return ( pos >= 0 ); |
|
862 } |
|
863 |
|
864 |
|
865 |
|
866 |
|
867 |
|
868 |
|
869 |
|
870 |
|
871 |
|
872 |
|
873 |
|
874 |
|
875 |
|
876 |
|
877 |
|
878 |
|
879 |
|
880 |
|
881 void CMemSpyEngineObjectContainer::ThreadIsDeadL( const TThreadId& aId, const RThread& aThread ) |
|
882 { |
|
883 // Try to find the thread in question... |
|
884 CMemSpyProcess* process = NULL; |
|
885 CMemSpyThread* thread = NULL; |
|
886 // |
|
887 const TInt err = ProcessAndThreadByThreadId( aId, process, thread ); |
|
888 if ( err == KErrNone && thread ) |
|
889 { |
|
890 // This will force the thread to detect if it is dead or not... |
|
891 thread->SetDeadL( aThread ); |
|
892 |
|
893 // Signal UI |
|
894 AsyncNotifyUiOfContainerChanges(); |
|
895 } |
|
896 } |
|
897 |
|
898 |
|
899 void CMemSpyEngineObjectContainer::ProcessIsDeadL( const TProcessId& aId, const RProcess& aProcess ) |
|
900 { |
|
901 const TInt index = ProcessIndexById( aId ); |
|
902 if ( index >= 0 ) |
|
903 { |
|
904 CMemSpyProcess* process = iProcesses[ index ]; |
|
905 process->SetDeadL( aProcess ); |
|
906 |
|
907 // Signal UI |
|
908 AsyncNotifyUiOfContainerChanges(); |
|
909 } |
|
910 } |
|
911 |
|
912 |
|
913 void CMemSpyEngineObjectContainer::ThreadIsBornL( const TThreadId& /*aId*/, const RThread& aThread ) |
|
914 { |
|
915 if ( aThread.Handle() != KNullHandle ) |
|
916 { |
|
917 // The thread and process objects that will be created (or found, if they already exist). |
|
918 CMemSpyProcess* process = NULL; |
|
919 CMemSpyThread* thread = NULL; |
|
920 |
|
921 // Create the objects if needed |
|
922 TryToCreateProcessAndThreadL( aThread, process, thread ); |
|
923 } |
|
924 } |
|
925 |
|
926 |
|
927 void CMemSpyEngineObjectContainer::ProcessIsBornL( const TProcessId& aId, const RProcess& /*aProcess*/ ) |
|
928 { |
|
929 #ifdef _DEBUG |
|
930 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::ProcessIsBornL() - START - pid: 0x%04x", (TUint) aId ); |
|
931 #endif |
|
932 (void) aId; |
|
933 |
|
934 // This gets handled by the new thread creation. When the first thread in the process |
|
935 // is created, we'll also prepare a new process object. |
|
936 |
|
937 #ifdef _DEBUG |
|
938 RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::ProcessIsBornL() - END - pid: 0x%04x", (TUint) aId ); |
|
939 #endif |
|
940 } |
|
941 |
|
942 |
|
943 void CMemSpyEngineObjectContainer::AsyncNotifyUiOfContainerChanges() |
|
944 { |
|
945 iIdleNotifyContainerChanged->Cancel(); |
|
946 iIdleNotifyContainerChanged->Start( TCallBack( NotifyUiOfContainerChanges, this ) ); |
|
947 } |
|
948 |
|
949 |
|
950 TBool CMemSpyEngineObjectContainer::NotifyUiOfContainerChanges( TAny* aSelf ) |
|
951 { |
|
952 CMemSpyEngineObjectContainer* self = reinterpret_cast< CMemSpyEngineObjectContainer* >( aSelf ); |
|
953 TRAP_IGNORE( self->iEngine.NotifyContainerChangeL() ); |
|
954 return EFalse; |
|
955 } |
|
956 |
|
957 |
|
958 |