blob: bb0fdfd041d529b5374f9fea03e8553d5d9f3cd6 [file] [log] [blame]
[email protected]5c41e6e12012-03-17 02:20:461// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]d27893f62010-07-03 05:47:422// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]4734d0b2011-12-03 07:10:445#include "content/common/child_process_host_impl.h"
[email protected]d27893f62010-07-03 05:47:426
[email protected]4306c3792011-12-02 01:57:537#include <limits>
8
9#include "base/atomicops.h"
[email protected]d27893f62010-07-03 05:47:4210#include "base/command_line.h"
[email protected]57999812013-02-24 05:40:5211#include "base/files/file_path.h"
[email protected]8c40f322011-08-24 03:33:3612#include "base/logging.h"
[email protected]835d7c82010-10-14 04:38:3813#include "base/metrics/histogram.h"
[email protected]d27893f62010-07-03 05:47:4214#include "base/path_service.h"
[email protected]bdae9812011-10-15 00:33:0315#include "base/process_util.h"
[email protected]4306c3792011-12-02 01:57:5316#include "base/rand_util.h"
17#include "base/stringprintf.h"
[email protected]a5f28b42011-01-17 10:30:1318#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
[email protected]ff47b2962011-03-07 23:51:4919#include "content/common/child_process_messages.h"
[email protected]4cb43102011-12-02 20:24:4920#include "content/public/common/child_process_host_delegate.h"
[email protected]5d921d4c2011-10-21 22:26:1421#include "content/public/common/content_paths.h"
[email protected]c08950d22011-10-13 22:20:2922#include "content/public/common/content_switches.h"
[email protected]5c41e6e12012-03-17 02:20:4623#include "ipc/ipc_channel.h"
[email protected]a83d42292010-08-17 22:51:1024#include "ipc/ipc_logging.h"
[email protected]d27893f62010-07-03 05:47:4225
26#if defined(OS_LINUX)
27#include "base/linux_util.h"
[email protected]e35c9a82011-12-01 18:48:4128#elif defined(OS_WIN)
29#include "content/common/font_cache_dispatcher_win.h"
[email protected]d27893f62010-07-03 05:47:4230#endif // OS_LINUX
31
[email protected]8c40f322011-08-24 03:33:3632#if defined(OS_MACOSX)
33namespace {
34
35// Given |path| identifying a Mac-style child process executable path, adjusts
36// it to correspond to |feature|. For a child process path such as
37// ".../Chromium Helper.app/Contents/MacOS/Chromium Helper", the transformed
38// path for feature "NP" would be
39// ".../Chromium Helper NP.app/Contents/MacOS/Chromium Helper NP". The new
40// path is returned.
[email protected]a7329162013-02-07 19:21:4841base::FilePath TransformPathForFeature(const base::FilePath& path,
[email protected]8c40f322011-08-24 03:33:3642 const std::string& feature) {
43 std::string basename = path.BaseName().value();
44
[email protected]a7329162013-02-07 19:21:4845 base::FilePath macos_path = path.DirName();
[email protected]8c40f322011-08-24 03:33:3646 const char kMacOSName[] = "MacOS";
47 DCHECK_EQ(kMacOSName, macos_path.BaseName().value());
48
[email protected]a7329162013-02-07 19:21:4849 base::FilePath contents_path = macos_path.DirName();
[email protected]8c40f322011-08-24 03:33:3650 const char kContentsName[] = "Contents";
51 DCHECK_EQ(kContentsName, contents_path.BaseName().value());
52
[email protected]a7329162013-02-07 19:21:4853 base::FilePath helper_app_path = contents_path.DirName();
[email protected]8c40f322011-08-24 03:33:3654 const char kAppExtension[] = ".app";
55 std::string basename_app = basename;
56 basename_app.append(kAppExtension);
57 DCHECK_EQ(basename_app, helper_app_path.BaseName().value());
58
[email protected]a7329162013-02-07 19:21:4859 base::FilePath root_path = helper_app_path.DirName();
[email protected]8c40f322011-08-24 03:33:3660
61 std::string new_basename = basename;
62 new_basename.append(1, ' ');
63 new_basename.append(feature);
64 std::string new_basename_app = new_basename;
65 new_basename_app.append(kAppExtension);
66
[email protected]a7329162013-02-07 19:21:4867 base::FilePath new_path = root_path.Append(new_basename_app)
[email protected]8c40f322011-08-24 03:33:3668 .Append(kContentsName)
69 .Append(kMacOSName)
70 .Append(new_basename);
71
72 return new_path;
73}
74
75} // namespace
76#endif // OS_MACOSX
77
[email protected]4734d0b2011-12-03 07:10:4478namespace content {
[email protected]d27893f62010-07-03 05:47:4279
[email protected]d7c7c98a2012-07-12 21:27:4480int ChildProcessHostImpl::kInvalidChildProcessId = -1;
81
[email protected]4734d0b2011-12-03 07:10:4482// static
83ChildProcessHost* ChildProcessHost::Create(ChildProcessHostDelegate* delegate) {
84 return new ChildProcessHostImpl(delegate);
[email protected]d27893f62010-07-03 05:47:4285}
86
87// static
[email protected]a7329162013-02-07 19:21:4888base::FilePath ChildProcessHost::GetChildPath(int flags) {
89 base::FilePath child_path;
[email protected]d27893f62010-07-03 05:47:4290
91 child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
92 switches::kBrowserSubprocessPath);
[email protected]d27893f62010-07-03 05:47:4293
[email protected]d27893f62010-07-03 05:47:4294#if defined(OS_LINUX)
95 // Use /proc/self/exe rather than our known binary path so updates
96 // can't swap out the binary from underneath us.
[email protected]a5f28b42011-01-17 10:30:1397 // When running under Valgrind, forking /proc/self/exe ends up forking the
98 // Valgrind executable, which then crashes. However, it's almost safe to
99 // assume that the updates won't happen while testing with Valgrind tools.
[email protected]bfd47482011-08-24 13:57:26100 if (child_path.empty() && flags & CHILD_ALLOW_SELF && !RunningOnValgrind())
[email protected]a7329162013-02-07 19:21:48101 child_path = base::FilePath(base::kProcSelfExe);
[email protected]d27893f62010-07-03 05:47:42102#endif
103
104 // On most platforms, the child executable is the same as the current
105 // executable.
[email protected]bfd47482011-08-24 13:57:26106 if (child_path.empty())
[email protected]dcc72db2013-01-02 00:44:18107 PathService::Get(CHILD_PROCESS_EXE, &child_path);
[email protected]8c40f322011-08-24 03:33:36108
109#if defined(OS_MACOSX)
110 DCHECK(!(flags & CHILD_NO_PIE && flags & CHILD_ALLOW_HEAP_EXECUTION));
111
112 // If needed, choose an executable with special flags set that inform the
113 // kernel to enable or disable specific optional process-wide features.
114 if (flags & CHILD_NO_PIE) {
115 // "NP" is "No PIE". This results in Chromium Helper NP.app or
116 // Google Chrome Helper NP.app.
117 child_path = TransformPathForFeature(child_path, "NP");
118 } else if (flags & CHILD_ALLOW_HEAP_EXECUTION) {
119 // "EH" is "Executable Heap". A non-executable heap is only available to
120 // 32-bit processes on Mac OS X 10.7. Most code can and should run with a
121 // non-executable heap, but the "EH" feature is provided to allow code
122 // intolerant of a non-executable heap to work properly on 10.7. This
123 // results in Chromium Helper EH.app or Google Chrome Helper EH.app.
124 child_path = TransformPathForFeature(child_path, "EH");
125 }
126#endif
127
[email protected]d27893f62010-07-03 05:47:42128 return child_path;
129}
130
[email protected]4734d0b2011-12-03 07:10:44131ChildProcessHostImpl::ChildProcessHostImpl(ChildProcessHostDelegate* delegate)
132 : delegate_(delegate),
133 peer_handle_(base::kNullProcessHandle),
134 opening_channel_(false) {
135#if defined(OS_WIN)
136 AddFilter(new FontCacheDispatcher());
137#endif
138}
139
140ChildProcessHostImpl::~ChildProcessHostImpl() {
141 for (size_t i = 0; i < filters_.size(); ++i) {
142 filters_[i]->OnChannelClosing();
143 filters_[i]->OnFilterRemoved();
144 }
145
146 base::CloseProcessHandle(peer_handle_);
147}
148
149void ChildProcessHostImpl::AddFilter(IPC::ChannelProxy::MessageFilter* filter) {
150 filters_.push_back(filter);
151
[email protected]59383c782013-04-17 16:43:27152 if (channel_)
[email protected]4734d0b2011-12-03 07:10:44153 filter->OnFilterAdded(channel_.get());
154}
155
156void ChildProcessHostImpl::ForceShutdown() {
[email protected]bdae9812011-10-15 00:33:03157 Send(new ChildProcessMsg_Shutdown());
158}
[email protected]91443fc2010-07-14 05:08:46159
[email protected]4734d0b2011-12-03 07:10:44160std::string ChildProcessHostImpl::CreateChannel() {
[email protected]5c41e6e12012-03-17 02:20:46161 channel_id_ = IPC::Channel::GenerateVerifiedChannelID(std::string());
[email protected]d27893f62010-07-03 05:47:42162 channel_.reset(new IPC::Channel(
[email protected]4cb43102011-12-02 20:24:49163 channel_id_, IPC::Channel::MODE_SERVER, this));
[email protected]d27893f62010-07-03 05:47:42164 if (!channel_->Connect())
[email protected]4734d0b2011-12-03 07:10:44165 return std::string();
[email protected]d27893f62010-07-03 05:47:42166
[email protected]8e2b6472010-12-15 22:19:48167 for (size_t i = 0; i < filters_.size(); ++i)
168 filters_[i]->OnFilterAdded(channel_.get());
169
[email protected]91443fc2010-07-14 05:08:46170 // Make sure these messages get sent first.
171#if defined(IPC_MESSAGE_LOG_ENABLED)
[email protected]8e8bb6d2010-12-13 08:18:55172 bool enabled = IPC::Logging::GetInstance()->Enabled();
[email protected]ff47b2962011-03-07 23:51:49173 Send(new ChildProcessMsg_SetIPCLoggingEnabled(enabled));
[email protected]91443fc2010-07-14 05:08:46174#endif
175
[email protected]d27893f62010-07-03 05:47:42176 opening_channel_ = true;
177
[email protected]4734d0b2011-12-03 07:10:44178 return channel_id_;
[email protected]d27893f62010-07-03 05:47:42179}
180
[email protected]4734d0b2011-12-03 07:10:44181bool ChildProcessHostImpl::IsChannelOpening() {
182 return opening_channel_;
183}
184
185#if defined(OS_POSIX)
186int ChildProcessHostImpl::TakeClientFileDescriptor() {
187 return channel_->TakeClientFileDescriptor();
188}
189#endif
190
191bool ChildProcessHostImpl::Send(IPC::Message* message) {
[email protected]59383c782013-04-17 16:43:27192 if (!channel_) {
[email protected]8e2b6472010-12-15 22:19:48193 delete message;
[email protected]d27893f62010-07-03 05:47:42194 return false;
195 }
[email protected]8e2b6472010-12-15 22:19:48196 return channel_->Send(message);
[email protected]d27893f62010-07-03 05:47:42197}
198
[email protected]4734d0b2011-12-03 07:10:44199void ChildProcessHostImpl::AllocateSharedMemory(
[email protected]3f892832013-01-11 03:23:59200 size_t buffer_size, base::ProcessHandle child_process_handle,
[email protected]bdae9812011-10-15 00:33:03201 base::SharedMemoryHandle* shared_memory_handle) {
202 base::SharedMemory shared_buf;
203 if (!shared_buf.CreateAndMapAnonymous(buffer_size)) {
204 *shared_memory_handle = base::SharedMemory::NULLHandle();
205 NOTREACHED() << "Cannot map shared memory buffer";
206 return;
207 }
208 shared_buf.GiveToProcess(child_process_handle, shared_memory_handle);
209}
210
[email protected]4734d0b2011-12-03 07:10:44211int ChildProcessHostImpl::GenerateChildProcessUniqueId() {
[email protected]4306c3792011-12-02 01:57:53212 // This function must be threadsafe.
[email protected]d7c7c98a2012-07-12 21:27:44213 //
214 // TODO(ajwong): Why not StaticAtomicSequenceNumber?
[email protected]4306c3792011-12-02 01:57:53215 static base::subtle::Atomic32 last_unique_child_id = 0;
[email protected]d7c7c98a2012-07-12 21:27:44216 int id = base::subtle::NoBarrier_AtomicIncrement(&last_unique_child_id, 1);
217
218 CHECK_NE(kInvalidChildProcessId, id);
219
220 return id;
[email protected]4306c3792011-12-02 01:57:53221}
222
[email protected]4734d0b2011-12-03 07:10:44223bool ChildProcessHostImpl::OnMessageReceived(const IPC::Message& msg) {
[email protected]d27893f62010-07-03 05:47:42224#ifdef IPC_MESSAGE_LOG_ENABLED
[email protected]8e8bb6d2010-12-13 08:18:55225 IPC::Logging* logger = IPC::Logging::GetInstance();
[email protected]d27893f62010-07-03 05:47:42226 if (msg.type() == IPC_LOGGING_ID) {
227 logger->OnReceivedLoggingMessage(msg);
[email protected]a95986a82010-12-24 06:19:28228 return true;
[email protected]d27893f62010-07-03 05:47:42229 }
230
231 if (logger->Enabled())
232 logger->OnPreDispatchMessage(msg);
233#endif
234
[email protected]8e2b6472010-12-15 22:19:48235 bool handled = false;
[email protected]4cb43102011-12-02 20:24:49236 for (size_t i = 0; i < filters_.size(); ++i) {
237 if (filters_[i]->OnMessageReceived(msg)) {
[email protected]8e2b6472010-12-15 22:19:48238 handled = true;
239 break;
[email protected]d27893f62010-07-03 05:47:42240 }
241 }
242
[email protected]bdae9812011-10-15 00:33:03243 if (!handled) {
[email protected]e5257432010-12-21 01:18:37244 handled = true;
[email protected]4734d0b2011-12-03 07:10:44245 IPC_BEGIN_MESSAGE_MAP(ChildProcessHostImpl, msg)
[email protected]bdae9812011-10-15 00:33:03246 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest,
247 OnShutdownRequest)
248 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory,
249 OnAllocateSharedMemory)
250 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]4cb43102011-12-02 20:24:49251 IPC_END_MESSAGE_MAP()
[email protected]e5257432010-12-21 01:18:37252
[email protected]bdae9812011-10-15 00:33:03253 if (!handled)
[email protected]4cb43102011-12-02 20:24:49254 handled = delegate_->OnMessageReceived(msg);
[email protected]bdae9812011-10-15 00:33:03255 }
[email protected]8e2b6472010-12-15 22:19:48256
[email protected]d27893f62010-07-03 05:47:42257#ifdef IPC_MESSAGE_LOG_ENABLED
258 if (logger->Enabled())
[email protected]4cb43102011-12-02 20:24:49259 logger->OnPostDispatchMessage(msg, channel_id_);
[email protected]d27893f62010-07-03 05:47:42260#endif
[email protected]a95986a82010-12-24 06:19:28261 return handled;
[email protected]d27893f62010-07-03 05:47:42262}
263
[email protected]4734d0b2011-12-03 07:10:44264void ChildProcessHostImpl::OnChannelConnected(int32 peer_pid) {
[email protected]a2b85422013-04-09 11:00:20265 if (!base::OpenPrivilegedProcessHandle(peer_pid, &peer_handle_)) {
[email protected]bdae9812011-10-15 00:33:03266 NOTREACHED();
267 }
[email protected]4cb43102011-12-02 20:24:49268 opening_channel_ = false;
269 delegate_->OnChannelConnected(peer_pid);
270 for (size_t i = 0; i < filters_.size(); ++i)
271 filters_[i]->OnChannelConnected(peer_pid);
[email protected]d27893f62010-07-03 05:47:42272}
273
[email protected]4734d0b2011-12-03 07:10:44274void ChildProcessHostImpl::OnChannelError() {
[email protected]4cb43102011-12-02 20:24:49275 opening_channel_ = false;
276 delegate_->OnChannelError();
[email protected]d27893f62010-07-03 05:47:42277
[email protected]4cb43102011-12-02 20:24:49278 for (size_t i = 0; i < filters_.size(); ++i)
279 filters_[i]->OnChannelError();
[email protected]8e2b6472010-12-15 22:19:48280
[email protected]d27893f62010-07-03 05:47:42281 // This will delete host_, which will also destroy this!
[email protected]4cb43102011-12-02 20:24:49282 delegate_->OnChildDisconnected();
[email protected]d27893f62010-07-03 05:47:42283}
284
[email protected]4734d0b2011-12-03 07:10:44285void ChildProcessHostImpl::OnAllocateSharedMemory(
[email protected]bdae9812011-10-15 00:33:03286 uint32 buffer_size,
287 base::SharedMemoryHandle* handle) {
[email protected]4cb43102011-12-02 20:24:49288 AllocateSharedMemory(buffer_size, peer_handle_, handle);
[email protected]bdae9812011-10-15 00:33:03289}
290
[email protected]4734d0b2011-12-03 07:10:44291void ChildProcessHostImpl::OnShutdownRequest() {
[email protected]4cb43102011-12-02 20:24:49292 if (delegate_->CanShutdown())
293 Send(new ChildProcessMsg_Shutdown());
[email protected]d27893f62010-07-03 05:47:42294}
[email protected]4734d0b2011-12-03 07:10:44295
296} // namespace content