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