OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ppapi/proxy/plugin_dispatcher.h" | 5 #include "ppapi/proxy/plugin_dispatcher.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "ipc/ipc_message.h" | 12 #include "ipc/ipc_message.h" |
13 #include "ipc/ipc_sync_channel.h" | 13 #include "ipc/ipc_sync_channel.h" |
14 #include "base/debug/trace_event.h" | 14 #include "base/debug/trace_event.h" |
15 #include "ppapi/c/pp_errors.h" | 15 #include "ppapi/c/pp_errors.h" |
| 16 #include "ppapi/proxy/interface_list.h" |
16 #include "ppapi/proxy/interface_proxy.h" | 17 #include "ppapi/proxy/interface_proxy.h" |
17 #include "ppapi/proxy/plugin_message_filter.h" | 18 #include "ppapi/proxy/plugin_message_filter.h" |
18 #include "ppapi/proxy/plugin_resource_tracker.h" | 19 #include "ppapi/proxy/plugin_resource_tracker.h" |
19 #include "ppapi/proxy/plugin_var_serialization_rules.h" | 20 #include "ppapi/proxy/plugin_var_serialization_rules.h" |
20 #include "ppapi/proxy/ppapi_messages.h" | 21 #include "ppapi/proxy/ppapi_messages.h" |
21 #include "ppapi/proxy/ppb_char_set_proxy.h" | 22 #include "ppapi/proxy/ppb_char_set_proxy.h" |
22 #include "ppapi/proxy/ppb_cursor_control_proxy.h" | 23 #include "ppapi/proxy/ppb_cursor_control_proxy.h" |
23 #include "ppapi/proxy/ppb_font_proxy.h" | 24 #include "ppapi/proxy/ppb_font_proxy.h" |
24 #include "ppapi/proxy/ppb_instance_proxy.h" | 25 #include "ppapi/proxy/ppb_instance_proxy.h" |
25 #include "ppapi/proxy/ppp_class_proxy.h" | 26 #include "ppapi/proxy/ppp_class_proxy.h" |
(...skipping 20 matching lines...) Expand all Loading... |
46 memset(&position, 0, sizeof(position)); | 47 memset(&position, 0, sizeof(position)); |
47 } | 48 } |
48 | 49 |
49 PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, | 50 PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, |
50 GetInterfaceFunc get_interface) | 51 GetInterfaceFunc get_interface) |
51 : Dispatcher(remote_process_handle, get_interface), | 52 : Dispatcher(remote_process_handle, get_interface), |
52 plugin_delegate_(NULL), | 53 plugin_delegate_(NULL), |
53 received_preferences_(false), | 54 received_preferences_(false), |
54 plugin_dispatcher_id_(0) { | 55 plugin_dispatcher_id_(0) { |
55 SetSerializationRules(new PluginVarSerializationRules); | 56 SetSerializationRules(new PluginVarSerializationRules); |
56 | |
57 // As a plugin, we always support the PPP_Class interface. There's no | |
58 // GetInterface call or name for it, so we insert it into our table now. | |
59 target_proxies_[INTERFACE_ID_PPP_CLASS].reset(new PPP_Class_Proxy(this)); | |
60 | |
61 TrackerBase::Init(&PluginResourceTracker::GetTrackerBaseInstance); | 57 TrackerBase::Init(&PluginResourceTracker::GetTrackerBaseInstance); |
62 } | 58 } |
63 | 59 |
64 PluginDispatcher::~PluginDispatcher() { | 60 PluginDispatcher::~PluginDispatcher() { |
65 if (plugin_delegate_) | 61 if (plugin_delegate_) |
66 plugin_delegate_->Unregister(plugin_dispatcher_id_); | 62 plugin_delegate_->Unregister(plugin_dispatcher_id_); |
67 } | 63 } |
68 | 64 |
69 // static | 65 // static |
70 PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { | 66 PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { |
71 if (!g_instance_to_dispatcher) | 67 if (!g_instance_to_dispatcher) |
72 return NULL; | 68 return NULL; |
73 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( | 69 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( |
74 instance); | 70 instance); |
75 if (found == g_instance_to_dispatcher->end()) | 71 if (found == g_instance_to_dispatcher->end()) |
76 return NULL; | 72 return NULL; |
77 return found->second; | 73 return found->second; |
78 } | 74 } |
79 | 75 |
80 // static | 76 // static |
81 PluginDispatcher* PluginDispatcher::GetForResource(const Resource* resource) { | 77 PluginDispatcher* PluginDispatcher::GetForResource(const Resource* resource) { |
82 return GetForInstance(resource->pp_instance()); | 78 return GetForInstance(resource->pp_instance()); |
83 } | 79 } |
84 | 80 |
85 // static | 81 // static |
86 const void* PluginDispatcher::GetInterfaceFromDispatcher( | 82 const void* PluginDispatcher::GetBrowserInterface(const char* interface_name) { |
87 const char* dispatcher_interface) { | 83 return InterfaceList::GetInstance()->GetInterfaceForPPB(interface_name); |
88 // All interfaces the plugin requests of the browser are "PPB". | 84 } |
89 const InterfaceProxy::Info* info = GetPPBInterfaceInfo(dispatcher_interface); | 85 |
90 if (!info) | 86 const void* PluginDispatcher::GetPluginInterface( |
91 return NULL; | 87 const std::string& interface_name) { |
92 return info->interface_ptr; | 88 InterfaceMap::iterator found = plugin_interfaces_.find(interface_name); |
| 89 if (found == plugin_interfaces_.end()) { |
| 90 const void* ret = local_get_interface()(interface_name.c_str()); |
| 91 plugin_interfaces_.insert(std::make_pair(interface_name, ret)); |
| 92 return ret; |
| 93 } |
| 94 return found->second; |
93 } | 95 } |
94 | 96 |
95 bool PluginDispatcher::InitPluginWithChannel( | 97 bool PluginDispatcher::InitPluginWithChannel( |
96 PluginDelegate* delegate, | 98 PluginDelegate* delegate, |
97 const IPC::ChannelHandle& channel_handle, | 99 const IPC::ChannelHandle& channel_handle, |
98 bool is_client) { | 100 bool is_client) { |
99 if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client)) | 101 if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client)) |
100 return false; | 102 return false; |
101 plugin_delegate_ = delegate; | 103 plugin_delegate_ = delegate; |
102 plugin_dispatcher_id_ = plugin_delegate_->Register(this); | 104 plugin_dispatcher_id_ = plugin_delegate_->Register(this); |
(...skipping 21 matching lines...) Expand all Loading... |
124 // Allowing all async messages to unblock the renderer means more reentrancy | 126 // Allowing all async messages to unblock the renderer means more reentrancy |
125 // there but gives correct ordering. | 127 // there but gives correct ordering. |
126 msg->set_unblock(true); | 128 msg->set_unblock(true); |
127 return Dispatcher::Send(msg); | 129 return Dispatcher::Send(msg); |
128 } | 130 } |
129 | 131 |
130 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { | 132 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { |
131 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived", | 133 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived", |
132 "Class", IPC_MESSAGE_ID_CLASS(msg.type()), | 134 "Class", IPC_MESSAGE_ID_CLASS(msg.type()), |
133 "Line", IPC_MESSAGE_ID_LINE(msg.type())); | 135 "Line", IPC_MESSAGE_ID_LINE(msg.type())); |
134 // Handle common control messages. | |
135 if (Dispatcher::OnMessageReceived(msg)) | |
136 return true; | |
137 | |
138 if (msg.routing_id() == MSG_ROUTING_CONTROL) { | 136 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
139 // Handle some plugin-specific control messages. | 137 // Handle some plugin-specific control messages. |
140 bool handled = true; | 138 bool handled = true; |
141 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) | 139 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) |
142 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) | 140 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) |
143 IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences) | 141 IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences) |
| 142 IPC_MESSAGE_UNHANDLED(handled = false); |
144 IPC_END_MESSAGE_MAP() | 143 IPC_END_MESSAGE_MAP() |
145 return handled; | 144 if (handled) |
| 145 return true; |
146 } | 146 } |
147 | 147 return Dispatcher::OnMessageReceived(msg); |
148 if (msg.routing_id() <= 0 || msg.routing_id() >= INTERFACE_ID_COUNT) { | |
149 // Host is sending us garbage. Since it's supposed to be trusted, this | |
150 // isn't supposed to happen. Crash here in all builds in case the renderer | |
151 // is compromised. | |
152 CHECK(false); | |
153 return true; | |
154 } | |
155 | |
156 // There are two cases: | |
157 // | |
158 // * The first case is that the host is calling a PPP interface. It will | |
159 // always do a check for the interface before sending messages, and this | |
160 // will create the necessary interface proxy at that time. So when we | |
161 // actually receive a message, we know such a proxy will exist. | |
162 // | |
163 // * The second case is that the host is sending a response to the plugin | |
164 // side of a PPB interface (some, like the URL loader, have complex | |
165 // response messages). Since the host is trusted and not supposed to be | |
166 // doing silly things, we can just create a PPB proxy project on demand the | |
167 // first time it's needed. | |
168 | |
169 InterfaceProxy* proxy = target_proxies_[msg.routing_id()].get(); | |
170 if (!proxy) { | |
171 // Handle the first time the host calls a PPB reply interface by | |
172 // autocreating it. | |
173 const InterfaceProxy::Info* info = GetPPBInterfaceInfo( | |
174 static_cast<InterfaceID>(msg.routing_id())); | |
175 if (!info) { | |
176 NOTREACHED(); | |
177 return true; | |
178 } | |
179 proxy = info->create_proxy(this, NULL); | |
180 target_proxies_[info->id].reset(proxy); | |
181 } | |
182 | |
183 return proxy->OnMessageReceived(msg); | |
184 } | 148 } |
185 | 149 |
186 void PluginDispatcher::OnChannelError() { | 150 void PluginDispatcher::OnChannelError() { |
187 Dispatcher::OnChannelError(); | 151 Dispatcher::OnChannelError(); |
188 | 152 |
189 // The renderer has crashed or exited. This channel and all instances | 153 // The renderer has crashed or exited. This channel and all instances |
190 // associated with it are no longer valid. | 154 // associated with it are no longer valid. |
191 ForceFreeAllInstances(); | 155 ForceFreeAllInstances(); |
192 // TODO(brettw) free resources too! | 156 // TODO(brettw) free resources too! |
193 delete this; | 157 delete this; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 | 195 |
232 bool PluginDispatcher::SendToBrowser(IPC::Message* msg) { | 196 bool PluginDispatcher::SendToBrowser(IPC::Message* msg) { |
233 return plugin_delegate_->SendToBrowser(msg); | 197 return plugin_delegate_->SendToBrowser(msg); |
234 } | 198 } |
235 | 199 |
236 WebKitForwarding* PluginDispatcher::GetWebKitForwarding() { | 200 WebKitForwarding* PluginDispatcher::GetWebKitForwarding() { |
237 return plugin_delegate_->GetWebKitForwarding(); | 201 return plugin_delegate_->GetWebKitForwarding(); |
238 } | 202 } |
239 | 203 |
240 FunctionGroupBase* PluginDispatcher::GetFunctionAPI(InterfaceID id) { | 204 FunctionGroupBase* PluginDispatcher::GetFunctionAPI(InterfaceID id) { |
241 scoped_ptr<FunctionGroupBase >& proxy = function_proxies_[id]; | 205 return GetInterfaceProxy(id); |
242 | |
243 if (proxy.get()) | |
244 return proxy.get(); | |
245 | |
246 if (id == INTERFACE_ID_PPB_CHAR_SET) | |
247 proxy.reset(new PPB_CharSet_Proxy(this, NULL)); | |
248 else if(id == INTERFACE_ID_PPB_CURSORCONTROL) | |
249 proxy.reset(new PPB_CursorControl_Proxy(this, NULL)); | |
250 else if (id == INTERFACE_ID_PPB_FONT) | |
251 proxy.reset(new PPB_Font_Proxy(this, NULL)); | |
252 else if (id == INTERFACE_ID_PPB_INSTANCE) | |
253 proxy.reset(new PPB_Instance_Proxy(this, NULL)); | |
254 else if (id == INTERFACE_ID_RESOURCE_CREATION) | |
255 proxy.reset(new ResourceCreationProxy(this)); | |
256 | |
257 return proxy.get(); | |
258 } | 206 } |
259 | 207 |
260 void PluginDispatcher::ForceFreeAllInstances() { | 208 void PluginDispatcher::ForceFreeAllInstances() { |
261 if (!g_instance_to_dispatcher) | 209 if (!g_instance_to_dispatcher) |
262 return; | 210 return; |
263 | 211 |
264 // Iterating will remove each item from the map, so we need to make a copy | 212 // Iterating will remove each item from the map, so we need to make a copy |
265 // to avoid things changing out from under is. | 213 // to avoid things changing out from under is. |
266 InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher; | 214 InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher; |
267 for (InstanceToDispatcherMap::iterator i = temp_map.begin(); | 215 for (InstanceToDispatcherMap::iterator i = temp_map.begin(); |
268 i != temp_map.end(); ++i) { | 216 i != temp_map.end(); ++i) { |
269 if (i->second == this) { | 217 if (i->second == this) { |
270 // Synthesize an "instance destroyed" message, this will notify the | 218 // Synthesize an "instance destroyed" message, this will notify the |
271 // plugin and also remove it from our list of tracked plugins. | 219 // plugin and also remove it from our list of tracked plugins. |
272 PpapiMsg_PPPInstance_DidDestroy msg(INTERFACE_ID_PPP_INSTANCE, i->first); | 220 PpapiMsg_PPPInstance_DidDestroy msg(INTERFACE_ID_PPP_INSTANCE, i->first); |
273 OnMessageReceived(msg); | 221 OnMessageReceived(msg); |
274 } | 222 } |
275 } | 223 } |
276 } | 224 } |
277 | 225 |
278 void PluginDispatcher::OnMsgSupportsInterface( | 226 void PluginDispatcher::OnMsgSupportsInterface( |
279 const std::string& interface_name, | 227 const std::string& interface_name, |
280 bool* result) { | 228 bool* result) { |
281 *result = false; | 229 *result = !!GetPluginInterface(interface_name); |
282 | |
283 // Setup a proxy for receiving the messages from this interface. | |
284 const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface_name); | |
285 if (!info) | |
286 return; // Interface not supported by proxy. | |
287 | |
288 // Check for a cached result. | |
289 if (target_proxies_[info->id].get()) { | |
290 *result = true; | |
291 return; | |
292 } | |
293 | |
294 // Query the plugin & cache the result. | |
295 const void* interface_functions = GetLocalInterface(interface_name.c_str()); | |
296 if (!interface_functions) | |
297 return; | |
298 target_proxies_[info->id].reset( | |
299 info->create_proxy(this, interface_functions)); | |
300 *result = true; | |
301 } | 230 } |
302 | 231 |
303 void PluginDispatcher::OnMsgSetPreferences(const Preferences& prefs) { | 232 void PluginDispatcher::OnMsgSetPreferences(const Preferences& prefs) { |
304 // The renderer may send us preferences more than once (currently this | 233 // The renderer may send us preferences more than once (currently this |
305 // happens every time a new plugin instance is created). Since we don't have | 234 // happens every time a new plugin instance is created). Since we don't have |
306 // a way to signal to the plugin that the preferences have changed, changing | 235 // a way to signal to the plugin that the preferences have changed, changing |
307 // the default fonts and such in the middle of a running plugin could be | 236 // the default fonts and such in the middle of a running plugin could be |
308 // confusing to it. As a result, we never allow the preferences to be changed | 237 // confusing to it. As a result, we never allow the preferences to be changed |
309 // once they're set. The user will have to restart to get new font prefs | 238 // once they're set. The user will have to restart to get new font prefs |
310 // propogated to plugins. | 239 // propogated to plugins. |
311 if (!received_preferences_) { | 240 if (!received_preferences_) { |
312 received_preferences_ = true; | 241 received_preferences_ = true; |
313 preferences_ = prefs; | 242 preferences_ = prefs; |
314 } | 243 } |
315 } | 244 } |
316 | 245 |
317 } // namespace proxy | 246 } // namespace proxy |
318 } // namespace ppapi | 247 } // namespace ppapi |
OLD | NEW |