|
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 using System; |
|
18 using System.Collections.Generic; |
|
19 using System.IO; |
|
20 using System.Threading; |
|
21 using SymbianDebugLib.Engine; |
|
22 using SymbianUtils; |
|
23 using SymbianUtils.Tracer; |
|
24 using SymbianUtils.Threading; |
|
25 using SymbianUtils.FileSystem; |
|
26 using CrashItemLib.Crash.Base; |
|
27 using CrashItemLib.Crash.Container; |
|
28 using CrashItemLib.Engine.Interfaces; |
|
29 using CrashItemLib.Engine.Operations; |
|
30 using CrashItemLib.Engine.Primer; |
|
31 using CrashItemLib.Engine.ProblemDetectors; |
|
32 using CrashItemLib.Engine.Sources; |
|
33 using CrashItemLib.PluginAPI; |
|
34 using CrashItemLib.Sink; |
|
35 |
|
36 namespace CrashItemLib.Engine |
|
37 { |
|
38 public class CIEngine : DisposableObject, IEnumerable<CIContainer>, ITracer |
|
39 { |
|
40 #region Enumerations |
|
41 public enum TState |
|
42 { |
|
43 // We've started to process the crash sources |
|
44 EStateProcessingStarted = 0, |
|
45 |
|
46 // Engine is idle & fully ready for display & output |
|
47 EStateProcessingComplete |
|
48 } |
|
49 |
|
50 public enum TSourceEvent |
|
51 { |
|
52 EEventSourceReady = 0, |
|
53 EEventSourceProgress, |
|
54 EEventSourceStateChanged |
|
55 } |
|
56 |
|
57 public enum TCrashEvent |
|
58 { |
|
59 EEventCrashAdded = 0, |
|
60 EEventCrashRemoved, |
|
61 EEventCrashRemovedAll |
|
62 } |
|
63 #endregion |
|
64 |
|
65 #region Delegates & events |
|
66 public delegate void CIEngineStateHandler( TState aEvent ); |
|
67 public event CIEngineStateHandler StateChanged = delegate( TState aState ) { }; |
|
68 |
|
69 public delegate void CIEngineSourceObserver( TSourceEvent aEvent, CIEngineSource aSource, object aParameter ); |
|
70 public event CIEngineSourceObserver SourceObservers = delegate( TSourceEvent aEvent, CIEngineSource aSource, object aParameter ) { }; |
|
71 |
|
72 public delegate void CIEngineCrashObserver( TCrashEvent aEvent, CIContainer aContainer ); |
|
73 public event CIEngineCrashObserver CrashObservers; |
|
74 |
|
75 public delegate void CIExceptionHandler( Exception aException ); |
|
76 public event CIExceptionHandler ExceptionHandlers = delegate( Exception aException ) { }; |
|
77 #endregion |
|
78 |
|
79 #region Constructors |
|
80 public CIEngine( DbgEngine aDebugEngine, ICIEngineUI aUI ) |
|
81 { |
|
82 iUI = aUI; |
|
83 iDebugEngine = aDebugEngine; |
|
84 // |
|
85 iPrimer = new CIEnginePrimer( this ); |
|
86 iPlugins = new CFFPluginRegistry( this ); |
|
87 iSinkManager = new CISinkManager( this ); |
|
88 iSources = new CIEngineSourceCollection( this ); |
|
89 iContainerIndex = new CIContainerIndex( this ); |
|
90 iContainerCollection = new CIContainerCollection(); |
|
91 iOperationManager = new CIEngineOperationManager( this ); |
|
92 iProblemDetectorManager = new CIProblemDetectorManager( this ); |
|
93 } |
|
94 #endregion |
|
95 |
|
96 #region API |
|
97 public void ClearAll() |
|
98 { |
|
99 lock ( iSources ) |
|
100 { |
|
101 iSources.Clear(); |
|
102 } |
|
103 ClearCrashes(); |
|
104 } |
|
105 |
|
106 public void ClearCrashes() |
|
107 { |
|
108 bool notify = true; |
|
109 lock ( iContainerCollection ) |
|
110 { |
|
111 notify = iContainerCollection.Count > 0; |
|
112 iContainerCollection.Clear(); |
|
113 } |
|
114 // |
|
115 if ( notify ) |
|
116 { |
|
117 OnContainerRemovedAll(); |
|
118 } |
|
119 } |
|
120 |
|
121 public bool Prime( FileInfo aFile ) |
|
122 { |
|
123 bool success = false; |
|
124 // |
|
125 try |
|
126 { |
|
127 success = iPrimer.Prime( aFile ); |
|
128 } |
|
129 catch ( Exception ) |
|
130 { |
|
131 } |
|
132 // |
|
133 return success; |
|
134 } |
|
135 |
|
136 public bool Prime( DirectoryInfo aDirectory ) |
|
137 { |
|
138 bool success = false; |
|
139 // |
|
140 try |
|
141 { |
|
142 iPrimer.Prime( aDirectory ); |
|
143 success = true; |
|
144 } |
|
145 catch ( Exception ) |
|
146 { |
|
147 } |
|
148 // |
|
149 return success; |
|
150 } |
|
151 |
|
152 public bool PrimeRecursive( DirectoryInfo aDirectory ) |
|
153 { |
|
154 bool success = false; |
|
155 // |
|
156 try |
|
157 { |
|
158 iPrimer.PrimeRecursive( aDirectory ); |
|
159 success = true; |
|
160 } |
|
161 catch ( Exception ) |
|
162 { |
|
163 } |
|
164 // |
|
165 return success; |
|
166 } |
|
167 |
|
168 public void IdentifyCrashes( TSynchronicity aSynchronicity ) |
|
169 { |
|
170 // If we must operate in synchronous mode, that is, we must not |
|
171 // return until the all the crash item containers are prepared, |
|
172 // then we created a blocking object that will be signalled when |
|
173 // all the asynchronous operations are complete. |
|
174 DestroyBlocker(); |
|
175 if ( aSynchronicity == TSynchronicity.ESynchronous ) |
|
176 { |
|
177 iSynchronousBlocker = new ManualResetEvent( false ); |
|
178 } |
|
179 |
|
180 // Next, we start processing the source files in order to create |
|
181 // crash containers. |
|
182 DestroySourceProcessor(); |
|
183 iSourceProcessor = new CIEngineSourceProcessor( iSources ); |
|
184 iSourceProcessor.EventHandler += new CIEngineSourceProcessor.ProcessorEventHandler( SourceProcessor_EventHandler ); |
|
185 iSourceProcessor.Start( TSynchronicity.EAsynchronous ); |
|
186 |
|
187 // Now we operate asynchronously. When the source processor has read |
|
188 // all of the CIEngineSource objects, it will trigger and event |
|
189 // callback (SourceProcessor_EventHandler) which will cause us to start |
|
190 // the serialized operation manager. |
|
191 // |
|
192 // When the serialized operation manager completes, it will again indicate |
|
193 // this via an event callback at which point we will trigger the manual |
|
194 // reset event (blocker) and therefore resume this main thread. |
|
195 if ( aSynchronicity == TSynchronicity.ESynchronous ) |
|
196 { |
|
197 // Now wait. |
|
198 using ( iSynchronousBlocker ) |
|
199 { |
|
200 iSynchronousBlocker.WaitOne(); |
|
201 } |
|
202 iSynchronousBlocker = null; |
|
203 } |
|
204 } |
|
205 #endregion |
|
206 |
|
207 #region Properties |
|
208 public int Count |
|
209 { |
|
210 get |
|
211 { |
|
212 lock ( iContainerCollection ) |
|
213 { |
|
214 return iContainerCollection.Count; |
|
215 } |
|
216 } |
|
217 } |
|
218 |
|
219 public CIContainer this[ int aIndex ] |
|
220 { |
|
221 get |
|
222 { |
|
223 lock ( iContainerCollection ) |
|
224 { |
|
225 return iContainerCollection[ aIndex ]; |
|
226 } |
|
227 } |
|
228 } |
|
229 |
|
230 public DbgEngine DebugEngine |
|
231 { |
|
232 get { return iDebugEngine; } |
|
233 } |
|
234 |
|
235 public CISinkManager SinkManager |
|
236 { |
|
237 get { return iSinkManager; } |
|
238 } |
|
239 |
|
240 public CFFPluginRegistry PluginRegistry |
|
241 { |
|
242 get { return iPlugins; } |
|
243 } |
|
244 |
|
245 public CIEngineSourceCollection Sources |
|
246 { |
|
247 get { return iSources; } |
|
248 } |
|
249 #endregion |
|
250 |
|
251 #region Event handlers |
|
252 private void SourceProcessor_EventHandler( CIEngineSourceProcessor.TEvent aEvent ) |
|
253 { |
|
254 this.Trace( "[CIEngine] SourceProcessor_EventHandler() - START - aEvent: {0}", aEvent ); |
|
255 // |
|
256 if ( aEvent == CIEngineSourceProcessor.TEvent.EEventStarting ) |
|
257 { |
|
258 OnStateChanged( TState.EStateProcessingStarted ); |
|
259 ClearCrashes(); |
|
260 } |
|
261 else if ( aEvent == CIEngineSourceProcessor.TEvent.EEventCompleted ) |
|
262 { |
|
263 DestroySourceProcessor(); |
|
264 // |
|
265 DestroyIndexProcessor(); |
|
266 iIndexProcessor = new CIContainerIndexProcessor( iContainerIndex, this ); |
|
267 iIndexProcessor.EventHandler += new CIContainerIndexProcessor.ProcessorEventHandler( IndexProcessor_EventHandler ); |
|
268 iIndexProcessor.Start( TSynchronicity.EAsynchronous ); |
|
269 } |
|
270 // |
|
271 this.Trace( "[CIEngine] SourceProcessor_EventHandler() - END - aEvent: {0}", aEvent ); |
|
272 } |
|
273 |
|
274 private void IndexProcessor_EventHandler( CIContainerIndexProcessor.TEvent aEvent ) |
|
275 { |
|
276 this.Trace( "[CIEngine] IndexProcessor_EventHandler() - START - aEvent: {0}", aEvent ); |
|
277 // |
|
278 if ( aEvent == CIContainerIndexProcessor.TEvent.EEventStarting ) |
|
279 { |
|
280 } |
|
281 else if ( aEvent == CIContainerIndexProcessor.TEvent.EEventCompleted ) |
|
282 { |
|
283 DestroyIndexProcessor(); |
|
284 |
|
285 // All the sources have been processed. Create any problem detectors. |
|
286 iProblemDetectorManager.EventHandler += new MultiThreadedProcessor<CIProblemDetector>.ProcessorEventHandler( ProblemDetectorManager_EventHandler ); |
|
287 iProblemDetectorManager.Start( TSynchronicity.EAsynchronous ); |
|
288 } |
|
289 // |
|
290 this.Trace( "[CIEngine] IndexProcessor_EventHandler() - END - aEvent: {0}", aEvent ); |
|
291 } |
|
292 |
|
293 private void ProblemDetectorManager_EventHandler( MultiThreadedProcessor<CIProblemDetector>.TEvent aEvent ) |
|
294 { |
|
295 this.Trace( "[CIEngine] ProblemDetectorManager_EventHandler() - START - aEvent: {0}", aEvent ); |
|
296 // |
|
297 if ( aEvent == MultiThreadedProcessor<CIProblemDetector>.TEvent.EEventStarting ) |
|
298 { |
|
299 } |
|
300 else if ( aEvent == MultiThreadedProcessor<CIProblemDetector>.TEvent.EEventCompleted ) |
|
301 { |
|
302 iProblemDetectorManager.EventHandler -= new MultiThreadedProcessor<CIProblemDetector>.ProcessorEventHandler( ProblemDetectorManager_EventHandler ); |
|
303 |
|
304 // Run any serialized operations |
|
305 iOperationManager.StateHandler += new CIEngineOperationManager.QueueStateHandler( OperationManager_StateHandler ); |
|
306 iOperationManager.Start(); |
|
307 } |
|
308 // |
|
309 this.Trace( "[CIEngine] ProblemDetectorManager_EventHandler() - END - aEvent: {0}", aEvent ); |
|
310 } |
|
311 |
|
312 private void OperationManager_StateHandler( CIEngineOperationManager.TState aState ) |
|
313 { |
|
314 this.Trace( "[CIEngine] OperationManager_StateHandler() - START - aState: {0}", aState ); |
|
315 // |
|
316 if ( aState == SymbianUtils.SerializedOperations.SerializedOperationManager.TState.EStateOperationsCompleted ) |
|
317 { |
|
318 iOperationManager.StateHandler -= new CIEngineOperationManager.QueueStateHandler( OperationManager_StateHandler ); |
|
319 // |
|
320 IdentifyCrashesComplete(); |
|
321 } |
|
322 // |
|
323 this.Trace( "[CIEngine] OperationManager_StateHandler() - END - aState: {0}", aState ); |
|
324 } |
|
325 #endregion |
|
326 |
|
327 #region Internal delegates |
|
328 private delegate void VoidHandler(); |
|
329 #endregion |
|
330 |
|
331 #region Internal methods |
|
332 internal void Add( CIContainer aContainer ) |
|
333 { |
|
334 string fileName = aContainer.Source.MasterFileName; |
|
335 if ( string.IsNullOrEmpty( fileName ) ) |
|
336 { |
|
337 throw new ArgumentException( "Container source file name cannot be empty" ); |
|
338 } |
|
339 // |
|
340 lock ( iContainerCollection ) |
|
341 { |
|
342 iContainerCollection.Add( aContainer ); |
|
343 } |
|
344 // |
|
345 if ( CrashObservers != null ) |
|
346 { |
|
347 CrashObservers( TCrashEvent.EEventCrashAdded, aContainer ); |
|
348 } |
|
349 } |
|
350 |
|
351 internal int GetNextElementId() |
|
352 { |
|
353 return iIdProvider.GetNextId(); |
|
354 } |
|
355 |
|
356 internal void QueueOperation( CIEngineOperation aOperation ) |
|
357 { |
|
358 this.Trace( "[CIEngine] QueueOperation() - aOperation: {0} ({1})", aOperation, aOperation.GetType() ); |
|
359 iOperationManager.Queue( aOperation ); |
|
360 } |
|
361 |
|
362 internal void OnSourceStateChanged( CIEngineSource aSource ) |
|
363 { |
|
364 this.Trace( "[CIEngine] OnSourceStateChanged() - START - aSource: {0}, aSource.IsReady: {1}, aSource.State: {2}", aSource.FileName, aSource.IsReady, aSource.State ); |
|
365 |
|
366 SourceObservers( TSourceEvent.EEventSourceStateChanged, aSource, null ); |
|
367 if ( aSource.IsReady ) |
|
368 { |
|
369 SourceObservers( TSourceEvent.EEventSourceReady, aSource, null ); |
|
370 } |
|
371 |
|
372 this.Trace( "[CIEngine] OnSourceStateChanged() - END - aSource: {0}, aSource.IsReady: {1}, aSource.State: {2}", aSource.FileName, aSource.IsReady, aSource.State ); |
|
373 } |
|
374 |
|
375 internal void OnSourceProgress( CIEngineSource aSource, int aProgress ) |
|
376 { |
|
377 this.Trace( "[CIEngine] OnSourceProgress() - START - aSource: {0}, aSource.IsReady: {1}, aProgress: {2}", aSource.FileName, aSource.IsReady, aProgress ); |
|
378 |
|
379 SourceObservers( TSourceEvent.EEventSourceProgress, aSource, aProgress ); |
|
380 |
|
381 this.Trace( "[CIEngine] OnSourceProgress() - END - aSource: {0}, aSource.IsReady: {1}, aProgress: {2}", aSource.FileName, aSource.IsReady, aProgress ); |
|
382 } |
|
383 |
|
384 internal void OnException( Exception aException ) |
|
385 { |
|
386 this.Trace( "[CIEngine] OnException() - {0} / {1}", aException.Message, aException.StackTrace ); |
|
387 ExceptionHandlers( aException ); |
|
388 } |
|
389 |
|
390 internal void OnContainerRemovedAll() |
|
391 { |
|
392 if ( CrashObservers != null ) |
|
393 { |
|
394 CrashObservers( TCrashEvent.EEventCrashRemovedAll, null ); |
|
395 } |
|
396 } |
|
397 |
|
398 private void Remove( CIContainer aContainer ) |
|
399 { |
|
400 lock ( iContainerCollection ) |
|
401 { |
|
402 if ( iContainerCollection.Contains( aContainer ) ) |
|
403 { |
|
404 iContainerCollection.Remove( aContainer ); |
|
405 if ( CrashObservers != null ) |
|
406 { |
|
407 CrashObservers( TCrashEvent.EEventCrashRemoved, aContainer ); |
|
408 } |
|
409 } |
|
410 } |
|
411 } |
|
412 |
|
413 private void OnStateChanged( TState aEvent ) |
|
414 { |
|
415 this.Trace( "[CIEngine] OnStateChanged() - START - aEvent: {0}", aEvent ); |
|
416 if ( StateChanged != null ) |
|
417 { |
|
418 StateChanged( aEvent ); |
|
419 } |
|
420 this.Trace( "[CIEngine] OnStateChanged() - END - aEvent: {0}", aEvent ); |
|
421 } |
|
422 |
|
423 private void IdentifyCrashesComplete() |
|
424 { |
|
425 this.Trace( "[CIEngine] IdentifyCrashesComplete()" ); |
|
426 OnStateChanged( TState.EStateProcessingComplete ); |
|
427 // |
|
428 ReleaseBlocker(); |
|
429 } |
|
430 |
|
431 private void DestroyBlocker() |
|
432 { |
|
433 if ( iSynchronousBlocker != null ) |
|
434 { |
|
435 iSynchronousBlocker.Close(); |
|
436 iSynchronousBlocker = null; |
|
437 } |
|
438 } |
|
439 |
|
440 private void ReleaseBlocker() |
|
441 { |
|
442 if ( iSynchronousBlocker != null ) |
|
443 { |
|
444 iSynchronousBlocker.Set(); |
|
445 } |
|
446 } |
|
447 |
|
448 private void DestroySourceProcessor() |
|
449 { |
|
450 if ( iSourceProcessor != null ) |
|
451 { |
|
452 iSourceProcessor.EventHandler -= new CIEngineSourceProcessor.ProcessorEventHandler( SourceProcessor_EventHandler ); |
|
453 iSourceProcessor.Dispose(); |
|
454 iSourceProcessor = null; |
|
455 } |
|
456 } |
|
457 |
|
458 private void DestroyIndexProcessor() |
|
459 { |
|
460 if ( iIndexProcessor != null ) |
|
461 { |
|
462 iIndexProcessor.EventHandler -= new CIContainerIndexProcessor.ProcessorEventHandler( IndexProcessor_EventHandler ); |
|
463 iIndexProcessor = null; |
|
464 } |
|
465 } |
|
466 |
|
467 private void DestroyProblemDetectorManager() |
|
468 { |
|
469 if ( iProblemDetectorManager != null ) |
|
470 { |
|
471 iProblemDetectorManager.EventHandler -= new MultiThreadedProcessor<CIProblemDetector>.ProcessorEventHandler( ProblemDetectorManager_EventHandler ); |
|
472 iProblemDetectorManager.Dispose(); |
|
473 } |
|
474 } |
|
475 |
|
476 private void DestroyOperationManager() |
|
477 { |
|
478 if ( iOperationManager != null ) |
|
479 { |
|
480 iOperationManager.StateHandler -= new CIEngineOperationManager.QueueStateHandler( OperationManager_StateHandler ); |
|
481 iOperationManager.Dispose(); |
|
482 } |
|
483 } |
|
484 #endregion |
|
485 |
|
486 #region Internal properties |
|
487 internal ICIEngineUI UI |
|
488 { |
|
489 get { return iUI; } |
|
490 } |
|
491 #endregion |
|
492 |
|
493 #region From System.Object |
|
494 #endregion |
|
495 |
|
496 #region From ITracer |
|
497 public void Trace( string aMessage ) |
|
498 { |
|
499 UI.CITrace( aMessage ); |
|
500 } |
|
501 |
|
502 public void Trace( string aFormat, params object[] aParams ) |
|
503 { |
|
504 UI.CITrace( aFormat, aParams ); |
|
505 } |
|
506 #endregion |
|
507 |
|
508 #region From IEnumerable<CIContainer> |
|
509 public IEnumerator<CIContainer> GetEnumerator() |
|
510 { |
|
511 lock ( iContainerCollection ) |
|
512 { |
|
513 foreach ( CIContainer container in iContainerCollection ) |
|
514 { |
|
515 yield return container; |
|
516 } |
|
517 } |
|
518 } |
|
519 |
|
520 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
|
521 { |
|
522 lock ( iContainerCollection ) |
|
523 { |
|
524 foreach ( CIContainer container in iContainerCollection ) |
|
525 { |
|
526 yield return container; |
|
527 } |
|
528 } |
|
529 } |
|
530 #endregion |
|
531 |
|
532 #region From DisposableObject |
|
533 protected override void CleanupManagedResources() |
|
534 { |
|
535 try |
|
536 { |
|
537 base.CleanupManagedResources(); |
|
538 } |
|
539 finally |
|
540 { |
|
541 DestroyIndexProcessor(); |
|
542 DestroySourceProcessor(); |
|
543 DestroyProblemDetectorManager(); |
|
544 DestroyOperationManager(); |
|
545 DestroyBlocker(); |
|
546 } |
|
547 } |
|
548 #endregion |
|
549 |
|
550 #region Data members |
|
551 private readonly DbgEngine iDebugEngine; |
|
552 private readonly ICIEngineUI iUI; |
|
553 private readonly CIEnginePrimer iPrimer; |
|
554 private readonly CISinkManager iSinkManager; |
|
555 private readonly CFFPluginRegistry iPlugins; |
|
556 private readonly CIEngineSourceCollection iSources; |
|
557 private readonly CIContainerCollection iContainerCollection; |
|
558 private readonly CIEngineOperationManager iOperationManager; |
|
559 private readonly CIProblemDetectorManager iProblemDetectorManager; |
|
560 private readonly CIContainerIndex iContainerIndex; |
|
561 private ManualResetEvent iSynchronousBlocker = null; |
|
562 private CIEngineSourceProcessor iSourceProcessor = null; |
|
563 private CIContainerIndexProcessor iIndexProcessor = null; |
|
564 private CIElementIdProvider iIdProvider = new CIElementIdProvider(); |
|
565 #endregion |
|
566 } |
|
567 } |