1 // Copyright (c) 2012 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/common/child_process_host_impl.h" 6 7 #include <limits> 8 9 #include "base/atomicops.h" 10 #include "base/command_line.h" 11 #include "base/files/file_path.h" 12 #include "base/logging.h" 13 #include "base/metrics/histogram.h" 14 #include "base/path_service.h" 15 #include "base/process/process_metrics.h" 16 #include "base/rand_util.h" 17 #include "base/strings/stringprintf.h" 18 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 19 #include "content/common/child_process_messages.h" 20 #include "content/common/gpu/client/gpu_memory_buffer_impl.h" 21 #include "content/public/common/child_process_host_delegate.h" 22 #include "content/public/common/content_paths.h" 23 #include "content/public/common/content_switches.h" 24 #include "ipc/ipc_channel.h" 25 #include "ipc/ipc_logging.h" 26 27 #if defined(OS_LINUX) 28 #include "base/linux_util.h" 29 #elif defined(OS_WIN) 30 #include "content/common/font_cache_dispatcher_win.h" 31 #endif // OS_LINUX 32 33 #if defined(OS_MACOSX) 34 namespace { 35 36 // Given |path| identifying a Mac-style child process executable path, adjusts 37 // it to correspond to |feature|. For a child process path such as 38 // ".../Chromium Helper.app/Contents/MacOS/Chromium Helper", the transformed 39 // path for feature "NP" would be 40 // ".../Chromium Helper NP.app/Contents/MacOS/Chromium Helper NP". The new 41 // path is returned. 42 base::FilePath TransformPathForFeature(const base::FilePath& path, 43 const std::string& feature) { 44 std::string basename = path.BaseName().value(); 45 46 base::FilePath macos_path = path.DirName(); 47 const char kMacOSName[] = "MacOS"; 48 DCHECK_EQ(kMacOSName, macos_path.BaseName().value()); 49 50 base::FilePath contents_path = macos_path.DirName(); 51 const char kContentsName[] = "Contents"; 52 DCHECK_EQ(kContentsName, contents_path.BaseName().value()); 53 54 base::FilePath helper_app_path = contents_path.DirName(); 55 const char kAppExtension[] = ".app"; 56 std::string basename_app = basename; 57 basename_app.append(kAppExtension); 58 DCHECK_EQ(basename_app, helper_app_path.BaseName().value()); 59 60 base::FilePath root_path = helper_app_path.DirName(); 61 62 std::string new_basename = basename; 63 new_basename.append(1, ' '); 64 new_basename.append(feature); 65 std::string new_basename_app = new_basename; 66 new_basename_app.append(kAppExtension); 67 68 base::FilePath new_path = root_path.Append(new_basename_app) 69 .Append(kContentsName) 70 .Append(kMacOSName) 71 .Append(new_basename); 72 73 return new_path; 74 } 75 76 } // namespace 77 #endif // OS_MACOSX 78 79 namespace content { 80 81 int ChildProcessHostImpl::kInvalidChildProcessId = -1; 82 83 // static 84 ChildProcessHost* ChildProcessHost::Create(ChildProcessHostDelegate* delegate) { 85 return new ChildProcessHostImpl(delegate); 86 } 87 88 // static 89 base::FilePath ChildProcessHost::GetChildPath(int flags) { 90 base::FilePath child_path; 91 92 child_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath( 93 switches::kBrowserSubprocessPath); 94 95 #if defined(OS_LINUX) 96 // Use /proc/self/exe rather than our known binary path so updates 97 // can't swap out the binary from underneath us. 98 // When running under Valgrind, forking /proc/self/exe ends up forking the 99 // Valgrind executable, which then crashes. However, it's almost safe to 100 // assume that the updates won't happen while testing with Valgrind tools. 101 if (child_path.empty() && flags & CHILD_ALLOW_SELF && !RunningOnValgrind()) 102 child_path = base::FilePath(base::kProcSelfExe); 103 #endif 104 105 // On most platforms, the child executable is the same as the current 106 // executable. 107 if (child_path.empty()) 108 PathService::Get(CHILD_PROCESS_EXE, &child_path); 109 110 #if defined(OS_MACOSX) 111 DCHECK(!(flags & CHILD_NO_PIE && flags & CHILD_ALLOW_HEAP_EXECUTION)); 112 113 // If needed, choose an executable with special flags set that inform the 114 // kernel to enable or disable specific optional process-wide features. 115 if (flags & CHILD_NO_PIE) { 116 // "NP" is "No PIE". This results in Chromium Helper NP.app or 117 // Google Chrome Helper NP.app. 118 child_path = TransformPathForFeature(child_path, "NP"); 119 } else if (flags & CHILD_ALLOW_HEAP_EXECUTION) { 120 // "EH" is "Executable Heap". A non-executable heap is only available to 121 // 32-bit processes on Mac OS X 10.7. Most code can and should run with a 122 // non-executable heap, but the "EH" feature is provided to allow code 123 // intolerant of a non-executable heap to work properly on 10.7. This 124 // results in Chromium Helper EH.app or Google Chrome Helper EH.app. 125 child_path = TransformPathForFeature(child_path, "EH"); 126 } 127 #endif 128 129 return child_path; 130 } 131 132 ChildProcessHostImpl::ChildProcessHostImpl(ChildProcessHostDelegate* delegate) 133 : delegate_(delegate), 134 peer_handle_(base::kNullProcessHandle), 135 opening_channel_(false) { 136 #if defined(OS_WIN) 137 AddFilter(new FontCacheDispatcher()); 138 #endif 139 } 140 141 ChildProcessHostImpl::~ChildProcessHostImpl() { 142 for (size_t i = 0; i < filters_.size(); ++i) { 143 filters_[i]->OnChannelClosing(); 144 filters_[i]->OnFilterRemoved(); 145 } 146 147 base::CloseProcessHandle(peer_handle_); 148 } 149 150 void ChildProcessHostImpl::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { 151 filters_.push_back(filter); 152 153 if (channel_) 154 filter->OnFilterAdded(channel_.get()); 155 } 156 157 void ChildProcessHostImpl::ForceShutdown() { 158 Send(new ChildProcessMsg_Shutdown()); 159 } 160 161 std::string ChildProcessHostImpl::CreateChannel() { 162 channel_id_ = IPC::Channel::GenerateVerifiedChannelID(std::string()); 163 channel_.reset(new IPC::Channel( 164 channel_id_, IPC::Channel::MODE_SERVER, this)); 165 if (!channel_->Connect()) 166 return std::string(); 167 168 for (size_t i = 0; i < filters_.size(); ++i) 169 filters_[i]->OnFilterAdded(channel_.get()); 170 171 // Make sure these messages get sent first. 172 #if defined(IPC_MESSAGE_LOG_ENABLED) 173 bool enabled = IPC::Logging::GetInstance()->Enabled(); 174 Send(new ChildProcessMsg_SetIPCLoggingEnabled(enabled)); 175 #endif 176 177 opening_channel_ = true; 178 179 return channel_id_; 180 } 181 182 bool ChildProcessHostImpl::IsChannelOpening() { 183 return opening_channel_; 184 } 185 186 #if defined(OS_POSIX) 187 int ChildProcessHostImpl::TakeClientFileDescriptor() { 188 return channel_->TakeClientFileDescriptor(); 189 } 190 #endif 191 192 bool ChildProcessHostImpl::Send(IPC::Message* message) { 193 if (!channel_) { 194 delete message; 195 return false; 196 } 197 return channel_->Send(message); 198 } 199 200 void ChildProcessHostImpl::AllocateSharedMemory( 201 size_t buffer_size, base::ProcessHandle child_process_handle, 202 base::SharedMemoryHandle* shared_memory_handle) { 203 base::SharedMemory shared_buf; 204 if (!shared_buf.CreateAnonymous(buffer_size)) { 205 *shared_memory_handle = base::SharedMemory::NULLHandle(); 206 NOTREACHED() << "Cannot create shared memory buffer"; 207 return; 208 } 209 shared_buf.GiveToProcess(child_process_handle, shared_memory_handle); 210 } 211 212 int ChildProcessHostImpl::GenerateChildProcessUniqueId() { 213 // This function must be threadsafe. 214 // 215 // TODO(ajwong): Why not StaticAtomicSequenceNumber? 216 static base::subtle::Atomic32 last_unique_child_id = 0; 217 int id = base::subtle::NoBarrier_AtomicIncrement(&last_unique_child_id, 1); 218 219 CHECK_NE(kInvalidChildProcessId, id); 220 221 return id; 222 } 223 224 bool ChildProcessHostImpl::OnMessageReceived(const IPC::Message& msg) { 225 #ifdef IPC_MESSAGE_LOG_ENABLED 226 IPC::Logging* logger = IPC::Logging::GetInstance(); 227 if (msg.type() == IPC_LOGGING_ID) { 228 logger->OnReceivedLoggingMessage(msg); 229 return true; 230 } 231 232 if (logger->Enabled()) 233 logger->OnPreDispatchMessage(msg); 234 #endif 235 236 bool handled = false; 237 for (size_t i = 0; i < filters_.size(); ++i) { 238 if (filters_[i]->OnMessageReceived(msg)) { 239 handled = true; 240 break; 241 } 242 } 243 244 if (!handled) { 245 handled = true; 246 IPC_BEGIN_MESSAGE_MAP(ChildProcessHostImpl, msg) 247 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ShutdownRequest, 248 OnShutdownRequest) 249 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory, 250 OnAllocateSharedMemory) 251 IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer, 252 OnAllocateGpuMemoryBuffer) 253 IPC_MESSAGE_UNHANDLED(handled = false) 254 IPC_END_MESSAGE_MAP() 255 256 if (!handled) 257 handled = delegate_->OnMessageReceived(msg); 258 } 259 260 #ifdef IPC_MESSAGE_LOG_ENABLED 261 if (logger->Enabled()) 262 logger->OnPostDispatchMessage(msg, channel_id_); 263 #endif 264 return handled; 265 } 266 267 void ChildProcessHostImpl::OnChannelConnected(int32 peer_pid) { 268 if (!base::OpenPrivilegedProcessHandle(peer_pid, &peer_handle_)) { 269 NOTREACHED(); 270 } 271 opening_channel_ = false; 272 delegate_->OnChannelConnected(peer_pid); 273 for (size_t i = 0; i < filters_.size(); ++i) 274 filters_[i]->OnChannelConnected(peer_pid); 275 } 276 277 void ChildProcessHostImpl::OnChannelError() { 278 opening_channel_ = false; 279 delegate_->OnChannelError(); 280 281 for (size_t i = 0; i < filters_.size(); ++i) 282 filters_[i]->OnChannelError(); 283 284 // This will delete host_, which will also destroy this! 285 delegate_->OnChildDisconnected(); 286 } 287 288 void ChildProcessHostImpl::OnAllocateSharedMemory( 289 uint32 buffer_size, 290 base::SharedMemoryHandle* handle) { 291 AllocateSharedMemory(buffer_size, peer_handle_, handle); 292 } 293 294 void ChildProcessHostImpl::OnShutdownRequest() { 295 if (delegate_->CanShutdown()) 296 Send(new ChildProcessMsg_Shutdown()); 297 } 298 299 void ChildProcessHostImpl::OnAllocateGpuMemoryBuffer( 300 uint32 width, 301 uint32 height, 302 uint32 internalformat, 303 gfx::GpuMemoryBufferHandle* handle) { 304 handle->type = gfx::SHARED_MEMORY_BUFFER; 305 AllocateSharedMemory( 306 width * height * GpuMemoryBufferImpl::BytesPerPixel(internalformat), 307 peer_handle_, 308 &handle->handle); 309 } 310 311 } // namespace content 312