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_impl.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" |
(...skipping 19 matching lines...) Expand all Loading... |
35 #endif | 35 #endif |
36 | 36 |
37 using content::BrowserChildProcessHostDelegate; | 37 using content::BrowserChildProcessHostDelegate; |
38 using content::BrowserThread; | 38 using content::BrowserThread; |
39 using content::ChildProcessData; | 39 using content::ChildProcessData; |
40 using content::ChildProcessHost; | 40 using content::ChildProcessHost; |
41 using content::ChildProcessHostImpl; | 41 using content::ChildProcessHostImpl; |
42 | 42 |
43 namespace { | 43 namespace { |
44 | 44 |
45 static base::LazyInstance<BrowserChildProcessHost::BrowserChildProcessList> | 45 static base::LazyInstance<BrowserChildProcessHostImpl::BrowserChildProcessList> |
46 g_child_process_list = LAZY_INSTANCE_INITIALIZER; | 46 g_child_process_list = LAZY_INSTANCE_INITIALIZER; |
47 | 47 |
48 // Helper functions since the child process related notifications happen on the | 48 // Helper functions since the child process related notifications happen on the |
49 // UI thread. | 49 // UI thread. |
50 void ChildNotificationHelper(int notification_type, | 50 void ChildNotificationHelper(int notification_type, |
51 const ChildProcessData& data) { | 51 const ChildProcessData& data) { |
52 content::NotificationService::current()-> | 52 content::NotificationService::current()-> |
53 Notify(notification_type, content::NotificationService::AllSources(), | 53 Notify(notification_type, content::NotificationService::AllSources(), |
54 content::Details<const ChildProcessData>(&data)); | 54 content::Details<const ChildProcessData>(&data)); |
55 } | 55 } |
56 | 56 |
57 } // namespace | 57 } // namespace |
58 | 58 |
59 namespace content { | 59 namespace content { |
60 | 60 |
61 BrowserChildProcessHost* BrowserChildProcessHost::Create( | 61 BrowserChildProcessHost* BrowserChildProcessHost::Create( |
62 ProcessType type, | 62 ProcessType type, |
63 BrowserChildProcessHostDelegate* delegate) { | 63 BrowserChildProcessHostDelegate* delegate) { |
64 return new ::BrowserChildProcessHost(type, delegate); | 64 return new BrowserChildProcessHostImpl(type, delegate); |
65 } | 65 } |
66 | 66 |
67 } // namespace content | 67 } // namespace content |
68 | 68 |
69 BrowserChildProcessHost::BrowserChildProcessList* | 69 BrowserChildProcessHostImpl::BrowserChildProcessList* |
70 BrowserChildProcessHost::GetIterator() { | 70 BrowserChildProcessHostImpl::GetIterator() { |
71 return g_child_process_list.Pointer(); | 71 return g_child_process_list.Pointer(); |
72 } | 72 } |
73 | 73 |
74 BrowserChildProcessHost::BrowserChildProcessHost( | 74 BrowserChildProcessHostImpl::BrowserChildProcessHostImpl( |
75 content::ProcessType type, | 75 content::ProcessType type, |
76 BrowserChildProcessHostDelegate* delegate) | 76 BrowserChildProcessHostDelegate* delegate) |
77 : data_(type), | 77 : data_(type), |
78 delegate_(delegate), | 78 delegate_(delegate), |
79 #if !defined(OS_WIN) | 79 #if !defined(OS_WIN) |
80 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), | 80 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), |
81 #endif | 81 #endif |
82 disconnect_was_alive_(false) { | 82 disconnect_was_alive_(false) { |
83 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); | 83 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); |
84 | 84 |
85 child_process_host_.reset(ChildProcessHost::Create(this)); | 85 child_process_host_.reset(ChildProcessHost::Create(this)); |
86 child_process_host_->AddFilter(new TraceMessageFilter); | 86 child_process_host_->AddFilter(new TraceMessageFilter); |
87 child_process_host_->AddFilter(new ProfilerMessageFilter); | 87 child_process_host_->AddFilter(new ProfilerMessageFilter); |
88 | 88 |
89 g_child_process_list.Get().push_back(this); | 89 g_child_process_list.Get().push_back(this); |
90 } | 90 } |
91 | 91 |
92 BrowserChildProcessHost::~BrowserChildProcessHost() { | 92 BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() { |
93 g_child_process_list.Get().remove(this); | 93 g_child_process_list.Get().remove(this); |
94 } | 94 } |
95 | 95 |
96 // static | 96 // static |
97 void BrowserChildProcessHost::TerminateAll() { | 97 void BrowserChildProcessHostImpl::TerminateAll() { |
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
99 // Make a copy since the BrowserChildProcessHost dtor mutates the original | 99 // Make a copy since the BrowserChildProcessHost dtor mutates the original |
100 // list. | 100 // list. |
101 BrowserChildProcessList copy = g_child_process_list.Get(); | 101 BrowserChildProcessList copy = g_child_process_list.Get(); |
102 STLDeleteElements(©); | 102 STLDeleteElements(©); |
103 } | 103 } |
104 | 104 |
105 void BrowserChildProcessHost::Launch( | 105 void BrowserChildProcessHostImpl::Launch( |
106 #if defined(OS_WIN) | 106 #if defined(OS_WIN) |
107 const FilePath& exposed_dir, | 107 const FilePath& exposed_dir, |
108 #elif defined(OS_POSIX) | 108 #elif defined(OS_POSIX) |
109 bool use_zygote, | 109 bool use_zygote, |
110 const base::environment_vector& environ, | 110 const base::environment_vector& environ, |
111 #endif | 111 #endif |
112 CommandLine* cmd_line) { | 112 CommandLine* cmd_line) { |
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
114 | 114 |
115 content::GetContentClient()->browser()->AppendExtraCommandLineSwitches( | 115 content::GetContentClient()->browser()->AppendExtraCommandLineSwitches( |
116 cmd_line, data_.id); | 116 cmd_line, data_.id); |
117 | 117 |
118 child_process_.reset(new ChildProcessLauncher( | 118 child_process_.reset(new ChildProcessLauncher( |
119 #if defined(OS_WIN) | 119 #if defined(OS_WIN) |
120 exposed_dir, | 120 exposed_dir, |
121 #elif defined(OS_POSIX) | 121 #elif defined(OS_POSIX) |
122 use_zygote, | 122 use_zygote, |
123 environ, | 123 environ, |
124 child_process_host_->TakeClientFileDescriptor(), | 124 child_process_host_->TakeClientFileDescriptor(), |
125 #endif | 125 #endif |
126 cmd_line, | 126 cmd_line, |
127 this)); | 127 this)); |
128 } | 128 } |
129 | 129 |
130 const ChildProcessData& BrowserChildProcessHost::GetData() const { | 130 const ChildProcessData& BrowserChildProcessHostImpl::GetData() const { |
131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
132 return data_; | 132 return data_; |
133 } | 133 } |
134 | 134 |
135 ChildProcessHost* BrowserChildProcessHost::GetHost() const { | 135 ChildProcessHost* BrowserChildProcessHostImpl::GetHost() const { |
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
137 return child_process_host_.get(); | 137 return child_process_host_.get(); |
138 } | 138 } |
139 | 139 |
140 base::ProcessHandle BrowserChildProcessHost::GetHandle() const { | 140 base::ProcessHandle BrowserChildProcessHostImpl::GetHandle() const { |
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
142 DCHECK(child_process_.get()) | 142 DCHECK(child_process_.get()) |
143 << "Requesting a child process handle before launching."; | 143 << "Requesting a child process handle before launching."; |
144 DCHECK(child_process_->GetHandle()) | 144 DCHECK(child_process_->GetHandle()) |
145 << "Requesting a child process handle before launch has completed OK."; | 145 << "Requesting a child process handle before launch has completed OK."; |
146 return child_process_->GetHandle(); | 146 return child_process_->GetHandle(); |
147 } | 147 } |
148 | 148 |
149 void BrowserChildProcessHost::SetName(const string16& name) { | 149 void BrowserChildProcessHostImpl::SetName(const string16& name) { |
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
151 data_.name = name; | 151 data_.name = name; |
152 } | 152 } |
153 | 153 |
154 void BrowserChildProcessHost::SetHandle(base::ProcessHandle handle) { | 154 void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) { |
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
156 data_.handle = handle; | 156 data_.handle = handle; |
157 } | 157 } |
158 | 158 |
159 void BrowserChildProcessHost::ForceShutdown() { | 159 void BrowserChildProcessHostImpl::ForceShutdown() { |
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
161 g_child_process_list.Get().remove(this); | 161 g_child_process_list.Get().remove(this); |
162 child_process_host_->ForceShutdown(); | 162 child_process_host_->ForceShutdown(); |
163 } | 163 } |
164 | 164 |
165 void BrowserChildProcessHost::SetTerminateChildOnShutdown( | 165 void BrowserChildProcessHostImpl::SetTerminateChildOnShutdown( |
166 bool terminate_on_shutdown) { | 166 bool terminate_on_shutdown) { |
167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
168 child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown); | 168 child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown); |
169 } | 169 } |
170 | 170 |
171 void BrowserChildProcessHost::Notify(int type) { | 171 void BrowserChildProcessHostImpl::Notify(int type) { |
172 BrowserThread::PostTask( | 172 BrowserThread::PostTask( |
173 BrowserThread::UI, | 173 BrowserThread::UI, |
174 FROM_HERE, | 174 FROM_HERE, |
175 base::Bind(&ChildNotificationHelper, type, data_)); | 175 base::Bind(&ChildNotificationHelper, type, data_)); |
176 } | 176 } |
177 | 177 |
178 base::TerminationStatus BrowserChildProcessHost::GetTerminationStatus( | 178 base::TerminationStatus BrowserChildProcessHostImpl::GetTerminationStatus( |
179 int* exit_code) { | 179 int* exit_code) { |
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
181 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. |
182 return base::GetTerminationStatus(data_.handle, exit_code); | 182 return base::GetTerminationStatus(data_.handle, exit_code); |
183 return child_process_->GetChildTerminationStatus(exit_code); | 183 return child_process_->GetChildTerminationStatus(exit_code); |
184 } | 184 } |
185 | 185 |
186 bool BrowserChildProcessHost::OnMessageReceived(const IPC::Message& message) { | 186 bool BrowserChildProcessHostImpl::OnMessageReceived( |
| 187 const IPC::Message& message) { |
187 return delegate_->OnMessageReceived(message); | 188 return delegate_->OnMessageReceived(message); |
188 } | 189 } |
189 | 190 |
190 void BrowserChildProcessHost::OnChannelConnected(int32 peer_pid) { | 191 void BrowserChildProcessHostImpl::OnChannelConnected(int32 peer_pid) { |
191 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED); | 192 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED); |
192 delegate_->OnChannelConnected(peer_pid); | 193 delegate_->OnChannelConnected(peer_pid); |
193 } | 194 } |
194 | 195 |
195 void BrowserChildProcessHost::OnChannelError() { | 196 void BrowserChildProcessHostImpl::OnChannelError() { |
196 delegate_->OnChannelError(); | 197 delegate_->OnChannelError(); |
197 } | 198 } |
198 | 199 |
199 bool BrowserChildProcessHost::CanShutdown() { | 200 bool BrowserChildProcessHostImpl::CanShutdown() { |
200 return delegate_->CanShutdown(); | 201 return delegate_->CanShutdown(); |
201 } | 202 } |
202 | 203 |
203 // Normally a ChildProcessHostDelegate deletes itself from this callback, but at | 204 // 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 // 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 // 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 // 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 // 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 // may be called twice: once from the actual channel error and once from |
209 // OnWaitableEventSignaled() or the delayed task. | 210 // OnWaitableEventSignaled() or the delayed task. |
210 void BrowserChildProcessHost::OnChildDisconnected() { | 211 void BrowserChildProcessHostImpl::OnChildDisconnected() { |
211 DCHECK(data_.handle != base::kNullProcessHandle); | 212 DCHECK(data_.handle != base::kNullProcessHandle); |
212 int exit_code; | 213 int exit_code; |
213 base::TerminationStatus status = GetTerminationStatus(&exit_code); | 214 base::TerminationStatus status = GetTerminationStatus(&exit_code); |
214 switch (status) { | 215 switch (status) { |
215 case base::TERMINATION_STATUS_PROCESS_CRASHED: | 216 case base::TERMINATION_STATUS_PROCESS_CRASHED: |
216 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: { | 217 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: { |
217 delegate_->OnProcessCrashed(exit_code); | 218 delegate_->OnProcessCrashed(exit_code); |
218 // Report that this child process crashed. | 219 // Report that this child process crashed. |
219 Notify(content::NOTIFICATION_CHILD_PROCESS_CRASHED); | 220 Notify(content::NOTIFICATION_CHILD_PROCESS_CRASHED); |
220 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed", | 221 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed", |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 child_watcher_.StartWatching( | 254 child_watcher_.StartWatching( |
254 new base::WaitableEvent(data_.handle), this); | 255 new base::WaitableEvent(data_.handle), this); |
255 #else | 256 #else |
256 // On non-Windows platforms, give the child process some time to die after | 257 // 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 // 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 // become available. This is best effort -- if the process doesn't die |
259 // within the time limit, this object gets destroyed. | 260 // within the time limit, this object gets destroyed. |
260 const int kExitCodeWaitMs = 250; | 261 const int kExitCodeWaitMs = 250; |
261 MessageLoop::current()->PostDelayedTask( | 262 MessageLoop::current()->PostDelayedTask( |
262 FROM_HERE, | 263 FROM_HERE, |
263 base::Bind(&BrowserChildProcessHost::OnChildDisconnected, | 264 base::Bind(&BrowserChildProcessHostImpl::OnChildDisconnected, |
264 task_factory_.GetWeakPtr()), | 265 task_factory_.GetWeakPtr()), |
265 kExitCodeWaitMs); | 266 kExitCodeWaitMs); |
266 #endif | 267 #endif |
267 return; | 268 return; |
268 } | 269 } |
269 | 270 |
270 default: | 271 default: |
271 break; | 272 break; |
272 } | 273 } |
273 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected", | 274 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected", |
274 data_.type, | 275 data_.type, |
275 content::PROCESS_TYPE_MAX); | 276 content::PROCESS_TYPE_MAX); |
276 // Notify in the main loop of the disconnection. | 277 // Notify in the main loop of the disconnection. |
277 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED); | 278 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED); |
278 delete delegate_; // Will delete us | 279 delete delegate_; // Will delete us |
279 } | 280 } |
280 | 281 |
281 // The child process handle has been signaled so the exit code is finally | 282 // 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 // 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 // which case we should not call OnChildDisconnected() or else we will be |
284 // waiting forever. | 285 // waiting forever. |
285 void BrowserChildProcessHost::OnWaitableEventSignaled( | 286 void BrowserChildProcessHostImpl::OnWaitableEventSignaled( |
286 base::WaitableEvent* waitable_event) { | 287 base::WaitableEvent* waitable_event) { |
287 #if defined (OS_WIN) | 288 #if defined (OS_WIN) |
288 unsigned long exit_code = 0; | 289 unsigned long exit_code = 0; |
289 GetExitCodeProcess(waitable_event->Release(), &exit_code); | 290 GetExitCodeProcess(waitable_event->Release(), &exit_code); |
290 delete waitable_event; | 291 delete waitable_event; |
291 if (exit_code == STILL_ACTIVE) { | 292 if (exit_code == STILL_ACTIVE) { |
292 delete delegate_; // Will delete us | 293 delete delegate_; // Will delete us |
293 } else { | 294 } else { |
294 BrowserChildProcessHost::OnChildDisconnected(); | 295 BrowserChildProcessHostImpl::OnChildDisconnected(); |
295 } | 296 } |
296 #endif | 297 #endif |
297 } | 298 } |
298 | 299 |
299 bool BrowserChildProcessHost::Send(IPC::Message* message) { | 300 bool BrowserChildProcessHostImpl::Send(IPC::Message* message) { |
300 return child_process_host_->Send(message); | 301 return child_process_host_->Send(message); |
301 } | 302 } |
302 | 303 |
303 void BrowserChildProcessHost::ShutdownStarted() { | 304 void BrowserChildProcessHostImpl::ShutdownStarted() { |
304 // Must remove the process from the list now, in case it gets used for a | 305 // 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 // new instance before our watcher tells us that the process terminated. |
306 g_child_process_list.Get().remove(this); | 307 g_child_process_list.Get().remove(this); |
307 } | 308 } |
308 | 309 |
309 | 310 |
310 void BrowserChildProcessHost::OnProcessLaunched() { | 311 void BrowserChildProcessHostImpl::OnProcessLaunched() { |
311 if (!child_process_->GetHandle()) { | 312 if (!child_process_->GetHandle()) { |
312 delete delegate_; // Will delete us | 313 delete delegate_; // Will delete us |
313 return; | 314 return; |
314 } | 315 } |
315 data_.handle = child_process_->GetHandle(); | 316 data_.handle = child_process_->GetHandle(); |
316 delegate_->OnProcessLaunched(); | 317 delegate_->OnProcessLaunched(); |
317 } | 318 } |
OLD | NEW |