blob: 8dbca8d23d38d4a8aff6d8c7bce345d7cfa66746 [file] [log] [blame]
[email protected]4c41d3f2012-02-15 01:44:471// Copyright (c) 2012 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"
[email protected]aabfa652011-07-13 23:28:4411#include "base/message_loop.h"
[email protected]c2932f5e2010-11-03 03:22:3312#include "ipc/ipc_message.h"
13#include "ipc/ipc_sync_channel.h"
[email protected]366ae242011-05-10 02:23:5814#include "base/debug/trace_event.h"
[email protected]c2932f5e2010-11-03 03:22:3315#include "ppapi/c/pp_errors.h"
[email protected]e8f07ac2012-01-03 17:43:3616#include "ppapi/c/ppp_instance.h"
[email protected]f5118812012-08-24 19:54:3017#include "ppapi/proxy/gamepad_resource.h"
[email protected]5c966022011-09-13 18:09:3718#include "ppapi/proxy/interface_list.h"
[email protected]c2932f5e2010-11-03 03:22:3319#include "ppapi/proxy/interface_proxy.h"
[email protected]2cc062242011-03-10 21:16:3420#include "ppapi/proxy/plugin_message_filter.h"
[email protected]6239d342011-05-06 22:55:4721#include "ppapi/proxy/plugin_resource_tracker.h"
[email protected]c2932f5e2010-11-03 03:22:3322#include "ppapi/proxy/plugin_var_serialization_rules.h"
23#include "ppapi/proxy/ppapi_messages.h"
[email protected]ceadc392011-06-15 23:04:2424#include "ppapi/proxy/ppb_instance_proxy.h"
[email protected]c2932f5e2010-11-03 03:22:3325#include "ppapi/proxy/ppp_class_proxy.h"
[email protected]6239d342011-05-06 22:55:4726#include "ppapi/proxy/resource_creation_proxy.h"
[email protected]eccf80312012-07-14 15:43:4227#include "ppapi/proxy/resource_message_params.h"
28#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]4c41d3f2012-02-15 01:44:4729#include "ppapi/shared_impl/proxy_lock.h"
[email protected]7f8b26b2011-08-18 15:41:0130#include "ppapi/shared_impl/resource.h"
[email protected]c2932f5e2010-11-03 03:22:3331
[email protected]339fbcff2012-02-29 16:10:3232#if defined(OS_POSIX) && !defined(OS_NACL)
[email protected]a08ebea2011-02-13 17:50:2033#include "base/eintr_wrapper.h"
34#include "ipc/ipc_channel_posix.h"
35#endif
36
[email protected]4d2efd22011-08-18 21:58:0237namespace ppapi {
[email protected]c2932f5e2010-11-03 03:22:3338namespace proxy {
39
40namespace {
41
[email protected]465faa22011-02-08 16:31:4642typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap;
43InstanceToDispatcherMap* g_instance_to_dispatcher = NULL;
[email protected]c2932f5e2010-11-03 03:22:3344
[email protected]a9b16dd2012-01-31 05:00:2645typedef std::set<PluginDispatcher*> DispatcherSet;
46DispatcherSet* g_live_dispatchers = NULL;
47
[email protected]c2932f5e2010-11-03 03:22:3348} // namespace
49
[email protected]06e0a342011-09-27 04:24:3050InstanceData::InstanceData()
[email protected]a8e72142012-08-21 17:24:2051 : flash_fullscreen(PP_FALSE),
52 is_request_surrounding_text_pending(false),
53 should_do_request_surrounding_text(false) {
[email protected]c7bf7452011-09-12 21:31:5054}
55
[email protected]0f41c012011-10-21 19:49:2056InstanceData::~InstanceData() {
57 // Run any pending mouse lock callback to prevent leaks.
[email protected]aed96532012-06-23 14:27:4258 if (mouse_lock_callback)
59 mouse_lock_callback->Abort();
[email protected]0f41c012011-10-21 19:49:2060}
61
[email protected]f0ecb552012-05-11 22:09:1162PluginDispatcher::PluginDispatcher(PP_GetInterface_Func get_interface,
[email protected]bc2eeb42012-05-02 22:35:5363 bool incognito)
[email protected]f0ecb552012-05-11 22:09:1164 : Dispatcher(get_interface),
[email protected]208aad792011-05-26 19:05:2865 plugin_delegate_(NULL),
[email protected]373a95a2011-07-01 16:58:1466 received_preferences_(false),
[email protected]bc2eeb42012-05-02 22:35:5367 plugin_dispatcher_id_(0),
68 incognito_(incognito) {
[email protected]67600b92012-03-10 06:51:4869 SetSerializationRules(new PluginVarSerializationRules(AsWeakPtr()));
[email protected]a9b16dd2012-01-31 05:00:2670
71 if (!g_live_dispatchers)
72 g_live_dispatchers = new DispatcherSet;
73 g_live_dispatchers->insert(this);
[email protected]c2932f5e2010-11-03 03:22:3374}
75
76PluginDispatcher::~PluginDispatcher() {
[email protected]373a95a2011-07-01 16:58:1477 if (plugin_delegate_)
78 plugin_delegate_->Unregister(plugin_dispatcher_id_);
[email protected]a9b16dd2012-01-31 05:00:2679
80 g_live_dispatchers->erase(this);
81 if (g_live_dispatchers->empty()) {
82 delete g_live_dispatchers;
83 g_live_dispatchers = NULL;
84 }
[email protected]c2932f5e2010-11-03 03:22:3385}
86
87// static
[email protected]4614f192011-01-21 00:26:4388PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) {
[email protected]465faa22011-02-08 16:31:4689 if (!g_instance_to_dispatcher)
90 return NULL;
91 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
92 instance);
93 if (found == g_instance_to_dispatcher->end())
94 return NULL;
95 return found->second;
[email protected]4614f192011-01-21 00:26:4396}
97
[email protected]a08ebea2011-02-13 17:50:2098// static
[email protected]7f8b26b2011-08-18 15:41:0199PluginDispatcher* PluginDispatcher::GetForResource(const Resource* resource) {
100 return GetForInstance(resource->pp_instance());
101}
102
103// static
[email protected]5c966022011-09-13 18:09:37104const void* PluginDispatcher::GetBrowserInterface(const char* interface_name) {
[email protected]234c1392012-09-27 23:30:41105 DCHECK(interface_name) << "|interface_name| is null. Did you forget to add "
106 "the |interface_name()| template function to the interface's C++ "
107 "wrapper?";
108
[email protected]5c966022011-09-13 18:09:37109 return InterfaceList::GetInstance()->GetInterfaceForPPB(interface_name);
110}
111
[email protected]a9b16dd2012-01-31 05:00:26112// static
113void PluginDispatcher::LogWithSource(PP_Instance instance,
114 PP_LogLevel_Dev level,
115 const std::string& source,
116 const std::string& value) {
117 if (!g_live_dispatchers || !g_instance_to_dispatcher)
118 return;
119
120 if (instance) {
121 InstanceToDispatcherMap::iterator found =
122 g_instance_to_dispatcher->find(instance);
123 if (found != g_instance_to_dispatcher->end()) {
124 // Send just to this specific dispatcher.
125 found->second->Send(new PpapiHostMsg_LogWithSource(
126 instance, static_cast<int>(level), source, value));
127 return;
128 }
129 }
130
131 // Instance 0 or invalid, send to all dispatchers.
132 for (DispatcherSet::iterator i = g_live_dispatchers->begin();
133 i != g_live_dispatchers->end(); ++i) {
134 (*i)->Send(new PpapiHostMsg_LogWithSource(
135 instance, static_cast<int>(level), source, value));
136 }
137}
138
[email protected]5c966022011-09-13 18:09:37139const void* PluginDispatcher::GetPluginInterface(
140 const std::string& interface_name) {
141 InterfaceMap::iterator found = plugin_interfaces_.find(interface_name);
142 if (found == plugin_interfaces_.end()) {
143 const void* ret = local_get_interface()(interface_name.c_str());
144 plugin_interfaces_.insert(std::make_pair(interface_name, ret));
145 return ret;
146 }
147 return found->second;
[email protected]a08ebea2011-02-13 17:50:20148}
149
[email protected]e2614c62011-04-16 22:12:45150bool PluginDispatcher::InitPluginWithChannel(
[email protected]d259a8e2011-05-18 22:31:09151 PluginDelegate* delegate,
[email protected]2cc062242011-03-10 21:16:34152 const IPC::ChannelHandle& channel_handle,
153 bool is_client) {
154 if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client))
155 return false;
[email protected]d259a8e2011-05-18 22:31:09156 plugin_delegate_ = delegate;
[email protected]373a95a2011-07-01 16:58:14157 plugin_dispatcher_id_ = plugin_delegate_->Register(this);
[email protected]2cc062242011-03-10 21:16:34158
159 // The message filter will intercept and process certain messages directly
160 // on the I/O thread.
161 channel()->AddFilter(
162 new PluginMessageFilter(delegate->GetGloballySeenInstanceIDSet()));
163 return true;
164}
165
[email protected]7cf40912010-12-09 18:25:03166bool PluginDispatcher::IsPlugin() const {
167 return true;
168}
169
[email protected]b00bbb32011-03-30 19:02:14170bool PluginDispatcher::Send(IPC::Message* msg) {
[email protected]366ae242011-05-10 02:23:58171 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::Send",
172 "Class", IPC_MESSAGE_ID_CLASS(msg->type()),
173 "Line", IPC_MESSAGE_ID_LINE(msg->type()));
[email protected]b00bbb32011-03-30 19:02:14174 // We always want plugin->renderer messages to arrive in-order. If some sync
[email protected]4c41d3f2012-02-15 01:44:47175 // and some async messages are sent in response to a synchronous
[email protected]b00bbb32011-03-30 19:02:14176 // renderer->plugin call, the sync reply will be processed before the async
177 // reply, and everything will be confused.
178 //
179 // Allowing all async messages to unblock the renderer means more reentrancy
180 // there but gives correct ordering.
[email protected]80f86a92012-04-09 23:58:14181 //
182 // We don't want reply messages to unblock however, as they will potentially
183 // end up on the wrong queue - see crbug.com/122443
184 if (!msg->is_reply())
185 msg->set_unblock(true);
[email protected]4c41d3f2012-02-15 01:44:47186 if (msg->is_sync()) {
187 // Synchronous messages might be re-entrant, so we need to drop the lock.
188 ProxyAutoUnlock unlock;
189 return Dispatcher::Send(msg);
190 }
[email protected]b00bbb32011-03-30 19:02:14191 return Dispatcher::Send(msg);
192}
193
[email protected]a95986a82010-12-24 06:19:28194bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) {
[email protected]4c41d3f2012-02-15 01:44:47195 // We need to grab the proxy lock to ensure that we don't collide with the
196 // plugin making pepper calls on a different thread.
197 ProxyAutoLock lock;
[email protected]366ae242011-05-10 02:23:58198 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived",
199 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
200 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
[email protected]eccf80312012-07-14 15:43:42201
[email protected]c2932f5e2010-11-03 03:22:33202 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
203 // Handle some plugin-specific control messages.
[email protected]a95986a82010-12-24 06:19:28204 bool handled = true;
[email protected]c2932f5e2010-11-03 03:22:33205 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg)
[email protected]eccf80312012-07-14 15:43:42206 IPC_MESSAGE_HANDLER(PpapiPluginMsg_ResourceReply, OnMsgResourceReply)
[email protected]465faa22011-02-08 16:31:46207 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface)
[email protected]208aad792011-05-26 19:05:28208 IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences)
[email protected]5c966022011-09-13 18:09:37209 IPC_MESSAGE_UNHANDLED(handled = false);
[email protected]c2932f5e2010-11-03 03:22:33210 IPC_END_MESSAGE_MAP()
[email protected]5c966022011-09-13 18:09:37211 if (handled)
[email protected]37fe0362011-09-13 04:00:33212 return true;
[email protected]37fe0362011-09-13 04:00:33213 }
[email protected]5c966022011-09-13 18:09:37214 return Dispatcher::OnMessageReceived(msg);
[email protected]c2932f5e2010-11-03 03:22:33215}
216
[email protected]a08ebea2011-02-13 17:50:20217void PluginDispatcher::OnChannelError() {
[email protected]4f15d2842011-02-15 17:36:33218 Dispatcher::OnChannelError();
219
[email protected]4b417e52011-04-18 22:51:08220 // The renderer has crashed or exited. This channel and all instances
221 // associated with it are no longer valid.
[email protected]a08ebea2011-02-13 17:50:20222 ForceFreeAllInstances();
223 // TODO(brettw) free resources too!
224 delete this;
225}
226
[email protected]f56279c2011-02-02 18:12:31227void PluginDispatcher::DidCreateInstance(PP_Instance instance) {
[email protected]465faa22011-02-08 16:31:46228 if (!g_instance_to_dispatcher)
229 g_instance_to_dispatcher = new InstanceToDispatcherMap;
230 (*g_instance_to_dispatcher)[instance] = this;
231
[email protected]f56279c2011-02-02 18:12:31232 instance_map_[instance] = InstanceData();
233}
234
235void PluginDispatcher::DidDestroyInstance(PP_Instance instance) {
236 InstanceDataMap::iterator it = instance_map_.find(instance);
237 if (it != instance_map_.end())
238 instance_map_.erase(it);
[email protected]465faa22011-02-08 16:31:46239
240 if (g_instance_to_dispatcher) {
241 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
242 instance);
243 if (found != g_instance_to_dispatcher->end()) {
244 DCHECK(found->second == this);
245 g_instance_to_dispatcher->erase(found);
246 } else {
247 NOTREACHED();
248 }
249 }
[email protected]f56279c2011-02-02 18:12:31250}
251
252InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) {
253 InstanceDataMap::iterator it = instance_map_.find(instance);
254 return (it == instance_map_.end()) ? NULL : &it->second;
255}
256
[email protected]4f2006122012-04-30 05:13:17257thunk::PPB_Instance_API* PluginDispatcher::GetInstanceAPI() {
258 return static_cast<PPB_Instance_Proxy*>(
259 GetInterfaceProxy(API_ID_PPB_INSTANCE));
260}
261
262thunk::ResourceCreationAPI* PluginDispatcher::GetResourceCreationAPI() {
263 return static_cast<ResourceCreationProxy*>(
264 GetInterfaceProxy(API_ID_RESOURCE_CREATION));
[email protected]6239d342011-05-06 22:55:47265}
266
[email protected]00c0d042012-09-10 07:06:39267// static
268void PluginDispatcher::DispatchResourceReply(
269 const ppapi::proxy::ResourceMessageReplyParams& reply_params,
270 const IPC::Message& nested_msg) {
271 Resource* resource = PpapiGlobals::Get()->GetResourceTracker()->GetResource(
272 reply_params.pp_resource());
273 if (!resource) {
274 NOTREACHED();
275 return;
276 }
277 resource->OnReplyReceived(reply_params, nested_msg);
278}
279
[email protected]a08ebea2011-02-13 17:50:20280void PluginDispatcher::ForceFreeAllInstances() {
[email protected]4f15d2842011-02-15 17:36:33281 if (!g_instance_to_dispatcher)
282 return;
283
284 // Iterating will remove each item from the map, so we need to make a copy
285 // to avoid things changing out from under is.
286 InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher;
287 for (InstanceToDispatcherMap::iterator i = temp_map.begin();
288 i != temp_map.end(); ++i) {
289 if (i->second == this) {
290 // Synthesize an "instance destroyed" message, this will notify the
291 // plugin and also remove it from our list of tracked plugins.
[email protected]ac4b54d2011-10-20 23:09:28292 PpapiMsg_PPPInstance_DidDestroy msg(API_ID_PPP_INSTANCE, i->first);
[email protected]4585fbc2011-06-13 17:17:56293 OnMessageReceived(msg);
[email protected]4f15d2842011-02-15 17:36:33294 }
295 }
[email protected]176c73922010-12-03 17:32:19296}
297
[email protected]eccf80312012-07-14 15:43:42298void PluginDispatcher::OnMsgResourceReply(
299 const ppapi::proxy::ResourceMessageReplyParams& reply_params,
300 const IPC::Message& nested_msg) {
[email protected]00c0d042012-09-10 07:06:39301 DispatchResourceReply(reply_params, nested_msg);
[email protected]eccf80312012-07-14 15:43:42302}
303
[email protected]465faa22011-02-08 16:31:46304void PluginDispatcher::OnMsgSupportsInterface(
305 const std::string& interface_name,
306 bool* result) {
[email protected]5c966022011-09-13 18:09:37307 *result = !!GetPluginInterface(interface_name);
[email protected]e8f07ac2012-01-03 17:43:36308
309 // Do fallback for PPP_Instance. This is a hack here and if we have more
310 // cases like this it should be generalized. The PPP_Instance proxy always
311 // proxies the 1.1 interface, and then does fallback to 1.0 inside the
312 // plugin process (see PPP_Instance_Proxy). So here we return true for
313 // supporting the 1.1 interface if either 1.1 or 1.0 is supported.
314 if (!*result && interface_name == PPP_INSTANCE_INTERFACE)
315 *result = !!GetPluginInterface(PPP_INSTANCE_INTERFACE_1_0);
[email protected]465faa22011-02-08 16:31:46316}
317
[email protected]4d2efd22011-08-18 21:58:02318void PluginDispatcher::OnMsgSetPreferences(const Preferences& prefs) {
[email protected]208aad792011-05-26 19:05:28319 // The renderer may send us preferences more than once (currently this
320 // happens every time a new plugin instance is created). Since we don't have
321 // a way to signal to the plugin that the preferences have changed, changing
322 // the default fonts and such in the middle of a running plugin could be
323 // confusing to it. As a result, we never allow the preferences to be changed
324 // once they're set. The user will have to restart to get new font prefs
325 // propogated to plugins.
326 if (!received_preferences_) {
327 received_preferences_ = true;
328 preferences_ = prefs;
329 }
330}
331
[email protected]c2932f5e2010-11-03 03:22:33332} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02333} // namespace ppapi