1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/chrome/common/child_process_host.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,231 @@ 1.4 +// Copyright (c) 2009 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "chrome/common/child_process_host.h" 1.9 + 1.10 +#include "base/compiler_specific.h" 1.11 +#include "base/logging.h" 1.12 +#include "base/message_loop.h" 1.13 +#include "base/process_util.h" 1.14 +#include "base/singleton.h" 1.15 +#include "base/waitable_event.h" 1.16 +#include "mozilla/ipc/ProcessChild.h" 1.17 +#include "mozilla/ipc/BrowserProcessSubThread.h" 1.18 +#include "mozilla/ipc/Transport.h" 1.19 +typedef mozilla::ipc::BrowserProcessSubThread ChromeThread; 1.20 +#include "chrome/common/ipc_logging.h" 1.21 +#include "chrome/common/notification_service.h" 1.22 +#include "chrome/common/notification_type.h" 1.23 +#include "chrome/common/process_watcher.h" 1.24 +#include "chrome/common/result_codes.h" 1.25 + 1.26 +using mozilla::ipc::FileDescriptor; 1.27 + 1.28 +namespace { 1.29 +typedef std::list<ChildProcessHost*> ChildProcessList; 1.30 + 1.31 +// The NotificationTask is used to notify about plugin process connection/ 1.32 +// disconnection. It is needed because the notifications in the 1.33 +// NotificationService must happen in the main thread. 1.34 +class ChildNotificationTask : public Task { 1.35 + public: 1.36 + ChildNotificationTask( 1.37 + NotificationType notification_type, ChildProcessInfo* info) 1.38 + : notification_type_(notification_type), info_(*info) { } 1.39 + 1.40 + virtual void Run() { 1.41 + NotificationService::current()-> 1.42 + Notify(notification_type_, NotificationService::AllSources(), 1.43 + Details<ChildProcessInfo>(&info_)); 1.44 + } 1.45 + 1.46 + private: 1.47 + NotificationType notification_type_; 1.48 + ChildProcessInfo info_; 1.49 +}; 1.50 + 1.51 +} // namespace 1.52 + 1.53 + 1.54 + 1.55 +ChildProcessHost::ChildProcessHost(ProcessType type) 1.56 + : 1.57 + ChildProcessInfo(type), 1.58 + ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), 1.59 + opening_channel_(false), 1.60 + process_event_(NULL) { 1.61 + Singleton<ChildProcessList>::get()->push_back(this); 1.62 +} 1.63 + 1.64 + 1.65 +ChildProcessHost::~ChildProcessHost() { 1.66 + Singleton<ChildProcessList>::get()->remove(this); 1.67 + 1.68 + if (handle()) { 1.69 + watcher_.StopWatching(); 1.70 + ProcessWatcher::EnsureProcessTerminated(handle()); 1.71 + 1.72 +#if defined(OS_WIN) 1.73 + // Above call took ownership, so don't want WaitableEvent to assert because 1.74 + // the handle isn't valid anymore. 1.75 + process_event_->Release(); 1.76 +#endif 1.77 + } 1.78 +} 1.79 + 1.80 +bool ChildProcessHost::CreateChannel() { 1.81 + channel_id_ = GenerateRandomChannelID(this); 1.82 + channel_.reset(new IPC::Channel( 1.83 + channel_id_, IPC::Channel::MODE_SERVER, &listener_)); 1.84 + if (!channel_->Connect()) 1.85 + return false; 1.86 + 1.87 + opening_channel_ = true; 1.88 + 1.89 + return true; 1.90 +} 1.91 + 1.92 +bool ChildProcessHost::CreateChannel(FileDescriptor& aFileDescriptor) { 1.93 + if (channel_.get()) { 1.94 + channel_->Close(); 1.95 + } 1.96 + channel_.reset(mozilla::ipc::OpenDescriptor( 1.97 + aFileDescriptor, IPC::Channel::MODE_SERVER)); 1.98 + channel_->set_listener(&listener_); 1.99 + if (!channel_->Connect()) { 1.100 + return false; 1.101 + } 1.102 + 1.103 + opening_channel_ = true; 1.104 + 1.105 + return true; 1.106 +} 1.107 + 1.108 +void ChildProcessHost::SetHandle(base::ProcessHandle process) { 1.109 +#if defined(OS_WIN) 1.110 + process_event_.reset(new base::WaitableEvent(process)); 1.111 + 1.112 + DCHECK(!handle()); 1.113 + set_handle(process); 1.114 + watcher_.StartWatching(process_event_.get(), this); 1.115 +#endif 1.116 +} 1.117 + 1.118 +void ChildProcessHost::InstanceCreated() { 1.119 + Notify(NotificationType::CHILD_INSTANCE_CREATED); 1.120 +} 1.121 + 1.122 +bool ChildProcessHost::Send(IPC::Message* msg) { 1.123 + if (!channel_.get()) { 1.124 + delete msg; 1.125 + return false; 1.126 + } 1.127 + return channel_->Send(msg); 1.128 +} 1.129 + 1.130 +void ChildProcessHost::Notify(NotificationType type) { 1.131 + MessageLoop* loop = ChromeThread::GetMessageLoop(ChromeThread::IO); 1.132 + if (!loop) 1.133 + loop = mozilla::ipc::ProcessChild::message_loop(); 1.134 + if (!loop) 1.135 + loop = MessageLoop::current(); 1.136 + loop->PostTask( 1.137 + FROM_HERE, new ChildNotificationTask(type, this)); 1.138 +} 1.139 + 1.140 +void ChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event) { 1.141 +#if defined(OS_WIN) 1.142 + HANDLE object = event->handle(); 1.143 + DCHECK(handle()); 1.144 + DCHECK_EQ(object, handle()); 1.145 + 1.146 + bool did_crash = base::DidProcessCrash(NULL, object); 1.147 + if (did_crash) { 1.148 + // Report that this child process crashed. 1.149 + Notify(NotificationType::CHILD_PROCESS_CRASHED); 1.150 + } 1.151 + // Notify in the main loop of the disconnection. 1.152 + Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED); 1.153 +#endif 1.154 +} 1.155 + 1.156 +ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) 1.157 + : host_(host) { 1.158 +} 1.159 + 1.160 +void ChildProcessHost::ListenerHook::OnMessageReceived( 1.161 + const IPC::Message& msg) { 1.162 +#ifdef IPC_MESSAGE_LOG_ENABLED 1.163 + IPC::Logging* logger = IPC::Logging::current(); 1.164 + if (msg.type() == IPC_LOGGING_ID) { 1.165 + logger->OnReceivedLoggingMessage(msg); 1.166 + return; 1.167 + } 1.168 + 1.169 + if (logger->Enabled()) 1.170 + logger->OnPreDispatchMessage(msg); 1.171 +#endif 1.172 + 1.173 + bool msg_is_ok = true; 1.174 + bool handled = false; 1.175 + 1.176 + if (!handled) { 1.177 + host_->OnMessageReceived(msg); 1.178 + } 1.179 + 1.180 + if (!msg_is_ok) 1.181 + base::KillProcess(host_->handle(), ResultCodes::KILLED_BAD_MESSAGE, false); 1.182 + 1.183 +#ifdef IPC_MESSAGE_LOG_ENABLED 1.184 + if (logger->Enabled()) 1.185 + logger->OnPostDispatchMessage(msg, host_->channel_id_); 1.186 +#endif 1.187 +} 1.188 + 1.189 +void ChildProcessHost::ListenerHook::OnChannelConnected(int32_t peer_pid) { 1.190 + host_->opening_channel_ = false; 1.191 + host_->OnChannelConnected(peer_pid); 1.192 + 1.193 + // Notify in the main loop of the connection. 1.194 + host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED); 1.195 +} 1.196 + 1.197 +void ChildProcessHost::ListenerHook::OnChannelError() { 1.198 + host_->opening_channel_ = false; 1.199 + host_->OnChannelError(); 1.200 +} 1.201 + 1.202 +void ChildProcessHost::ListenerHook::GetQueuedMessages(std::queue<IPC::Message>& queue) { 1.203 + host_->GetQueuedMessages(queue); 1.204 +} 1.205 + 1.206 +ChildProcessHost::Iterator::Iterator() : all_(true) { 1.207 + iterator_ = Singleton<ChildProcessList>::get()->begin(); 1.208 +} 1.209 + 1.210 +ChildProcessHost::Iterator::Iterator(ProcessType type) 1.211 + : all_(false), type_(type) { 1.212 + iterator_ = Singleton<ChildProcessList>::get()->begin(); 1.213 + if (!Done() && (*iterator_)->type() != type_) 1.214 + ++(*this); 1.215 +} 1.216 + 1.217 +ChildProcessHost* ChildProcessHost::Iterator::operator++() { 1.218 + do { 1.219 + ++iterator_; 1.220 + if (Done()) 1.221 + break; 1.222 + 1.223 + if (!all_ && (*iterator_)->type() != type_) 1.224 + continue; 1.225 + 1.226 + return *iterator_; 1.227 + } while (true); 1.228 + 1.229 + return NULL; 1.230 +} 1.231 + 1.232 +bool ChildProcessHost::Iterator::Done() { 1.233 + return iterator_ == Singleton<ChildProcessList>::get()->end(); 1.234 +}