Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1008)

Side by Side Diff: content/browser/browser_child_process_host.cc

Issue 9150017: Add a Content API around BrowserChildProcessHost, similar to what was done with ChildProcessHost.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix?! Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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(&copy); 102 STLDeleteElements(&copy);
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 }
OLDNEW
« no previous file with comments | « content/browser/browser_child_process_host.h ('k') | content/browser/browser_process_sub_thread.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698