diff options
Diffstat (limited to 'chrome/common/child_process_host.cc')
-rw-r--r-- | chrome/common/child_process_host.cc | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/chrome/common/child_process_host.cc b/chrome/common/child_process_host.cc new file mode 100644 index 0000000..14f2c8c --- /dev/null +++ b/chrome/common/child_process_host.cc @@ -0,0 +1,180 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/child_process_host.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/singleton.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/ipc_logging.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" +#include "chrome/common/process_watcher.h" + +typedef std::list<ChildProcessInfo*> ChildProcessList; + +// The NotificationTask is used to notify about plugin process connection/ +// disconnection. It is needed because the notifications in the +// NotificationService must happen in the main thread. +class ChildNotificationTask : public Task { + public: + ChildNotificationTask( + NotificationType notification_type, ChildProcessInfo* info) + : notification_type_(notification_type), info_(*info) { } + + virtual void Run() { + NotificationService::current()-> + Notify(notification_type_, NotificationService::AllSources(), + Details<ChildProcessInfo>(&info_)); + } + + private: + NotificationType notification_type_; + ChildProcessInfo info_; +}; + + +ChildProcessHost::ChildProcessHost( + ProcessType type, MessageLoop* main_message_loop) + : ChildProcessInfo(type), + main_message_loop_(main_message_loop), + opening_channel_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)) { + Singleton<ChildProcessList>::get()->push_back(this); +} + + +ChildProcessHost::~ChildProcessHost() { + Singleton<ChildProcessList>::get()->remove(this); + + if (handle()) { + watcher_.StopWatching(); + ProcessWatcher::EnsureProcessTerminated(handle()); + } +} + +bool ChildProcessHost::CreateChannel() { + channel_id_ = GenerateRandomChannelID(this); + channel_.reset(new IPC::Channel( + channel_id_, IPC::Channel::MODE_SERVER, &listener_)); + if (!channel_->Connect()) + return false; + + opening_channel_ = true; + + return true; +} + +void ChildProcessHost::SetHandle(base::ProcessHandle process) { + DCHECK(handle() == NULL); + set_handle(process); + watcher_.StartWatching(process, this); +} + +void ChildProcessHost::InstanceCreated() { + Notify(NotificationType::CHILD_INSTANCE_CREATED); +} + +bool ChildProcessHost::Send(IPC::Message* msg) { + if (!channel_.get()) { + delete msg; + return false; + } + return channel_->Send(msg); +} + +void ChildProcessHost::Notify(NotificationType type) { + main_message_loop_->PostTask( + FROM_HERE, new ChildNotificationTask(type, this)); +} + +void ChildProcessHost::OnObjectSignaled(HANDLE object) { + DCHECK(handle()); + DCHECK_EQ(object, handle()); + + bool did_crash = base::DidProcessCrash(object); + if (did_crash) { + // Report that this child process crashed. + Notify(NotificationType::CHILD_PROCESS_CRASHED); + } + // Notify in the main loop of the disconnection. + Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED); + + delete this; +} + + + +ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host) + : host_(host) { +} + +void ChildProcessHost::ListenerHook::OnMessageReceived(const IPC::Message& msg) { +#ifdef IPC_MESSAGE_LOG_ENABLED + IPC::Logging* logger = IPC::Logging::current(); + if (msg.type() == IPC_LOGGING_ID) { + logger->OnReceivedLoggingMessage(msg); + return; + } + + if (logger->Enabled()) + logger->OnPreDispatchMessage(msg); +#endif + + host_->OnMessageReceived(msg); + +#ifdef IPC_MESSAGE_LOG_ENABLED + if (logger->Enabled()) + logger->OnPostDispatchMessage(msg, host_->channel_id_); +#endif +} + +void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) { + host_->opening_channel_ = false; + host_->OnChannelConnected(peer_pid); + + // Notify in the main loop of the connection. + host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED); +} + +void ChildProcessHost::ListenerHook::OnChannelError() { + host_->opening_channel_ = false; + host_->OnChannelError(); +} + + +ChildProcessHost::Iterator::Iterator() : all_(true) { + iterator_ = Singleton<ChildProcessList>::get()->begin(); + DCHECK(MessageLoop::current() == + ChromeThread::GetMessageLoop(ChromeThread::IO)) << + "ChildProcessInfo::Iterator must be used on the IO thread."; +} + +ChildProcessHost::Iterator::Iterator(ProcessType type) + : all_(false), type_(type) { + iterator_ = Singleton<ChildProcessList>::get()->begin(); + DCHECK(MessageLoop::current() == + ChromeThread::GetMessageLoop(ChromeThread::IO)) << + "ChildProcessInfo::Iterator must be used on the IO thread."; +} + +ChildProcessInfo* ChildProcessHost::Iterator::operator++() { + do { + ++iterator_; + if (Done()) + break; + + if (!all_ && (*iterator_)->type() != type_) + continue; + + return *iterator_; + } while (true); + + return NULL; +} + +bool ChildProcessHost::Iterator::Done() { + return iterator_ == Singleton<ChildProcessList>::get()->end(); +} |