blob: e9a2c4e648dd58322a6e3d3d1568161124553d23 [file] [log] [blame]
[email protected]a08ebea2011-02-13 17:50:201// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]c2932f5e2010-11-03 03:22:332// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/plugin_dispatcher.h"
6
7#include <map>
8
[email protected]709a847e2010-11-10 01:16:119#include "base/compiler_specific.h"
[email protected]c2932f5e2010-11-03 03:22:3310#include "base/logging.h"
11#include "ipc/ipc_message.h"
12#include "ipc/ipc_sync_channel.h"
[email protected]366ae242011-05-10 02:23:5813#include "base/debug/trace_event.h"
[email protected]c2932f5e2010-11-03 03:22:3314#include "ppapi/c/pp_errors.h"
15#include "ppapi/proxy/interface_proxy.h"
[email protected]2cc062242011-03-10 21:16:3416#include "ppapi/proxy/plugin_message_filter.h"
[email protected]6239d342011-05-06 22:55:4717#include "ppapi/proxy/plugin_resource_tracker.h"
[email protected]c2932f5e2010-11-03 03:22:3318#include "ppapi/proxy/plugin_var_serialization_rules.h"
19#include "ppapi/proxy/ppapi_messages.h"
[email protected]9815108e2011-05-27 21:50:2820#include "ppapi/proxy/ppb_char_set_proxy.h"
21#include "ppapi/proxy/ppb_cursor_control_proxy.h"
[email protected]d259a8e2011-05-18 22:31:0922#include "ppapi/proxy/ppb_font_proxy.h"
[email protected]c2932f5e2010-11-03 03:22:3323#include "ppapi/proxy/ppp_class_proxy.h"
[email protected]6239d342011-05-06 22:55:4724#include "ppapi/proxy/resource_creation_proxy.h"
25#include "ppapi/shared_impl/tracker_base.h"
[email protected]c2932f5e2010-11-03 03:22:3326
[email protected]a08ebea2011-02-13 17:50:2027#if defined(OS_POSIX)
28#include "base/eintr_wrapper.h"
29#include "ipc/ipc_channel_posix.h"
30#endif
31
[email protected]c2932f5e2010-11-03 03:22:3332namespace pp {
33namespace proxy {
34
35namespace {
36
[email protected]465faa22011-02-08 16:31:4637typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap;
38InstanceToDispatcherMap* g_instance_to_dispatcher = NULL;
[email protected]c2932f5e2010-11-03 03:22:3339
[email protected]c2932f5e2010-11-03 03:22:3340} // namespace
41
[email protected]5d84d012010-12-02 17:17:2142PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle,
[email protected]a08ebea2011-02-13 17:50:2043 GetInterfaceFunc get_interface)
[email protected]d259a8e2011-05-18 22:31:0944 : Dispatcher(remote_process_handle, get_interface),
[email protected]208aad792011-05-26 19:05:2845 plugin_delegate_(NULL),
46 received_preferences_(false) {
[email protected]4614f192011-01-21 00:26:4347 SetSerializationRules(new PluginVarSerializationRules);
[email protected]c2932f5e2010-11-03 03:22:3348
49 // As a plugin, we always support the PPP_Class interface. There's no
50 // GetInterface call or name for it, so we insert it into our table now.
[email protected]465faa22011-02-08 16:31:4651 target_proxies_[INTERFACE_ID_PPP_CLASS].reset(new PPP_Class_Proxy(this));
[email protected]6239d342011-05-06 22:55:4752
[email protected]55cdf6052011-05-13 19:22:5353 ::ppapi::TrackerBase::Init(
[email protected]6239d342011-05-06 22:55:4754 &PluginResourceTracker::GetTrackerBaseInstance);
[email protected]c2932f5e2010-11-03 03:22:3355}
56
57PluginDispatcher::~PluginDispatcher() {
[email protected]c2932f5e2010-11-03 03:22:3358}
59
60// static
[email protected]4614f192011-01-21 00:26:4361PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) {
[email protected]465faa22011-02-08 16:31:4662 if (!g_instance_to_dispatcher)
63 return NULL;
64 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
65 instance);
66 if (found == g_instance_to_dispatcher->end())
67 return NULL;
68 return found->second;
[email protected]4614f192011-01-21 00:26:4369}
70
[email protected]a08ebea2011-02-13 17:50:2071// static
72const void* PluginDispatcher::GetInterfaceFromDispatcher(
73 const char* interface) {
74 // All interfaces the plugin requests of the browser are "PPB".
75 const InterfaceProxy::Info* info = GetPPBInterfaceInfo(interface);
76 if (!info)
77 return NULL;
[email protected]84396dbc2011-04-14 06:33:4278 return info->interface_ptr;
[email protected]a08ebea2011-02-13 17:50:2079}
80
[email protected]e2614c62011-04-16 22:12:4581bool PluginDispatcher::InitPluginWithChannel(
[email protected]d259a8e2011-05-18 22:31:0982 PluginDelegate* delegate,
[email protected]2cc062242011-03-10 21:16:3483 const IPC::ChannelHandle& channel_handle,
84 bool is_client) {
85 if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client))
86 return false;
[email protected]d259a8e2011-05-18 22:31:0987 plugin_delegate_ = delegate;
[email protected]2cc062242011-03-10 21:16:3488
89 // The message filter will intercept and process certain messages directly
90 // on the I/O thread.
91 channel()->AddFilter(
92 new PluginMessageFilter(delegate->GetGloballySeenInstanceIDSet()));
93 return true;
94}
95
[email protected]7cf40912010-12-09 18:25:0396bool PluginDispatcher::IsPlugin() const {
97 return true;
98}
99
[email protected]b00bbb32011-03-30 19:02:14100bool PluginDispatcher::Send(IPC::Message* msg) {
[email protected]366ae242011-05-10 02:23:58101 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::Send",
102 "Class", IPC_MESSAGE_ID_CLASS(msg->type()),
103 "Line", IPC_MESSAGE_ID_LINE(msg->type()));
[email protected]b00bbb32011-03-30 19:02:14104 // We always want plugin->renderer messages to arrive in-order. If some sync
105 // and some async messages are send in response to a synchronous
106 // renderer->plugin call, the sync reply will be processed before the async
107 // reply, and everything will be confused.
108 //
109 // Allowing all async messages to unblock the renderer means more reentrancy
110 // there but gives correct ordering.
111 msg->set_unblock(true);
112 return Dispatcher::Send(msg);
113}
114
[email protected]a95986a82010-12-24 06:19:28115bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) {
[email protected]366ae242011-05-10 02:23:58116 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived",
117 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
118 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
[email protected]465faa22011-02-08 16:31:46119 // Handle common control messages.
120 if (Dispatcher::OnMessageReceived(msg))
121 return true;
122
[email protected]c2932f5e2010-11-03 03:22:33123 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
124 // Handle some plugin-specific control messages.
[email protected]a95986a82010-12-24 06:19:28125 bool handled = true;
[email protected]c2932f5e2010-11-03 03:22:33126 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg)
[email protected]465faa22011-02-08 16:31:46127 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface)
[email protected]208aad792011-05-26 19:05:28128 IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences)
[email protected]c2932f5e2010-11-03 03:22:33129 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28130 return handled;
[email protected]c2932f5e2010-11-03 03:22:33131 }
132
[email protected]465faa22011-02-08 16:31:46133 if (msg.routing_id() <= 0 && msg.routing_id() >= INTERFACE_ID_COUNT) {
134 // Host is sending us garbage. Since it's supposed to be trusted, this
135 // isn't supposed to happen. Crash here in all builds in case the renderer
136 // is compromised.
137 CHECK(false);
138 return true;
139 }
140
141 // There are two cases:
142 //
143 // * The first case is that the host is calling a PPP interface. It will
144 // always do a check for the interface before sending messages, and this
145 // will create the necessary interface proxy at that time. So when we
146 // actually receive a message, we know such a proxy will exist.
147 //
148 // * The second case is that the host is sending a response to the plugin
149 // side of a PPB interface (some, like the URL loader, have complex
150 // response messages). Since the host is trusted and not supposed to be
151 // doing silly things, we can just create a PPB proxy project on demand the
152 // first time it's needed.
153
154 InterfaceProxy* proxy = target_proxies_[msg.routing_id()].get();
155 if (!proxy) {
156 // Handle the first time the host calls a PPB reply interface by
157 // autocreating it.
158 const InterfaceProxy::Info* info = GetPPBInterfaceInfo(
159 static_cast<InterfaceID>(msg.routing_id()));
160 if (!info) {
161 NOTREACHED();
162 return true;
163 }
164 proxy = info->create_proxy(this, NULL);
165 target_proxies_[info->id].reset(proxy);
166 }
167
168 return proxy->OnMessageReceived(msg);
[email protected]c2932f5e2010-11-03 03:22:33169}
170
[email protected]a08ebea2011-02-13 17:50:20171void PluginDispatcher::OnChannelError() {
[email protected]4f15d2842011-02-15 17:36:33172 Dispatcher::OnChannelError();
173
[email protected]4b417e52011-04-18 22:51:08174 // The renderer has crashed or exited. This channel and all instances
175 // associated with it are no longer valid.
[email protected]a08ebea2011-02-13 17:50:20176 ForceFreeAllInstances();
177 // TODO(brettw) free resources too!
178 delete this;
179}
180
[email protected]f56279c2011-02-02 18:12:31181void PluginDispatcher::DidCreateInstance(PP_Instance instance) {
[email protected]465faa22011-02-08 16:31:46182 if (!g_instance_to_dispatcher)
183 g_instance_to_dispatcher = new InstanceToDispatcherMap;
184 (*g_instance_to_dispatcher)[instance] = this;
185
[email protected]f56279c2011-02-02 18:12:31186 instance_map_[instance] = InstanceData();
187}
188
189void PluginDispatcher::DidDestroyInstance(PP_Instance instance) {
190 InstanceDataMap::iterator it = instance_map_.find(instance);
191 if (it != instance_map_.end())
192 instance_map_.erase(it);
[email protected]465faa22011-02-08 16:31:46193
194 if (g_instance_to_dispatcher) {
195 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
196 instance);
197 if (found != g_instance_to_dispatcher->end()) {
198 DCHECK(found->second == this);
199 g_instance_to_dispatcher->erase(found);
200 } else {
201 NOTREACHED();
202 }
203 }
[email protected]f56279c2011-02-02 18:12:31204}
205
206InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) {
207 InstanceDataMap::iterator it = instance_map_.find(instance);
208 return (it == instance_map_.end()) ? NULL : &it->second;
209}
210
[email protected]7a1f7c6f2011-05-10 21:17:48211void PluginDispatcher::PostToWebKitThread(
212 const tracked_objects::Location& from_here,
213 const base::Closure& task) {
[email protected]d259a8e2011-05-18 22:31:09214 return plugin_delegate_->PostToWebKitThread(from_here, task);
215}
216
217bool PluginDispatcher::SendToBrowser(IPC::Message* msg) {
218 return plugin_delegate_->SendToBrowser(msg);
[email protected]7a1f7c6f2011-05-10 21:17:48219}
220
[email protected]55cdf6052011-05-13 19:22:53221ppapi::WebKitForwarding* PluginDispatcher::GetWebKitForwarding() {
[email protected]d259a8e2011-05-18 22:31:09222 return plugin_delegate_->GetWebKitForwarding();
[email protected]7a1f7c6f2011-05-10 21:17:48223}
224
[email protected]55cdf6052011-05-13 19:22:53225::ppapi::FunctionGroupBase* PluginDispatcher::GetFunctionAPI(
[email protected]6239d342011-05-06 22:55:47226 pp::proxy::InterfaceID id) {
[email protected]9815108e2011-05-27 21:50:28227 scoped_ptr< ::ppapi::FunctionGroupBase >& proxy = function_proxies_[id];
[email protected]6239d342011-05-06 22:55:47228
[email protected]9815108e2011-05-27 21:50:28229 if (proxy.get())
230 return proxy.get();
[email protected]6239d342011-05-06 22:55:47231
[email protected]9815108e2011-05-27 21:50:28232 if (id == INTERFACE_ID_PPB_CHAR_SET)
233 proxy.reset(new PPB_CharSet_Proxy(this, NULL));
234 else if(id == INTERFACE_ID_PPB_CURSORCONTROL)
235 proxy.reset(new PPB_CursorControl_Proxy(this, NULL));
236 else if (id == INTERFACE_ID_PPB_FONT)
237 proxy.reset(new PPB_Font_Proxy(this, NULL));
238 else if (id == INTERFACE_ID_RESOURCE_CREATION)
239 proxy.reset(new ResourceCreationProxy(this));
240
241 return proxy.get();
[email protected]6239d342011-05-06 22:55:47242}
243
[email protected]a08ebea2011-02-13 17:50:20244void PluginDispatcher::ForceFreeAllInstances() {
[email protected]4f15d2842011-02-15 17:36:33245 if (!g_instance_to_dispatcher)
246 return;
247
248 // Iterating will remove each item from the map, so we need to make a copy
249 // to avoid things changing out from under is.
250 InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher;
251 for (InstanceToDispatcherMap::iterator i = temp_map.begin();
252 i != temp_map.end(); ++i) {
253 if (i->second == this) {
254 // Synthesize an "instance destroyed" message, this will notify the
255 // plugin and also remove it from our list of tracked plugins.
256 OnMessageReceived(
257 PpapiMsg_PPPInstance_DidDestroy(INTERFACE_ID_PPP_INSTANCE, i->first));
258 }
259 }
[email protected]176c73922010-12-03 17:32:19260}
261
[email protected]465faa22011-02-08 16:31:46262void PluginDispatcher::OnMsgSupportsInterface(
263 const std::string& interface_name,
264 bool* result) {
265 *result = false;
266
267 // Setup a proxy for receiving the messages from this interface.
268 const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface_name);
269 if (!info)
270 return; // Interface not supported by proxy.
271
272 // Check for a cached result.
273 if (target_proxies_[info->id].get()) {
274 *result = true;
275 return;
276 }
277
278 // Query the plugin & cache the result.
279 const void* interface_functions = GetLocalInterface(interface_name.c_str());
280 if (!interface_functions)
281 return;
282 target_proxies_[info->id].reset(
283 info->create_proxy(this, interface_functions));
284 *result = true;
285}
286
[email protected]208aad792011-05-26 19:05:28287void PluginDispatcher::OnMsgSetPreferences(const ::ppapi::Preferences& prefs) {
288 // The renderer may send us preferences more than once (currently this
289 // happens every time a new plugin instance is created). Since we don't have
290 // a way to signal to the plugin that the preferences have changed, changing
291 // the default fonts and such in the middle of a running plugin could be
292 // confusing to it. As a result, we never allow the preferences to be changed
293 // once they're set. The user will have to restart to get new font prefs
294 // propogated to plugins.
295 if (!received_preferences_) {
296 received_preferences_ = true;
297 preferences_ = prefs;
298 }
299}
300
[email protected]c2932f5e2010-11-03 03:22:33301} // namespace proxy
302} // namespace pp
303