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