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

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

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

Powered by Google App Engine
This is Rietveld 408576698