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.
4 :
5 : #include "chrome/common/child_process_host.h"
6 :
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 : typedef mozilla::ipc::BrowserProcessSubThread ChromeThread;
16 : #include "chrome/common/ipc_logging.h"
17 : #include "chrome/common/notification_service.h"
18 : #include "chrome/common/notification_type.h"
19 : #include "chrome/common/process_watcher.h"
20 : #include "chrome/common/result_codes.h"
21 :
22 :
23 : namespace {
24 : typedef std::list<ChildProcessHost*> ChildProcessList;
25 :
26 : // The NotificationTask is used to notify about plugin process connection/
27 : // disconnection. It is needed because the notifications in the
28 : // NotificationService must happen in the main thread.
29 0 : class ChildNotificationTask : public Task {
30 : public:
31 0 : ChildNotificationTask(
32 : NotificationType notification_type, ChildProcessInfo* info)
33 0 : : notification_type_(notification_type), info_(*info) { }
34 :
35 0 : virtual void Run() {
36 : NotificationService::current()->
37 0 : Notify(notification_type_, NotificationService::AllSources(),
38 0 : Details<ChildProcessInfo>(&info_));
39 0 : }
40 :
41 : private:
42 : NotificationType notification_type_;
43 : ChildProcessInfo info_;
44 : };
45 :
46 : } // namespace
47 :
48 :
49 :
50 0 : ChildProcessHost::ChildProcessHost(
51 : ProcessType type, ResourceDispatcherHost* resource_dispatcher_host)
52 : :
53 : ChildProcessInfo(type),
54 : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)),
55 : resource_dispatcher_host_(resource_dispatcher_host),
56 : opening_channel_(false),
57 0 : process_event_(NULL) {
58 0 : Singleton<ChildProcessList>::get()->push_back(this);
59 0 : }
60 :
61 :
62 0 : ChildProcessHost::~ChildProcessHost() {
63 0 : Singleton<ChildProcessList>::get()->remove(this);
64 :
65 0 : if (handle()) {
66 0 : watcher_.StopWatching();
67 0 : ProcessWatcher::EnsureProcessTerminated(handle());
68 :
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 0 : }
76 :
77 0 : bool ChildProcessHost::CreateChannel() {
78 0 : channel_id_ = GenerateRandomChannelID(this);
79 : channel_.reset(new IPC::Channel(
80 0 : channel_id_, IPC::Channel::MODE_SERVER, &listener_));
81 0 : if (!channel_->Connect())
82 0 : return false;
83 :
84 0 : opening_channel_ = true;
85 :
86 0 : return true;
87 : }
88 :
89 0 : void ChildProcessHost::SetHandle(base::ProcessHandle process) {
90 : #if defined(OS_WIN)
91 : process_event_.reset(new base::WaitableEvent(process));
92 :
93 : DCHECK(!handle());
94 : set_handle(process);
95 : watcher_.StartWatching(process_event_.get(), this);
96 : #endif
97 0 : }
98 :
99 0 : void ChildProcessHost::InstanceCreated() {
100 0 : Notify(NotificationType::CHILD_INSTANCE_CREATED);
101 0 : }
102 :
103 0 : bool ChildProcessHost::Send(IPC::Message* msg) {
104 0 : if (!channel_.get()) {
105 0 : delete msg;
106 0 : return false;
107 : }
108 0 : return channel_->Send(msg);
109 : }
110 :
111 0 : void ChildProcessHost::Notify(NotificationType type) {
112 0 : MessageLoop* loop = ChromeThread::GetMessageLoop(ChromeThread::IO);
113 0 : if (!loop)
114 0 : loop = mozilla::ipc::ProcessChild::message_loop();
115 0 : if (!loop)
116 0 : loop = MessageLoop::current();
117 : loop->PostTask(
118 0 : FROM_HERE, new ChildNotificationTask(type, this));
119 0 : }
120 :
121 0 : void ChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event) {
122 : #if defined(OS_WIN)
123 : HANDLE object = event->handle();
124 : DCHECK(handle());
125 : DCHECK_EQ(object, handle());
126 :
127 : bool did_crash = base::DidProcessCrash(NULL, object);
128 : if (did_crash) {
129 : // Report that this child process crashed.
130 : Notify(NotificationType::CHILD_PROCESS_CRASHED);
131 : }
132 : // Notify in the main loop of the disconnection.
133 : Notify(NotificationType::CHILD_PROCESS_HOST_DISCONNECTED);
134 : #endif
135 0 : }
136 :
137 0 : ChildProcessHost::ListenerHook::ListenerHook(ChildProcessHost* host)
138 0 : : host_(host) {
139 0 : }
140 :
141 0 : void ChildProcessHost::ListenerHook::OnMessageReceived(
142 : const IPC::Message& msg) {
143 : #ifdef IPC_MESSAGE_LOG_ENABLED
144 0 : IPC::Logging* logger = IPC::Logging::current();
145 0 : if (msg.type() == IPC_LOGGING_ID) {
146 0 : logger->OnReceivedLoggingMessage(msg);
147 0 : return;
148 : }
149 :
150 0 : if (logger->Enabled())
151 0 : logger->OnPreDispatchMessage(msg);
152 : #endif
153 :
154 0 : bool msg_is_ok = true;
155 0 : bool handled = false;
156 :
157 0 : if (!handled) {
158 0 : host_->OnMessageReceived(msg);
159 : }
160 :
161 0 : if (!msg_is_ok)
162 0 : base::KillProcess(host_->handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
163 :
164 : #ifdef IPC_MESSAGE_LOG_ENABLED
165 0 : if (logger->Enabled())
166 0 : logger->OnPostDispatchMessage(msg, host_->channel_id_);
167 : #endif
168 : }
169 :
170 0 : void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) {
171 0 : host_->opening_channel_ = false;
172 0 : host_->OnChannelConnected(peer_pid);
173 :
174 : // Notify in the main loop of the connection.
175 0 : host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED);
176 0 : }
177 :
178 0 : void ChildProcessHost::ListenerHook::OnChannelError() {
179 0 : host_->opening_channel_ = false;
180 0 : host_->OnChannelError();
181 0 : }
182 :
183 :
184 0 : ChildProcessHost::Iterator::Iterator() : all_(true) {
185 0 : iterator_ = Singleton<ChildProcessList>::get()->begin();
186 0 : }
187 :
188 0 : ChildProcessHost::Iterator::Iterator(ProcessType type)
189 0 : : all_(false), type_(type) {
190 0 : iterator_ = Singleton<ChildProcessList>::get()->begin();
191 0 : if (!Done() && (*iterator_)->type() != type_)
192 0 : ++(*this);
193 0 : }
194 :
195 0 : ChildProcessHost* ChildProcessHost::Iterator::operator++() {
196 0 : do {
197 0 : ++iterator_;
198 0 : if (Done())
199 : break;
200 :
201 0 : if (!all_ && (*iterator_)->type() != type_)
202 0 : continue;
203 :
204 0 : return *iterator_;
205 : } while (true);
206 :
207 0 : return NULL;
208 : }
209 :
210 0 : bool ChildProcessHost::Iterator::Done() {
211 0 : return iterator_ == Singleton<ChildProcessList>::get()->end();
212 : }
|