ipc/chromium/src/chrome/common/child_process_host.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2009 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.
     5 #include "chrome/common/child_process_host.h"
     7 #include "base/compiler_specific.h"
     8 #include "base/logging.h"
     9 #include "base/message_loop.h"
    10 #include "base/process_util.h"
    11 #include "base/singleton.h"
    12 #include "base/waitable_event.h"
    13 #include "mozilla/ipc/ProcessChild.h"
    14 #include "mozilla/ipc/BrowserProcessSubThread.h"
    15 #include "mozilla/ipc/Transport.h"
    16 typedef mozilla::ipc::BrowserProcessSubThread ChromeThread;
    17 #include "chrome/common/ipc_logging.h"
    18 #include "chrome/common/notification_service.h"
    19 #include "chrome/common/notification_type.h"
    20 #include "chrome/common/process_watcher.h"
    21 #include "chrome/common/result_codes.h"
    23 using mozilla::ipc::FileDescriptor;
    25 namespace {
    26 typedef std::list<ChildProcessHost*> ChildProcessList;
    28 // The NotificationTask is used to notify about plugin process connection/
    29 // disconnection. It is needed because the notifications in the
    30 // NotificationService must happen in the main thread.
    31 class ChildNotificationTask : public Task {
    32  public:
    33   ChildNotificationTask(
    34       NotificationType notification_type, ChildProcessInfo* info)
    35       : notification_type_(notification_type), info_(*info) { }
    37   virtual void Run() {
    38     NotificationService::current()->
    39         Notify(notification_type_, NotificationService::AllSources(),
    40                Details<ChildProcessInfo>(&info_));
    41   }
    43  private:
    44   NotificationType notification_type_;
    45   ChildProcessInfo info_;
    46 };
    48 }  // namespace
    52 ChildProcessHost::ChildProcessHost(ProcessType type)
    53     :
    54       ChildProcessInfo(type),
    55       ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
    56       opening_channel_(false),
    57       process_event_(NULL) {
    58   Singleton<ChildProcessList>::get()->push_back(this);
    59 }
    62 ChildProcessHost::~ChildProcessHost() {
    63   Singleton<ChildProcessList>::get()->remove(this);
    65   if (handle()) {
    66     watcher_.StopWatching();
    67     ProcessWatcher::EnsureProcessTerminated(handle());
    69 #if defined(OS_WIN)
    70     // Above call took ownership, so don't want WaitableEvent to assert because
    71     // the handle isn't valid anymore.
    72     process_event_->Release();
    73 #endif
    74   }
    75 }
    77 bool ChildProcessHost::CreateChannel() {
    78   channel_id_ = GenerateRandomChannelID(this);
    79   channel_.reset(new IPC::Channel(
    80       channel_id_, IPC::Channel::MODE_SERVER, &listener_));
    81   if (!channel_->Connect())
    82     return false;
    84   opening_channel_ = true;
    86   return true;
    87 }
    89 bool ChildProcessHost::CreateChannel(FileDescriptor& aFileDescriptor) {
    90   if (channel_.get()) {
    91     channel_->Close();
    92   }
    93   channel_.reset(mozilla::ipc::OpenDescriptor(
    94       aFileDescriptor, IPC::Channel::MODE_SERVER));
    95   channel_->set_listener(&listener_);
    96   if (!channel_->Connect()) {
    97     return false;
    98   }
   100   opening_channel_ = true;
   102   return true;
   103 }
   105 void ChildProcessHost::SetHandle(base::ProcessHandle process) {
   106 #if defined(OS_WIN)
   107   process_event_.reset(new base::WaitableEvent(process));
   109   DCHECK(!handle());
   110   set_handle(process);
   111   watcher_.StartWatching(process_event_.get(), this);
   112 #endif
   113 }
   115 void ChildProcessHost::InstanceCreated() {
   116   Notify(NotificationType::CHILD_INSTANCE_CREATED);
   117 }
   119 bool ChildProcessHost::Send(IPC::Message* msg) {
   120   if (!channel_.get()) {
   121     delete msg;
   122     return false;
   123   }
   124   return channel_->Send(msg);
   125 }
   127 void ChildProcessHost::Notify(NotificationType type) {
   128   MessageLoop* loop = ChromeThread::GetMessageLoop(ChromeThread::IO);
   129   if (!loop)
   130       loop = mozilla::ipc::ProcessChild::message_loop();
   131   if (!loop)
   132       loop = MessageLoop::current();
   133   loop->PostTask(
   134       FROM_HERE, new ChildNotificationTask(type, this));
   135 }
   137 void ChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event) {
   138 #if defined(OS_WIN)
   139   HANDLE object = event->handle();
   140   DCHECK(handle());
   141   DCHECK_EQ(object, handle());
   143   bool did_crash = base::DidProcessCrash(NULL, object);
   144   if (did_crash) {
   145     // Report that this child process crashed.
   146     Notify(NotificationType::CHILD_PROCESS_CRASHED);
   147   }
   148   // Notify in the main loop of the disconnection.
   149   Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED);
   150 #endif
   151 }
   153 ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host)
   154     : host_(host) {
   155 }
   157 void ChildProcessHost::ListenerHook::OnMessageReceived(
   158     const IPC::Message& msg) {
   159 #ifdef IPC_MESSAGE_LOG_ENABLED
   160   IPC::Logging* logger = IPC::Logging::current();
   161   if (msg.type() == IPC_LOGGING_ID) {
   162     logger->OnReceivedLoggingMessage(msg);
   163     return;
   164   }
   166   if (logger->Enabled())
   167     logger->OnPreDispatchMessage(msg);
   168 #endif
   170   bool msg_is_ok = true;
   171   bool handled = false;
   173   if (!handled) {
   174       host_->OnMessageReceived(msg);
   175   }
   177   if (!msg_is_ok)
   178     base::KillProcess(host_->handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
   180 #ifdef IPC_MESSAGE_LOG_ENABLED
   181   if (logger->Enabled())
   182     logger->OnPostDispatchMessage(msg, host_->channel_id_);
   183 #endif
   184 }
   186 void ChildProcessHost::ListenerHook::OnChannelConnected(int32_t peer_pid) {
   187   host_->opening_channel_ = false;
   188   host_->OnChannelConnected(peer_pid);
   190   // Notify in the main loop of the connection.
   191   host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED);
   192 }
   194 void ChildProcessHost::ListenerHook::OnChannelError() {
   195   host_->opening_channel_ = false;
   196   host_->OnChannelError();
   197 }
   199 void ChildProcessHost::ListenerHook::GetQueuedMessages(std::queue<IPC::Message>& queue) {
   200   host_->GetQueuedMessages(queue);
   201 }
   203 ChildProcessHost::Iterator::Iterator() : all_(true) {
   204   iterator_ = Singleton<ChildProcessList>::get()->begin();
   205 }
   207 ChildProcessHost::Iterator::Iterator(ProcessType type)
   208     : all_(false), type_(type) {
   209   iterator_ = Singleton<ChildProcessList>::get()->begin();
   210   if (!Done() && (*iterator_)->type() != type_)
   211     ++(*this);
   212 }
   214 ChildProcessHost* ChildProcessHost::Iterator::operator++() {
   215   do {
   216     ++iterator_;
   217     if (Done())
   218       break;
   220     if (!all_ && (*iterator_)->type() != type_)
   221       continue;
   223     return *iterator_;
   224   } while (true);
   226   return NULL;
   227 }
   229 bool ChildProcessHost::Iterator::Done() {
   230   return iterator_ == Singleton<ChildProcessList>::get()->end();
   231 }

mercurial