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/common/child_process_host.h" | 5 #include "content/common/child_process_host.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/atomicops.h" | 9 #include "base/atomicops.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/file_path.h" | 11 #include "base/file_path.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
14 #include "base/path_service.h" | 14 #include "base/path_service.h" |
15 #include "base/process_util.h" | 15 #include "base/process_util.h" |
16 #include "base/rand_util.h" | 16 #include "base/rand_util.h" |
17 #include "base/stringprintf.h" | 17 #include "base/stringprintf.h" |
18 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 18 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
19 #include "content/common/child_process_messages.h" | 19 #include "content/common/child_process_messages.h" |
| 20 #include "content/public/common/child_process_host_delegate.h" |
20 #include "content/public/common/content_paths.h" | 21 #include "content/public/common/content_paths.h" |
21 #include "content/public/common/content_switches.h" | 22 #include "content/public/common/content_switches.h" |
22 #include "ipc/ipc_logging.h" | 23 #include "ipc/ipc_logging.h" |
23 | 24 |
24 #if defined(OS_LINUX) | 25 #if defined(OS_LINUX) |
25 #include "base/linux_util.h" | 26 #include "base/linux_util.h" |
26 #elif defined(OS_WIN) | 27 #elif defined(OS_WIN) |
27 #include "content/common/font_cache_dispatcher_win.h" | 28 #include "content/common/font_cache_dispatcher_win.h" |
28 #endif // OS_LINUX | 29 #endif // OS_LINUX |
29 | 30 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 .Append(kContentsName) | 67 .Append(kContentsName) |
67 .Append(kMacOSName) | 68 .Append(kMacOSName) |
68 .Append(new_basename); | 69 .Append(new_basename); |
69 | 70 |
70 return new_path; | 71 return new_path; |
71 } | 72 } |
72 | 73 |
73 } // namespace | 74 } // namespace |
74 #endif // OS_MACOSX | 75 #endif // OS_MACOSX |
75 | 76 |
76 ChildProcessHost::ChildProcessHost() | 77 ChildProcessHost::ChildProcessHost(content::ChildProcessHostDelegate* delegate) |
77 : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), | 78 : delegate_(delegate), |
| 79 peer_handle_(base::kNullProcessHandle), |
78 opening_channel_(false) { | 80 opening_channel_(false) { |
79 #if defined(OS_WIN) | 81 #if defined(OS_WIN) |
80 AddFilter(new FontCacheDispatcher()); | 82 AddFilter(new FontCacheDispatcher()); |
81 #endif | 83 #endif |
82 } | 84 } |
83 | 85 |
84 ChildProcessHost::~ChildProcessHost() { | 86 ChildProcessHost::~ChildProcessHost() { |
85 for (size_t i = 0; i < filters_.size(); ++i) { | 87 for (size_t i = 0; i < filters_.size(); ++i) { |
86 filters_[i]->OnChannelClosing(); | 88 filters_[i]->OnChannelClosing(); |
87 filters_[i]->OnFilterRemoved(); | 89 filters_[i]->OnFilterRemoved(); |
88 } | 90 } |
89 listener_.Shutdown(); | 91 |
| 92 base::CloseProcessHandle(peer_handle_); |
90 } | 93 } |
91 | 94 |
92 void ChildProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { | 95 void ChildProcessHost::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { |
93 filters_.push_back(filter); | 96 filters_.push_back(filter); |
94 | 97 |
95 if (channel_.get()) | 98 if (channel_.get()) |
96 filter->OnFilterAdded(channel_.get()); | 99 filter->OnFilterAdded(channel_.get()); |
97 } | 100 } |
98 | 101 |
99 // static | 102 // static |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 return child_path; | 143 return child_path; |
141 } | 144 } |
142 | 145 |
143 void ChildProcessHost::ForceShutdown() { | 146 void ChildProcessHost::ForceShutdown() { |
144 Send(new ChildProcessMsg_Shutdown()); | 147 Send(new ChildProcessMsg_Shutdown()); |
145 } | 148 } |
146 | 149 |
147 bool ChildProcessHost::CreateChannel() { | 150 bool ChildProcessHost::CreateChannel() { |
148 channel_id_ = GenerateRandomChannelID(this); | 151 channel_id_ = GenerateRandomChannelID(this); |
149 channel_.reset(new IPC::Channel( | 152 channel_.reset(new IPC::Channel( |
150 channel_id_, IPC::Channel::MODE_SERVER, &listener_)); | 153 channel_id_, IPC::Channel::MODE_SERVER, this)); |
151 if (!channel_->Connect()) | 154 if (!channel_->Connect()) |
152 return false; | 155 return false; |
153 | 156 |
154 for (size_t i = 0; i < filters_.size(); ++i) | 157 for (size_t i = 0; i < filters_.size(); ++i) |
155 filters_[i]->OnFilterAdded(channel_.get()); | 158 filters_[i]->OnFilterAdded(channel_.get()); |
156 | 159 |
157 // Make sure these messages get sent first. | 160 // Make sure these messages get sent first. |
158 #if defined(IPC_MESSAGE_LOG_ENABLED) | 161 #if defined(IPC_MESSAGE_LOG_ENABLED) |
159 bool enabled = IPC::Logging::GetInstance()->Enabled(); | 162 bool enabled = IPC::Logging::GetInstance()->Enabled(); |
160 Send(new ChildProcessMsg_SetIPCLoggingEnabled(enabled)); | 163 Send(new ChildProcessMsg_SetIPCLoggingEnabled(enabled)); |
161 #endif | 164 #endif |
162 | 165 |
163 Send(new ChildProcessMsg_AskBeforeShutdown()); | 166 Send(new ChildProcessMsg_AskBeforeShutdown()); |
164 | 167 |
165 opening_channel_ = true; | 168 opening_channel_ = true; |
166 | 169 |
167 return true; | 170 return true; |
168 } | 171 } |
169 | 172 |
170 bool ChildProcessHost::OnMessageReceived(const IPC::Message& msg) { | |
171 return false; | |
172 } | |
173 | |
174 void ChildProcessHost::OnChannelConnected(int32 peer_pid) { | |
175 } | |
176 | |
177 void ChildProcessHost::OnChannelError() { | |
178 } | |
179 | |
180 bool ChildProcessHost::Send(IPC::Message* message) { | 173 bool ChildProcessHost::Send(IPC::Message* message) { |
181 if (!channel_.get()) { | 174 if (!channel_.get()) { |
182 delete message; | 175 delete message; |
183 return false; | 176 return false; |
184 } | 177 } |
185 return channel_->Send(message); | 178 return channel_->Send(message); |
186 } | 179 } |
187 | 180 |
188 void ChildProcessHost::OnAllocateSharedMemory( | 181 void ChildProcessHost::AllocateSharedMemory( |
189 uint32 buffer_size, base::ProcessHandle child_process_handle, | 182 uint32 buffer_size, base::ProcessHandle child_process_handle, |
190 base::SharedMemoryHandle* shared_memory_handle) { | 183 base::SharedMemoryHandle* shared_memory_handle) { |
191 base::SharedMemory shared_buf; | 184 base::SharedMemory shared_buf; |
192 if (!shared_buf.CreateAndMapAnonymous(buffer_size)) { | 185 if (!shared_buf.CreateAndMapAnonymous(buffer_size)) { |
193 *shared_memory_handle = base::SharedMemory::NULLHandle(); | 186 *shared_memory_handle = base::SharedMemory::NULLHandle(); |
194 NOTREACHED() << "Cannot map shared memory buffer"; | 187 NOTREACHED() << "Cannot map shared memory buffer"; |
195 return; | 188 return; |
196 } | 189 } |
197 shared_buf.GiveToProcess(child_process_handle, shared_memory_handle); | 190 shared_buf.GiveToProcess(child_process_handle, shared_memory_handle); |
198 } | 191 } |
199 | 192 |
200 std::string ChildProcessHost::GenerateRandomChannelID(void* instance) { | 193 std::string ChildProcessHost::GenerateRandomChannelID(void* instance) { |
201 // Note: the string must start with the current process id, this is how | 194 // Note: the string must start with the current process id, this is how |
202 // child processes determine the pid of the parent. | 195 // child processes determine the pid of the parent. |
203 // Build the channel ID. This is composed of a unique identifier for the | 196 // Build the channel ID. This is composed of a unique identifier for the |
204 // parent browser process, an identifier for the child instance, and a random | 197 // parent browser process, an identifier for the child instance, and a random |
205 // component. We use a random component so that a hacked child process can't | 198 // component. We use a random component so that a hacked child process can't |
206 // cause denial of service by causing future named pipe creation to fail. | 199 // cause denial of service by causing future named pipe creation to fail. |
207 return base::StringPrintf("%d.%p.%d", | 200 return base::StringPrintf("%d.%p.%d", |
208 base::GetCurrentProcId(), instance, | 201 base::GetCurrentProcId(), instance, |
209 base::RandInt(0, std::numeric_limits<int>::max())); | 202 base::RandInt(0, std::numeric_limits<int>::max())); |
210 } | 203 } |
211 | 204 |
212 int ChildProcessHost::GenerateChildProcessUniqueId() { | 205 int ChildProcessHost::GenerateChildProcessUniqueId() { |
213 // This function must be threadsafe. | 206 // This function must be threadsafe. |
214 static base::subtle::Atomic32 last_unique_child_id = 0; | 207 static base::subtle::Atomic32 last_unique_child_id = 0; |
215 return base::subtle::NoBarrier_AtomicIncrement(&last_unique_child_id, 1); | 208 return base::subtle::NoBarrier_AtomicIncrement(&last_unique_child_id, 1); |
216 } | 209 } |
217 | 210 |
218 | 211 bool ChildProcessHost::OnMessageReceived(const IPC::Message& msg) { |
219 void ChildProcessHost::OnChildDied() { | |
220 delete this; | |
221 } | |
222 | |
223 void ChildProcessHost::OnChildDisconnected() { | |
224 OnChildDied(); | |
225 } | |
226 | |
227 void ChildProcessHost::ShutdownStarted() { | |
228 } | |
229 | |
230 ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) | |
231 : host_(host), peer_handle_(base::kNullProcessHandle) { | |
232 } | |
233 | |
234 ChildProcessHost::ListenerHook::~ListenerHook() { | |
235 base::CloseProcessHandle(peer_handle_); | |
236 } | |
237 | |
238 void ChildProcessHost::ListenerHook::Shutdown() { | |
239 host_ = NULL; | |
240 } | |
241 | |
242 bool ChildProcessHost::ListenerHook::OnMessageReceived( | |
243 const IPC::Message& msg) { | |
244 if (!host_) | |
245 return true; | |
246 | |
247 #ifdef IPC_MESSAGE_LOG_ENABLED | 212 #ifdef IPC_MESSAGE_LOG_ENABLED |
248 IPC::Logging* logger = IPC::Logging::GetInstance(); | 213 IPC::Logging* logger = IPC::Logging::GetInstance(); |
249 if (msg.type() == IPC_LOGGING_ID) { | 214 if (msg.type() == IPC_LOGGING_ID) { |
250 logger->OnReceivedLoggingMessage(msg); | 215 logger->OnReceivedLoggingMessage(msg); |
251 return true; | 216 return true; |
252 } | 217 } |
253 | 218 |
254 if (logger->Enabled()) | 219 if (logger->Enabled()) |
255 logger->OnPreDispatchMessage(msg); | 220 logger->OnPreDispatchMessage(msg); |
256 #endif | 221 #endif |
257 | 222 |
258 bool handled = false; | 223 bool handled = false; |
259 for (size_t i = 0; i < host_->filters_.size(); ++i) { | 224 for (size_t i = 0; i < filters_.size(); ++i) { |
260 if (host_->filters_[i]->OnMessageReceived(msg)) { | 225 if (filters_[i]->OnMessageReceived(msg)) { |
261 handled = true; | 226 handled = true; |
262 break; | 227 break; |
263 } | 228 } |
264 } | 229 } |
265 | 230 |
266 if (!handled) { | 231 if (!handled) { |
267 bool msg_is_good = false; | |
268 handled = true; | 232 handled = true; |
269 IPC_BEGIN_MESSAGE_MAP_EX(ListenerHook, msg, msg_is_good) | 233 IPC_BEGIN_MESSAGE_MAP(ChildProcessHost, msg) |
270 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest, | 234 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest, |
271 OnShutdownRequest) | 235 OnShutdownRequest) |
272 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory, | 236 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory, |
273 OnAllocateSharedMemory) | 237 OnAllocateSharedMemory) |
274 IPC_MESSAGE_UNHANDLED(handled = false) | 238 IPC_MESSAGE_UNHANDLED(handled = false) |
275 IPC_END_MESSAGE_MAP_EX() | 239 IPC_END_MESSAGE_MAP() |
276 | 240 |
277 if (!handled) | 241 if (!handled) |
278 handled = host_->OnMessageReceived(msg); | 242 handled = delegate_->OnMessageReceived(msg); |
279 } | 243 } |
280 | 244 |
281 #ifdef IPC_MESSAGE_LOG_ENABLED | 245 #ifdef IPC_MESSAGE_LOG_ENABLED |
282 if (logger->Enabled()) | 246 if (logger->Enabled()) |
283 logger->OnPostDispatchMessage(msg, host_->channel_id_); | 247 logger->OnPostDispatchMessage(msg, channel_id_); |
284 #endif | 248 #endif |
285 return handled; | 249 return handled; |
286 } | 250 } |
287 | 251 |
288 void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) { | 252 void ChildProcessHost::OnChannelConnected(int32 peer_pid) { |
289 if (!host_) | |
290 return; | |
291 if (!base::OpenProcessHandle(peer_pid, &peer_handle_)) { | 253 if (!base::OpenProcessHandle(peer_pid, &peer_handle_)) { |
292 NOTREACHED(); | 254 NOTREACHED(); |
293 } | 255 } |
294 host_->opening_channel_ = false; | 256 opening_channel_ = false; |
295 host_->OnChannelConnected(peer_pid); | 257 delegate_->OnChannelConnected(peer_pid); |
296 for (size_t i = 0; i < host_->filters_.size(); ++i) | 258 for (size_t i = 0; i < filters_.size(); ++i) |
297 host_->filters_[i]->OnChannelConnected(peer_pid); | 259 filters_[i]->OnChannelConnected(peer_pid); |
298 } | 260 } |
299 | 261 |
300 void ChildProcessHost::ListenerHook::OnChannelError() { | 262 void ChildProcessHost::OnChannelError() { |
301 if (!host_) | 263 opening_channel_ = false; |
302 return; | 264 delegate_->OnChannelError(); |
303 host_->opening_channel_ = false; | |
304 host_->OnChannelError(); | |
305 | 265 |
306 for (size_t i = 0; i < host_->filters_.size(); ++i) | 266 for (size_t i = 0; i < filters_.size(); ++i) |
307 host_->filters_[i]->OnChannelError(); | 267 filters_[i]->OnChannelError(); |
308 | 268 |
309 // This will delete host_, which will also destroy this! | 269 // This will delete host_, which will also destroy this! |
310 host_->OnChildDisconnected(); | 270 delegate_->OnChildDisconnected(); |
311 } | 271 } |
312 | 272 |
313 bool ChildProcessHost::ListenerHook::Send(IPC::Message* message) { | 273 void ChildProcessHost::OnAllocateSharedMemory( |
314 return host_->Send(message); | 274 uint32 buffer_size, |
| 275 base::SharedMemoryHandle* handle) { |
| 276 AllocateSharedMemory(buffer_size, peer_handle_, handle); |
315 } | 277 } |
316 | 278 |
317 void ChildProcessHost::ListenerHook::OnAllocateSharedMemory( | 279 void ChildProcessHost::OnShutdownRequest() { |
318 uint32 buffer_size, | 280 if (delegate_->CanShutdown()) |
319 base::SharedMemoryHandle* handle) { | 281 Send(new ChildProcessMsg_Shutdown()); |
320 ChildProcessHost::OnAllocateSharedMemory( | |
321 buffer_size, peer_handle_, handle); | |
322 } | 282 } |
323 | |
324 void ChildProcessHost::ListenerHook::OnShutdownRequest() { | |
325 if (host_->CanShutdown()) | |
326 host_->Send(new ChildProcessMsg_Shutdown()); | |
327 } | |
OLD | NEW |