blob: 931471354e3e14239a534b3dde3bbd01c7876aa4 [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]5c966022011-09-13 18:09:3717#include "ppapi/proxy/interface_list.h"
[email protected]c2932f5e2010-11-03 03:22:3318#include "ppapi/proxy/interface_proxy.h"
[email protected]2cc062242011-03-10 21:16:3419#include "ppapi/proxy/plugin_message_filter.h"
[email protected]6239d342011-05-06 22:55:4720#include "ppapi/proxy/plugin_resource_tracker.h"
[email protected]c2932f5e2010-11-03 03:22:3321#include "ppapi/proxy/plugin_var_serialization_rules.h"
22#include "ppapi/proxy/ppapi_messages.h"
[email protected]ceadc392011-06-15 23:04:2423#include "ppapi/proxy/ppb_instance_proxy.h"
[email protected]c2932f5e2010-11-03 03:22:3324#include "ppapi/proxy/ppp_class_proxy.h"
[email protected]6239d342011-05-06 22:55:4725#include "ppapi/proxy/resource_creation_proxy.h"
[email protected]eccf80312012-07-14 15:43:4226#include "ppapi/proxy/resource_message_params.h"
27#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]4c41d3f2012-02-15 01:44:4728#include "ppapi/shared_impl/proxy_lock.h"
[email protected]7f8b26b2011-08-18 15:41:0129#include "ppapi/shared_impl/resource.h"
[email protected]c2932f5e2010-11-03 03:22:3330
[email protected]339fbcff2012-02-29 16:10:3231#if defined(OS_POSIX) && !defined(OS_NACL)
[email protected]a08ebea2011-02-13 17:50:2032#include "base/eintr_wrapper.h"
33#include "ipc/ipc_channel_posix.h"
34#endif
35
[email protected]4d2efd22011-08-18 21:58:0236namespace ppapi {
[email protected]c2932f5e2010-11-03 03:22:3337namespace proxy {
38
39namespace {
40
[email protected]465faa22011-02-08 16:31:4641typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap;
42InstanceToDispatcherMap* g_instance_to_dispatcher = NULL;
[email protected]c2932f5e2010-11-03 03:22:3343
[email protected]a9b16dd2012-01-31 05:00:2644typedef std::set<PluginDispatcher*> DispatcherSet;
45DispatcherSet* g_live_dispatchers = NULL;
46
[email protected]c2932f5e2010-11-03 03:22:3347} // namespace
48
[email protected]06e0a342011-09-27 04:24:3049InstanceData::InstanceData()
[email protected]aed96532012-06-23 14:27:4250 : flash_fullscreen(PP_FALSE) {
[email protected]c7bf7452011-09-12 21:31:5051}
52
[email protected]0f41c012011-10-21 19:49:2053InstanceData::~InstanceData() {
54 // Run any pending mouse lock callback to prevent leaks.
[email protected]aed96532012-06-23 14:27:4255 if (mouse_lock_callback)
56 mouse_lock_callback->Abort();
[email protected]0f41c012011-10-21 19:49:2057}
58
[email protected]f0ecb552012-05-11 22:09:1159PluginDispatcher::PluginDispatcher(PP_GetInterface_Func get_interface,
[email protected]bc2eeb42012-05-02 22:35:5360 bool incognito)
[email protected]f0ecb552012-05-11 22:09:1161 : Dispatcher(get_interface),
[email protected]208aad792011-05-26 19:05:2862 plugin_delegate_(NULL),
[email protected]373a95a2011-07-01 16:58:1463 received_preferences_(false),
[email protected]bc2eeb42012-05-02 22:35:5364 plugin_dispatcher_id_(0),
65 incognito_(incognito) {
[email protected]67600b92012-03-10 06:51:4866 SetSerializationRules(new PluginVarSerializationRules(AsWeakPtr()));
[email protected]a9b16dd2012-01-31 05:00:2667
68 if (!g_live_dispatchers)
69 g_live_dispatchers = new DispatcherSet;
70 g_live_dispatchers->insert(this);
[email protected]c2932f5e2010-11-03 03:22:3371}
72
73PluginDispatcher::~PluginDispatcher() {
[email protected]373a95a2011-07-01 16:58:1474 if (plugin_delegate_)
75 plugin_delegate_->Unregister(plugin_dispatcher_id_);
[email protected]a9b16dd2012-01-31 05:00:2676
77 g_live_dispatchers->erase(this);
78 if (g_live_dispatchers->empty()) {
79 delete g_live_dispatchers;
80 g_live_dispatchers = NULL;
81 }
[email protected]c2932f5e2010-11-03 03:22:3382}
83
84// static
[email protected]4614f192011-01-21 00:26:4385PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) {
[email protected]465faa22011-02-08 16:31:4686 if (!g_instance_to_dispatcher)
87 return NULL;
88 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
89 instance);
90 if (found == g_instance_to_dispatcher->end())
91 return NULL;
92 return found->second;
[email protected]4614f192011-01-21 00:26:4393}
94
[email protected]a08ebea2011-02-13 17:50:2095// static
[email protected]7f8b26b2011-08-18 15:41:0196PluginDispatcher* PluginDispatcher::GetForResource(const Resource* resource) {
97 return GetForInstance(resource->pp_instance());
98}
99
100// static
[email protected]5c966022011-09-13 18:09:37101const void* PluginDispatcher::GetBrowserInterface(const char* interface_name) {
102 return InterfaceList::GetInstance()->GetInterfaceForPPB(interface_name);
103}
104
[email protected]a9b16dd2012-01-31 05:00:26105// static
106void PluginDispatcher::LogWithSource(PP_Instance instance,
107 PP_LogLevel_Dev level,
108 const std::string& source,
109 const std::string& value) {
110 if (!g_live_dispatchers || !g_instance_to_dispatcher)
111 return;
112
113 if (instance) {
114 InstanceToDispatcherMap::iterator found =
115 g_instance_to_dispatcher->find(instance);
116 if (found != g_instance_to_dispatcher->end()) {
117 // Send just to this specific dispatcher.
118 found->second->Send(new PpapiHostMsg_LogWithSource(
119 instance, static_cast<int>(level), source, value));
120 return;
121 }
122 }
123
124 // Instance 0 or invalid, send to all dispatchers.
125 for (DispatcherSet::iterator i = g_live_dispatchers->begin();
126 i != g_live_dispatchers->end(); ++i) {
127 (*i)->Send(new PpapiHostMsg_LogWithSource(
128 instance, static_cast<int>(level), source, value));
129 }
130}
131
[email protected]5c966022011-09-13 18:09:37132const void* PluginDispatcher::GetPluginInterface(
133 const std::string& interface_name) {
134 InterfaceMap::iterator found = plugin_interfaces_.find(interface_name);
135 if (found == plugin_interfaces_.end()) {
136 const void* ret = local_get_interface()(interface_name.c_str());
137 plugin_interfaces_.insert(std::make_pair(interface_name, ret));
138 return ret;
139 }
140 return found->second;
[email protected]a08ebea2011-02-13 17:50:20141}
142
[email protected]e2614c62011-04-16 22:12:45143bool PluginDispatcher::InitPluginWithChannel(
[email protected]d259a8e2011-05-18 22:31:09144 PluginDelegate* delegate,
[email protected]2cc062242011-03-10 21:16:34145 const IPC::ChannelHandle& channel_handle,
146 bool is_client) {
147 if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client))
148 return false;
[email protected]d259a8e2011-05-18 22:31:09149 plugin_delegate_ = delegate;
[email protected]373a95a2011-07-01 16:58:14150 plugin_dispatcher_id_ = plugin_delegate_->Register(this);
[email protected]2cc062242011-03-10 21:16:34151
152 // The message filter will intercept and process certain messages directly
153 // on the I/O thread.
154 channel()->AddFilter(
155 new PluginMessageFilter(delegate->GetGloballySeenInstanceIDSet()));
156 return true;
157}
158
[email protected]7cf40912010-12-09 18:25:03159bool PluginDispatcher::IsPlugin() const {
160 return true;
161}
162
[email protected]b00bbb32011-03-30 19:02:14163bool PluginDispatcher::Send(IPC::Message* msg) {
[email protected]366ae242011-05-10 02:23:58164 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::Send",
165 "Class", IPC_MESSAGE_ID_CLASS(msg->type()),
166 "Line", IPC_MESSAGE_ID_LINE(msg->type()));
[email protected]b00bbb32011-03-30 19:02:14167 // We always want plugin->renderer messages to arrive in-order. If some sync
[email protected]4c41d3f2012-02-15 01:44:47168 // and some async messages are sent in response to a synchronous
[email protected]b00bbb32011-03-30 19:02:14169 // renderer->plugin call, the sync reply will be processed before the async
170 // reply, and everything will be confused.
171 //
172 // Allowing all async messages to unblock the renderer means more reentrancy
173 // there but gives correct ordering.
[email protected]80f86a92012-04-09 23:58:14174 //
175 // We don't want reply messages to unblock however, as they will potentially
176 // end up on the wrong queue - see crbug.com/122443
177 if (!msg->is_reply())
178 msg->set_unblock(true);
[email protected]4c41d3f2012-02-15 01:44:47179 if (msg->is_sync()) {
180 // Synchronous messages might be re-entrant, so we need to drop the lock.
181 ProxyAutoUnlock unlock;
182 return Dispatcher::Send(msg);
183 }
[email protected]b00bbb32011-03-30 19:02:14184 return Dispatcher::Send(msg);
185}
186
[email protected]a95986a82010-12-24 06:19:28187bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) {
[email protected]4c41d3f2012-02-15 01:44:47188 // We need to grab the proxy lock to ensure that we don't collide with the
189 // plugin making pepper calls on a different thread.
190 ProxyAutoLock lock;
[email protected]366ae242011-05-10 02:23:58191 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived",
192 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
193 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
[email protected]eccf80312012-07-14 15:43:42194
[email protected]c2932f5e2010-11-03 03:22:33195 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
196 // Handle some plugin-specific control messages.
[email protected]a95986a82010-12-24 06:19:28197 bool handled = true;
[email protected]c2932f5e2010-11-03 03:22:33198 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg)
[email protected]eccf80312012-07-14 15:43:42199 IPC_MESSAGE_HANDLER(PpapiPluginMsg_ResourceReply, OnMsgResourceReply)
[email protected]465faa22011-02-08 16:31:46200 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface)
[email protected]208aad792011-05-26 19:05:28201 IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences)
[email protected]5c966022011-09-13 18:09:37202 IPC_MESSAGE_UNHANDLED(handled = false);
[email protected]c2932f5e2010-11-03 03:22:33203 IPC_END_MESSAGE_MAP()
[email protected]5c966022011-09-13 18:09:37204 if (handled)
[email protected]37fe0362011-09-13 04:00:33205 return true;
[email protected]37fe0362011-09-13 04:00:33206 }
[email protected]5c966022011-09-13 18:09:37207 return Dispatcher::OnMessageReceived(msg);
[email protected]c2932f5e2010-11-03 03:22:33208}
209
[email protected]a08ebea2011-02-13 17:50:20210void PluginDispatcher::OnChannelError() {
[email protected]4f15d2842011-02-15 17:36:33211 Dispatcher::OnChannelError();
212
[email protected]4b417e52011-04-18 22:51:08213 // The renderer has crashed or exited. This channel and all instances
214 // associated with it are no longer valid.
[email protected]a08ebea2011-02-13 17:50:20215 ForceFreeAllInstances();
216 // TODO(brettw) free resources too!
217 delete this;
218}
219
[email protected]f56279c2011-02-02 18:12:31220void PluginDispatcher::DidCreateInstance(PP_Instance instance) {
[email protected]465faa22011-02-08 16:31:46221 if (!g_instance_to_dispatcher)
222 g_instance_to_dispatcher = new InstanceToDispatcherMap;
223 (*g_instance_to_dispatcher)[instance] = this;
224
[email protected]f56279c2011-02-02 18:12:31225 instance_map_[instance] = InstanceData();
226}
227
228void PluginDispatcher::DidDestroyInstance(PP_Instance instance) {
229 InstanceDataMap::iterator it = instance_map_.find(instance);
230 if (it != instance_map_.end())
231 instance_map_.erase(it);
[email protected]465faa22011-02-08 16:31:46232
233 if (g_instance_to_dispatcher) {
234 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
235 instance);
236 if (found != g_instance_to_dispatcher->end()) {
237 DCHECK(found->second == this);
238 g_instance_to_dispatcher->erase(found);
239 } else {
240 NOTREACHED();
241 }
242 }
[email protected]f56279c2011-02-02 18:12:31243}
244
245InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) {
246 InstanceDataMap::iterator it = instance_map_.find(instance);
247 return (it == instance_map_.end()) ? NULL : &it->second;
248}
249
[email protected]4f2006122012-04-30 05:13:17250thunk::PPB_Instance_API* PluginDispatcher::GetInstanceAPI() {
251 return static_cast<PPB_Instance_Proxy*>(
252 GetInterfaceProxy(API_ID_PPB_INSTANCE));
253}
254
255thunk::ResourceCreationAPI* PluginDispatcher::GetResourceCreationAPI() {
256 return static_cast<ResourceCreationProxy*>(
257 GetInterfaceProxy(API_ID_RESOURCE_CREATION));
[email protected]6239d342011-05-06 22:55:47258}
259
[email protected]a08ebea2011-02-13 17:50:20260void PluginDispatcher::ForceFreeAllInstances() {
[email protected]4f15d2842011-02-15 17:36:33261 if (!g_instance_to_dispatcher)
262 return;
263
264 // Iterating will remove each item from the map, so we need to make a copy
265 // to avoid things changing out from under is.
266 InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher;
267 for (InstanceToDispatcherMap::iterator i = temp_map.begin();
268 i != temp_map.end(); ++i) {
269 if (i->second == this) {
270 // Synthesize an "instance destroyed" message, this will notify the
271 // plugin and also remove it from our list of tracked plugins.
[email protected]ac4b54d2011-10-20 23:09:28272 PpapiMsg_PPPInstance_DidDestroy msg(API_ID_PPP_INSTANCE, i->first);
[email protected]4585fbc2011-06-13 17:17:56273 OnMessageReceived(msg);
[email protected]4f15d2842011-02-15 17:36:33274 }
275 }
[email protected]176c73922010-12-03 17:32:19276}
277
[email protected]eccf80312012-07-14 15:43:42278void PluginDispatcher::OnMsgResourceReply(
279 const ppapi::proxy::ResourceMessageReplyParams& reply_params,
280 const IPC::Message& nested_msg) {
281 Resource* resource = PpapiGlobals::Get()->GetResourceTracker()->GetResource(
282 reply_params.pp_resource());
283 if (!resource) {
284 NOTREACHED();
285 return;
286 }
287 resource->OnReplyReceived(reply_params.sequence(), reply_params.result(),
288 nested_msg);
289}
290
[email protected]465faa22011-02-08 16:31:46291void PluginDispatcher::OnMsgSupportsInterface(
292 const std::string& interface_name,
293 bool* result) {
[email protected]5c966022011-09-13 18:09:37294 *result = !!GetPluginInterface(interface_name);
[email protected]e8f07ac2012-01-03 17:43:36295
296 // Do fallback for PPP_Instance. This is a hack here and if we have more
297 // cases like this it should be generalized. The PPP_Instance proxy always
298 // proxies the 1.1 interface, and then does fallback to 1.0 inside the
299 // plugin process (see PPP_Instance_Proxy). So here we return true for
300 // supporting the 1.1 interface if either 1.1 or 1.0 is supported.
301 if (!*result && interface_name == PPP_INSTANCE_INTERFACE)
302 *result = !!GetPluginInterface(PPP_INSTANCE_INTERFACE_1_0);
[email protected]465faa22011-02-08 16:31:46303}
304
[email protected]4d2efd22011-08-18 21:58:02305void PluginDispatcher::OnMsgSetPreferences(const Preferences& prefs) {
[email protected]208aad792011-05-26 19:05:28306 // The renderer may send us preferences more than once (currently this
307 // happens every time a new plugin instance is created). Since we don't have
308 // a way to signal to the plugin that the preferences have changed, changing
309 // the default fonts and such in the middle of a running plugin could be
310 // confusing to it. As a result, we never allow the preferences to be changed
311 // once they're set. The user will have to restart to get new font prefs
312 // propogated to plugins.
313 if (!received_preferences_) {
314 received_preferences_ = true;
315 preferences_ = prefs;
316 }
317}
318
[email protected]c2932f5e2010-11-03 03:22:33319} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02320} // namespace ppapi