OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 namespace NativeClientVSAddIn |
| 6 { |
| 7 using System; |
| 8 using System.Collections.Generic; |
| 9 using System.Windows.Forms; |
| 10 |
| 11 using EnvDTE; |
| 12 using EnvDTE80; |
| 13 |
| 14 /// <summary> |
| 15 /// This is a base class for encapsulating functionality related to attaching
a debugger |
| 16 /// to a nacl/pepper plug-in. This base class mostly contains functionality r
elated to finding |
| 17 /// the plug-in. |
| 18 /// </summary> |
| 19 public class PluginDebuggerBase : IDisposable |
| 20 { |
| 21 /// <summary> |
| 22 /// This is the initial number of milliseconds to wait between |
| 23 /// checking for plug-in processes to attach the debugger to. |
| 24 /// </summary> |
| 25 private const int InitialPluginCheckFrequency = 1000; |
| 26 |
| 27 /// <summary> |
| 28 /// After a plug-in has been found, we slow the frequency of checking |
| 29 /// for new ones. This value is in milliseconds. |
| 30 /// </summary> |
| 31 private const int RelaxedPluginCheckFrequency = 5000; |
| 32 |
| 33 /// <summary> |
| 34 /// Timer object that periodically calls a function to look for the plug-in
process to debug. |
| 35 /// </summary> |
| 36 private Timer pluginFinderTimer_; |
| 37 |
| 38 /// <summary> |
| 39 /// List of process IDs which we should not attempt to attach the debugger t
o. Mainly this |
| 40 /// list contains process IDs of processes we have already attached to. |
| 41 /// </summary> |
| 42 private List<uint> pluginFinderForbiddenPids_; |
| 43 |
| 44 /// <summary> |
| 45 /// Process searcher class which allows us to query the system for running p
rocesses. |
| 46 /// </summary> |
| 47 private ProcessSearcher processSearcher_; |
| 48 |
| 49 /// <summary> |
| 50 /// The main process of chrome that was started by Visual Studio during debu
gging. |
| 51 /// </summary> |
| 52 private System.Diagnostics.Process debuggedChromeMainProcess_; |
| 53 |
| 54 /// <summary> |
| 55 /// Constructs the PluginDebuggerHelper. |
| 56 /// </summary> |
| 57 /// <param name="dte">Automation object from Visual Studio.</param> |
| 58 /// <param name="properties">PropertyManager set to a valid project/platform
.</param> |
| 59 protected PluginDebuggerBase(DTE2 dte, PropertyManager properties) |
| 60 { |
| 61 if (dte == null) |
| 62 { |
| 63 throw new ArgumentNullException("dte"); |
| 64 } |
| 65 |
| 66 if (properties == null) |
| 67 { |
| 68 throw new ArgumentNullException("properties"); |
| 69 } |
| 70 |
| 71 Dte = dte; |
| 72 |
| 73 // Every second, check for a new instance of the plug-in to attach to. |
| 74 // Note that although the timer itself runs on a separate thread, the even
t |
| 75 // is fired from the main UI thread during message processing, thus we do
not |
| 76 // need to worry about threading issues. |
| 77 pluginFinderTimer_ = new Timer(); |
| 78 pluginFinderTimer_.Tick += new EventHandler(FindAndAttachToPlugin); |
| 79 pluginFinderForbiddenPids_ = new List<uint>(); |
| 80 processSearcher_ = new ProcessSearcher(); |
| 81 |
| 82 pluginFinderTimer_.Interval = InitialPluginCheckFrequency; |
| 83 pluginFinderTimer_.Start(); |
| 84 } |
| 85 |
| 86 /// <summary> |
| 87 /// Finalizer. Should clean up unmanaged resources. Should not be overriden
in derived classes. |
| 88 /// </summary> |
| 89 ~PluginDebuggerBase() |
| 90 { |
| 91 Dispose(false); |
| 92 } |
| 93 |
| 94 /// <summary> |
| 95 /// An event indicating a target plug-in was found on the system. |
| 96 /// </summary> |
| 97 public event EventHandler<PluginFoundEventArgs> PluginFoundEvent; |
| 98 |
| 99 /// <summary> |
| 100 /// Gets or sets a value indicating whether this object has been disposed of
already. |
| 101 /// </summary> |
| 102 protected bool Disposed { get; set; } |
| 103 |
| 104 /// <summary> |
| 105 /// Gets or sets the main visual studio object. |
| 106 /// </summary> |
| 107 protected DTE2 Dte { get; set; } |
| 108 |
| 109 /// <summary> |
| 110 /// Disposes the object when called by user code (not directly by garbage co
llector). |
| 111 /// </summary> |
| 112 public void Dispose() |
| 113 { |
| 114 Dispose(true); |
| 115 GC.SuppressFinalize(this); |
| 116 } |
| 117 |
| 118 /// <summary> |
| 119 /// This is called periodically by the Visual Studio UI thread to look for o
ur plug-in process |
| 120 /// and attach the debugger to it. The call is triggered by the pluginFinde
rTimer_ object. |
| 121 /// </summary> |
| 122 /// <param name="unused">The parameter is not used.</param> |
| 123 /// <param name="unused1">The parameter is not used.</param> |
| 124 public void FindAndAttachToPlugin(object unused, EventArgs unused1) |
| 125 { |
| 126 // This function is called by the main Visual Studio event loop and we may
have put the event |
| 127 // on the queue just before disposing it meaning this could be called afte
r we've disposed. |
| 128 if (Disposed) |
| 129 { |
| 130 return; |
| 131 } |
| 132 |
| 133 StringComparison ignoreCase = StringComparison.InvariantCultureIgnoreCase; |
| 134 |
| 135 // Set the main chrome process that was started by visual studio. If it's
not chrome |
| 136 // or not found then we have no business attaching to any plug-ins so retu
rn. |
| 137 if (debuggedChromeMainProcess_ == null) |
| 138 { |
| 139 foreach (Process proc in Dte.Debugger.DebuggedProcesses) |
| 140 { |
| 141 if (proc.Name.EndsWith(Strings.ChromeProcessName, ignoreCase)) |
| 142 { |
| 143 debuggedChromeMainProcess_ = System.Diagnostics.Process.GetProcessBy
Id(proc.ProcessID); |
| 144 break; |
| 145 } |
| 146 } |
| 147 |
| 148 return; |
| 149 } |
| 150 |
| 151 // Get the list of all descendants of the main chrome process. |
| 152 uint mainChromeProcId = (uint)debuggedChromeMainProcess_.Id; |
| 153 List<ProcessInfo> chromeDescendants = processSearcher_.GetDescendants(main
ChromeProcId); |
| 154 string mainChromeFlags = chromeDescendants.Find(p => p.ID == mainChromePro
cId).CommandLine; |
| 155 |
| 156 // From the list of descendants, find the plug-in by it's command line arg
uments and |
| 157 // process name as well as not being attached to already. |
| 158 List<ProcessInfo> plugins = chromeDescendants.FindAll(p => |
| 159 IsPluginProcess(p, mainChromeFlags) && !pluginFinderForbiddenPids_.Con
tains(p.ID)); |
| 160 |
| 161 // Attach to all plug-ins that we found. |
| 162 foreach (ProcessInfo process in plugins) |
| 163 { |
| 164 // If we are attaching to a plug-in, add it to the forbidden list to ens
ure we |
| 165 // don't try to attach again later. |
| 166 pluginFinderForbiddenPids_.Add(process.ID); |
| 167 PluginFoundEvent.Invoke(this, new PluginFoundEventArgs(process.ID)); |
| 168 |
| 169 // Slow down the frequency of checks for new plugins. |
| 170 pluginFinderTimer_.Interval = RelaxedPluginCheckFrequency; |
| 171 } |
| 172 } |
| 173 |
| 174 /// <summary> |
| 175 /// Disposes the object. If disposing is false then this has been called by
garbage collection, |
| 176 /// and we shouldn't reference managed objects. |
| 177 /// </summary> |
| 178 /// <param name="disposing">True if user call to Dispose, false if garbase c
ollection.</param> |
| 179 protected virtual void Dispose(bool disposing) |
| 180 { |
| 181 if (!Disposed && disposing) |
| 182 { |
| 183 pluginFinderTimer_.Stop(); |
| 184 } |
| 185 |
| 186 Disposed = true; |
| 187 } |
| 188 |
| 189 /// <summary> |
| 190 /// Called to check if a process is a valid plugin to attach to. |
| 191 /// </summary> |
| 192 /// <param name="proc">Contains information about the process in question.</
param> |
| 193 /// <param name="mainChromeFlags">Flags on the main Chrome process.</param> |
| 194 /// <returns>True if we should attach to the process.</returns> |
| 195 protected virtual bool IsPluginProcess(ProcessInfo proc, string mainChromeFl
ags) |
| 196 { |
| 197 throw new InvalidOperationException(); |
| 198 } |
| 199 |
| 200 /// <summary> |
| 201 /// The event arguments when a plug-in is found. |
| 202 /// </summary> |
| 203 public class PluginFoundEventArgs : EventArgs |
| 204 { |
| 205 /// <summary> |
| 206 /// Construct the PluginFoundEventArgs. |
| 207 /// </summary> |
| 208 /// <param name="pid">Process ID of the found plug-in.</param> |
| 209 public PluginFoundEventArgs(uint pid) |
| 210 { |
| 211 this.ProcessID = pid; |
| 212 } |
| 213 |
| 214 /// <summary> |
| 215 /// Gets or sets process ID of the found plug-in. |
| 216 /// </summary> |
| 217 public uint ProcessID { get; set; } |
| 218 } |
| 219 } |
| 220 } |
OLD | NEW |