OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/browser_child_process_host.h" | 5 #include "content/browser/browser_child_process_host.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
13 #include "base/path_service.h" | 13 #include "base/path_service.h" |
14 #include "base/process_util.h" | 14 #include "base/process_util.h" |
15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
17 #include "content/browser/profiler_message_filter.h" | 17 #include "content/browser/profiler_message_filter.h" |
18 #include "content/browser/renderer_host/resource_message_filter.h" | 18 #include "content/browser/renderer_host/resource_message_filter.h" |
19 #include "content/browser/trace_message_filter.h" | 19 #include "content/browser/trace_message_filter.h" |
20 #include "content/common/child_process_host_impl.h" | 20 #include "content/common/child_process_host_impl.h" |
21 #include "content/common/plugin_messages.h" | 21 #include "content/common/plugin_messages.h" |
22 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
| 23 #include "content/public/browser/browser_child_process_host_delegate.h" |
23 #include "content/public/browser/child_process_data.h" | 24 #include "content/public/browser/child_process_data.h" |
24 #include "content/public/browser/content_browser_client.h" | 25 #include "content/public/browser/content_browser_client.h" |
25 #include "content/public/browser/notification_service.h" | 26 #include "content/public/browser/notification_service.h" |
26 #include "content/public/browser/notification_types.h" | 27 #include "content/public/browser/notification_types.h" |
27 #include "content/public/common/content_switches.h" | 28 #include "content/public/common/content_switches.h" |
28 #include "content/public/common/result_codes.h" | 29 #include "content/public/common/result_codes.h" |
29 | 30 |
30 #if defined(OS_WIN) | 31 #if defined(OS_WIN) |
31 #include "base/synchronization/waitable_event.h" | 32 #include "base/synchronization/waitable_event.h" |
32 #else | 33 #else |
33 #include "base/bind.h" | 34 #include "base/bind.h" |
34 #endif | 35 #endif |
35 | 36 |
| 37 using content::BrowserChildProcessHostDelegate; |
36 using content::BrowserThread; | 38 using content::BrowserThread; |
| 39 using content::ChildProcessData; |
37 using content::ChildProcessHost; | 40 using content::ChildProcessHost; |
38 using content::ChildProcessHostImpl; | 41 using content::ChildProcessHostImpl; |
39 | 42 |
40 namespace { | 43 namespace { |
41 | 44 |
42 typedef std::list<BrowserChildProcessHost*> BrowserChildProcessList; | 45 static base::LazyInstance<BrowserChildProcessHost::BrowserChildProcessList> |
43 static base::LazyInstance<BrowserChildProcessList> g_child_process_list = | 46 g_child_process_list = LAZY_INSTANCE_INITIALIZER; |
44 LAZY_INSTANCE_INITIALIZER; | |
45 | 47 |
46 // Helper functions since the child process related notifications happen on the | 48 // Helper functions since the child process related notifications happen on the |
47 // UI thread. | 49 // UI thread. |
48 void ChildNotificationHelper(int notification_type, | 50 void ChildNotificationHelper(int notification_type, |
49 const content::ChildProcessData& data) { | 51 const ChildProcessData& data) { |
50 content::NotificationService::current()-> | 52 content::NotificationService::current()-> |
51 Notify(notification_type, content::NotificationService::AllSources(), | 53 Notify(notification_type, content::NotificationService::AllSources(), |
52 content::Details<const content::ChildProcessData>(&data)); | 54 content::Details<const ChildProcessData>(&data)); |
53 } | 55 } |
54 | 56 |
55 } // namespace | 57 } // namespace |
56 | 58 |
| 59 namespace content { |
| 60 |
| 61 BrowserChildProcessHost* BrowserChildProcessHost::Create( |
| 62 ProcessType type, |
| 63 BrowserChildProcessHostDelegate* delegate) { |
| 64 return new ::BrowserChildProcessHost(type, delegate); |
| 65 } |
| 66 |
| 67 } // namespace content |
| 68 |
| 69 BrowserChildProcessHost::BrowserChildProcessList* |
| 70 BrowserChildProcessHost::GetIterator() { |
| 71 return g_child_process_list.Pointer(); |
| 72 } |
| 73 |
57 BrowserChildProcessHost::BrowserChildProcessHost( | 74 BrowserChildProcessHost::BrowserChildProcessHost( |
58 content::ProcessType type) | 75 content::ProcessType type, |
| 76 BrowserChildProcessHostDelegate* delegate) |
59 : data_(type), | 77 : data_(type), |
60 ALLOW_THIS_IN_INITIALIZER_LIST(client_(this)), | 78 delegate_(delegate), |
61 #if !defined(OS_WIN) | 79 #if !defined(OS_WIN) |
62 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), | 80 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), |
63 #endif | 81 #endif |
64 disconnect_was_alive_(false) { | 82 disconnect_was_alive_(false) { |
65 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); | 83 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); |
66 | 84 |
67 child_process_host_.reset(ChildProcessHost::Create(this)); | 85 child_process_host_.reset(ChildProcessHost::Create(this)); |
68 child_process_host_->AddFilter(new TraceMessageFilter); | 86 child_process_host_->AddFilter(new TraceMessageFilter); |
69 child_process_host_->AddFilter(new ProfilerMessageFilter); | 87 child_process_host_->AddFilter(new ProfilerMessageFilter); |
70 | 88 |
71 g_child_process_list.Get().push_back(this); | 89 g_child_process_list.Get().push_back(this); |
72 } | 90 } |
73 | 91 |
74 BrowserChildProcessHost::~BrowserChildProcessHost() { | 92 BrowserChildProcessHost::~BrowserChildProcessHost() { |
75 g_child_process_list.Get().remove(this); | 93 g_child_process_list.Get().remove(this); |
76 } | 94 } |
77 | 95 |
78 // static | 96 // static |
79 void BrowserChildProcessHost::TerminateAll() { | 97 void BrowserChildProcessHost::TerminateAll() { |
| 98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
80 // Make a copy since the BrowserChildProcessHost dtor mutates the original | 99 // Make a copy since the BrowserChildProcessHost dtor mutates the original |
81 // list. | 100 // list. |
82 BrowserChildProcessList copy = g_child_process_list.Get(); | 101 BrowserChildProcessList copy = g_child_process_list.Get(); |
83 STLDeleteElements(©); | 102 STLDeleteElements(©); |
84 } | 103 } |
85 | 104 |
86 void BrowserChildProcessHost::Launch( | 105 void BrowserChildProcessHost::Launch( |
87 #if defined(OS_WIN) | 106 #if defined(OS_WIN) |
88 const FilePath& exposed_dir, | 107 const FilePath& exposed_dir, |
89 #elif defined(OS_POSIX) | 108 #elif defined(OS_POSIX) |
90 bool use_zygote, | 109 bool use_zygote, |
91 const base::environment_vector& environ, | 110 const base::environment_vector& environ, |
92 #endif | 111 #endif |
93 CommandLine* cmd_line) { | 112 CommandLine* cmd_line) { |
| 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
94 | 114 |
95 content::GetContentClient()->browser()->AppendExtraCommandLineSwitches( | 115 content::GetContentClient()->browser()->AppendExtraCommandLineSwitches( |
96 cmd_line, data().id); | 116 cmd_line, data_.id); |
97 | 117 |
98 child_process_.reset(new ChildProcessLauncher( | 118 child_process_.reset(new ChildProcessLauncher( |
99 #if defined(OS_WIN) | 119 #if defined(OS_WIN) |
100 exposed_dir, | 120 exposed_dir, |
101 #elif defined(OS_POSIX) | 121 #elif defined(OS_POSIX) |
102 use_zygote, | 122 use_zygote, |
103 environ, | 123 environ, |
104 child_process_host()->TakeClientFileDescriptor(), | 124 child_process_host_->TakeClientFileDescriptor(), |
105 #endif | 125 #endif |
106 cmd_line, | 126 cmd_line, |
107 &client_)); | 127 this)); |
108 } | 128 } |
109 | 129 |
110 base::ProcessHandle BrowserChildProcessHost::GetChildProcessHandle() const { | 130 const ChildProcessData& BrowserChildProcessHost::GetData() const { |
| 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 132 return data_; |
| 133 } |
| 134 |
| 135 ChildProcessHost* BrowserChildProcessHost::GetHost() const { |
| 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 137 return child_process_host_.get(); |
| 138 } |
| 139 |
| 140 base::ProcessHandle BrowserChildProcessHost::GetHandle() const { |
| 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
111 DCHECK(child_process_.get()) | 142 DCHECK(child_process_.get()) |
112 << "Requesting a child process handle before launching."; | 143 << "Requesting a child process handle before launching."; |
113 DCHECK(child_process_->GetHandle()) | 144 DCHECK(child_process_->GetHandle()) |
114 << "Requesting a child process handle before launch has completed OK."; | 145 << "Requesting a child process handle before launch has completed OK."; |
115 return child_process_->GetHandle(); | 146 return child_process_->GetHandle(); |
116 } | 147 } |
117 | 148 |
118 void BrowserChildProcessHost::SetName(const string16& name) { | 149 void BrowserChildProcessHost::SetName(const string16& name) { |
| 150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
119 data_.name = name; | 151 data_.name = name; |
120 } | 152 } |
121 | 153 |
122 void BrowserChildProcessHost::SetHandle(base::ProcessHandle handle) { | 154 void BrowserChildProcessHost::SetHandle(base::ProcessHandle handle) { |
| 155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
123 data_.handle = handle; | 156 data_.handle = handle; |
124 } | 157 } |
125 | 158 |
126 void BrowserChildProcessHost::ForceShutdown() { | 159 void BrowserChildProcessHost::ForceShutdown() { |
| 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
127 g_child_process_list.Get().remove(this); | 161 g_child_process_list.Get().remove(this); |
128 child_process_host_->ForceShutdown(); | 162 child_process_host_->ForceShutdown(); |
129 } | 163 } |
130 | 164 |
131 void BrowserChildProcessHost::SetTerminateChildOnShutdown( | 165 void BrowserChildProcessHost::SetTerminateChildOnShutdown( |
132 bool terminate_on_shutdown) { | 166 bool terminate_on_shutdown) { |
| 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
133 child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown); | 168 child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown); |
134 } | 169 } |
135 | 170 |
136 void BrowserChildProcessHost::Notify(int type) { | 171 void BrowserChildProcessHost::Notify(int type) { |
137 BrowserThread::PostTask( | 172 BrowserThread::PostTask( |
138 BrowserThread::UI, | 173 BrowserThread::UI, |
139 FROM_HERE, | 174 FROM_HERE, |
140 base::Bind(&ChildNotificationHelper, type, data_)); | 175 base::Bind(&ChildNotificationHelper, type, data_)); |
141 } | 176 } |
142 | 177 |
143 base::TerminationStatus BrowserChildProcessHost::GetChildTerminationStatus( | 178 base::TerminationStatus BrowserChildProcessHost::GetTerminationStatus( |
144 int* exit_code) { | 179 int* exit_code) { |
| 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
145 if (!child_process_.get()) // If the delegate doesn't use Launch() helper. | 181 if (!child_process_.get()) // If the delegate doesn't use Launch() helper. |
146 return base::GetTerminationStatus(data().handle, exit_code); | 182 return base::GetTerminationStatus(data_.handle, exit_code); |
147 return child_process_->GetChildTerminationStatus(exit_code); | 183 return child_process_->GetChildTerminationStatus(exit_code); |
148 } | 184 } |
149 | 185 |
150 bool BrowserChildProcessHost::OnMessageReceived(const IPC::Message& message) { | 186 bool BrowserChildProcessHost::OnMessageReceived(const IPC::Message& message) { |
151 return false; | 187 return delegate_->OnMessageReceived(message); |
152 } | 188 } |
153 | 189 |
154 void BrowserChildProcessHost::OnChannelConnected(int32 peer_pid) { | 190 void BrowserChildProcessHost::OnChannelConnected(int32 peer_pid) { |
155 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED); | 191 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED); |
| 192 delegate_->OnChannelConnected(peer_pid); |
| 193 } |
| 194 |
| 195 void BrowserChildProcessHost::OnChannelError() { |
| 196 delegate_->OnChannelError(); |
156 } | 197 } |
157 | 198 |
158 bool BrowserChildProcessHost::CanShutdown() { | 199 bool BrowserChildProcessHost::CanShutdown() { |
159 return true; | 200 return delegate_->CanShutdown(); |
160 } | 201 } |
161 | 202 |
162 // Normally a ChildProcessHostDelegate deletes itself from this callback, but at | 203 // Normally a ChildProcessHostDelegate deletes itself from this callback, but at |
163 // this layer and below we need to have the final child process exit code to | 204 // this layer and below we need to have the final child process exit code to |
164 // properly bucket crashes vs kills. On Windows we can do this if we wait until | 205 // properly bucket crashes vs kills. On Windows we can do this if we wait until |
165 // the process handle is signaled; on the rest of the platforms, we schedule a | 206 // the process handle is signaled; on the rest of the platforms, we schedule a |
166 // delayed task to wait for an exit code. However, this means that this method | 207 // delayed task to wait for an exit code. However, this means that this method |
167 // may be called twice: once from the actual channel error and once from | 208 // may be called twice: once from the actual channel error and once from |
168 // OnWaitableEventSignaled() or the delayed task. | 209 // OnWaitableEventSignaled() or the delayed task. |
169 void BrowserChildProcessHost::OnChildDisconnected() { | 210 void BrowserChildProcessHost::OnChildDisconnected() { |
170 DCHECK(data().handle != base::kNullProcessHandle); | 211 DCHECK(data_.handle != base::kNullProcessHandle); |
171 int exit_code; | 212 int exit_code; |
172 base::TerminationStatus status = GetChildTerminationStatus(&exit_code); | 213 base::TerminationStatus status = GetTerminationStatus(&exit_code); |
173 switch (status) { | 214 switch (status) { |
174 case base::TERMINATION_STATUS_PROCESS_CRASHED: | 215 case base::TERMINATION_STATUS_PROCESS_CRASHED: |
175 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: { | 216 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: { |
176 OnProcessCrashed(exit_code); | 217 delegate_->OnProcessCrashed(exit_code); |
177 // Report that this child process crashed. | 218 // Report that this child process crashed. |
178 Notify(content::NOTIFICATION_CHILD_PROCESS_CRASHED); | 219 Notify(content::NOTIFICATION_CHILD_PROCESS_CRASHED); |
179 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed", | 220 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed", |
180 data().type, | 221 data_.type, |
181 content::PROCESS_TYPE_MAX); | 222 content::PROCESS_TYPE_MAX); |
182 if (disconnect_was_alive_) { | 223 if (disconnect_was_alive_) { |
183 UMA_HISTOGRAM_ENUMERATION("ChildProcess.CrashedWasAlive", | 224 UMA_HISTOGRAM_ENUMERATION("ChildProcess.CrashedWasAlive", |
184 data().type, | 225 data_.type, |
185 content::PROCESS_TYPE_MAX); | 226 content::PROCESS_TYPE_MAX); |
186 } | 227 } |
187 break; | 228 break; |
188 } | 229 } |
189 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: { | 230 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: { |
190 // Report that this child process was killed. | 231 // Report that this child process was killed. |
191 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed", | 232 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed", |
192 data().type, | 233 data_.type, |
193 content::PROCESS_TYPE_MAX); | 234 content::PROCESS_TYPE_MAX); |
194 if (disconnect_was_alive_) { | 235 if (disconnect_was_alive_) { |
195 UMA_HISTOGRAM_ENUMERATION("ChildProcess.KilledWasAlive", | 236 UMA_HISTOGRAM_ENUMERATION("ChildProcess.KilledWasAlive", |
196 data().type, | 237 data_.type, |
197 content::PROCESS_TYPE_MAX); | 238 content::PROCESS_TYPE_MAX); |
198 } | 239 } |
199 break; | 240 break; |
200 } | 241 } |
201 case base::TERMINATION_STATUS_STILL_RUNNING: { | 242 case base::TERMINATION_STATUS_STILL_RUNNING: { |
202 // Exit code not yet available. Ensure we don't wait forever for an exit | 243 // Exit code not yet available. Ensure we don't wait forever for an exit |
203 // code. | 244 // code. |
204 if (disconnect_was_alive_) { | 245 if (disconnect_was_alive_) { |
205 UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive", | 246 UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive", |
206 data().type, | 247 data_.type, |
207 content::PROCESS_TYPE_MAX); | 248 content::PROCESS_TYPE_MAX); |
208 break; | 249 break; |
209 } | 250 } |
210 disconnect_was_alive_ = true; | 251 disconnect_was_alive_ = true; |
211 #if defined(OS_WIN) | 252 #if defined(OS_WIN) |
212 child_watcher_.StartWatching( | 253 child_watcher_.StartWatching( |
213 new base::WaitableEvent(data().handle), this); | 254 new base::WaitableEvent(data_.handle), this); |
214 #else | 255 #else |
215 // On non-Windows platforms, give the child process some time to die after | 256 // On non-Windows platforms, give the child process some time to die after |
216 // disconnecting the channel so that the exit code and termination status | 257 // disconnecting the channel so that the exit code and termination status |
217 // become available. This is best effort -- if the process doesn't die | 258 // become available. This is best effort -- if the process doesn't die |
218 // within the time limit, this object gets destroyed. | 259 // within the time limit, this object gets destroyed. |
219 const int kExitCodeWaitMs = 250; | 260 const int kExitCodeWaitMs = 250; |
220 MessageLoop::current()->PostDelayedTask( | 261 MessageLoop::current()->PostDelayedTask( |
221 FROM_HERE, | 262 FROM_HERE, |
222 base::Bind(&BrowserChildProcessHost::OnChildDisconnected, | 263 base::Bind(&BrowserChildProcessHost::OnChildDisconnected, |
223 task_factory_.GetWeakPtr()), | 264 task_factory_.GetWeakPtr()), |
224 kExitCodeWaitMs); | 265 kExitCodeWaitMs); |
225 #endif | 266 #endif |
226 return; | 267 return; |
227 } | 268 } |
228 | 269 |
229 default: | 270 default: |
230 break; | 271 break; |
231 } | 272 } |
232 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected", | 273 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected", |
233 data().type, | 274 data_.type, |
234 content::PROCESS_TYPE_MAX); | 275 content::PROCESS_TYPE_MAX); |
235 // Notify in the main loop of the disconnection. | 276 // Notify in the main loop of the disconnection. |
236 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED); | 277 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED); |
237 delete this; | 278 delete delegate_; // Will delete us |
238 } | 279 } |
239 | 280 |
240 // The child process handle has been signaled so the exit code is finally | 281 // The child process handle has been signaled so the exit code is finally |
241 // available. Unfortunately STILL_ACTIVE (0x103) is a valid exit code in | 282 // available. Unfortunately STILL_ACTIVE (0x103) is a valid exit code in |
242 // which case we should not call OnChildDisconnected() or else we will be | 283 // which case we should not call OnChildDisconnected() or else we will be |
243 // waiting forever. | 284 // waiting forever. |
244 void BrowserChildProcessHost::OnWaitableEventSignaled( | 285 void BrowserChildProcessHost::OnWaitableEventSignaled( |
245 base::WaitableEvent* waitable_event) { | 286 base::WaitableEvent* waitable_event) { |
246 #if defined (OS_WIN) | 287 #if defined (OS_WIN) |
247 unsigned long exit_code = 0; | 288 unsigned long exit_code = 0; |
248 GetExitCodeProcess(waitable_event->Release(), &exit_code); | 289 GetExitCodeProcess(waitable_event->Release(), &exit_code); |
249 delete waitable_event; | 290 delete waitable_event; |
250 if (exit_code == STILL_ACTIVE) { | 291 if (exit_code == STILL_ACTIVE) { |
251 delete this; | 292 delete delegate_; // Will delete us |
252 } else { | 293 } else { |
253 BrowserChildProcessHost::OnChildDisconnected(); | 294 BrowserChildProcessHost::OnChildDisconnected(); |
254 } | 295 } |
255 #endif | 296 #endif |
256 } | 297 } |
257 | 298 |
258 bool BrowserChildProcessHost::Send(IPC::Message* message) { | 299 bool BrowserChildProcessHost::Send(IPC::Message* message) { |
259 return child_process_host_->Send(message); | 300 return child_process_host_->Send(message); |
260 } | 301 } |
261 | 302 |
262 void BrowserChildProcessHost::ShutdownStarted() { | 303 void BrowserChildProcessHost::ShutdownStarted() { |
263 // Must remove the process from the list now, in case it gets used for a | 304 // Must remove the process from the list now, in case it gets used for a |
264 // new instance before our watcher tells us that the process terminated. | 305 // new instance before our watcher tells us that the process terminated. |
265 g_child_process_list.Get().remove(this); | 306 g_child_process_list.Get().remove(this); |
266 } | 307 } |
267 | 308 |
268 BrowserChildProcessHost::ClientHook::ClientHook(BrowserChildProcessHost* host) | |
269 : host_(host) { | |
270 } | |
271 | 309 |
272 void BrowserChildProcessHost::ClientHook::OnProcessLaunched() { | 310 void BrowserChildProcessHost::OnProcessLaunched() { |
273 if (!host_->child_process_->GetHandle()) { | 311 if (!child_process_->GetHandle()) { |
274 delete host_; | 312 delete delegate_; // Will delete us |
275 return; | 313 return; |
276 } | 314 } |
277 host_->data_.handle = host_->child_process_->GetHandle(); | 315 data_.handle = child_process_->GetHandle(); |
278 host_->OnProcessLaunched(); | 316 delegate_->OnProcessLaunched(); |
279 } | 317 } |
280 | |
281 BrowserChildProcessHost::Iterator::Iterator() | |
282 : all_(true), type_(content::PROCESS_TYPE_UNKNOWN) { | |
283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) << | |
284 "BrowserChildProcessHost::Iterator must be used on the IO thread."; | |
285 iterator_ = g_child_process_list.Get().begin(); | |
286 } | |
287 | |
288 BrowserChildProcessHost::Iterator::Iterator(content::ProcessType type) | |
289 : all_(false), type_(type) { | |
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) << | |
291 "BrowserChildProcessHost::Iterator must be used on the IO thread."; | |
292 iterator_ = g_child_process_list.Get().begin(); | |
293 if (!Done() && (*iterator_)->data().type != type_) | |
294 ++(*this); | |
295 } | |
296 | |
297 BrowserChildProcessHost* BrowserChildProcessHost::Iterator::operator++() { | |
298 do { | |
299 ++iterator_; | |
300 if (Done()) | |
301 break; | |
302 | |
303 if (!all_ && (*iterator_)->data().type != type_) | |
304 continue; | |
305 | |
306 return *iterator_; | |
307 } while (true); | |
308 | |
309 return NULL; | |
310 } | |
311 | |
312 bool BrowserChildProcessHost::Iterator::Done() { | |
313 return iterator_ == g_child_process_list.Get().end(); | |
314 } | |
OLD | NEW |