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" | |
17 #include "ppapi/proxy/interface_proxy.h" | 16 #include "ppapi/proxy/interface_proxy.h" |
18 #include "ppapi/proxy/plugin_message_filter.h" | 17 #include "ppapi/proxy/plugin_message_filter.h" |
19 #include "ppapi/proxy/plugin_resource_tracker.h" | 18 #include "ppapi/proxy/plugin_resource_tracker.h" |
20 #include "ppapi/proxy/plugin_var_serialization_rules.h" | 19 #include "ppapi/proxy/plugin_var_serialization_rules.h" |
21 #include "ppapi/proxy/ppapi_messages.h" | 20 #include "ppapi/proxy/ppapi_messages.h" |
22 #include "ppapi/proxy/ppb_char_set_proxy.h" | 21 #include "ppapi/proxy/ppb_char_set_proxy.h" |
23 #include "ppapi/proxy/ppb_cursor_control_proxy.h" | 22 #include "ppapi/proxy/ppb_cursor_control_proxy.h" |
24 #include "ppapi/proxy/ppb_font_proxy.h" | 23 #include "ppapi/proxy/ppb_font_proxy.h" |
25 #include "ppapi/proxy/ppb_instance_proxy.h" | 24 #include "ppapi/proxy/ppb_instance_proxy.h" |
26 #include "ppapi/proxy/ppp_class_proxy.h" | 25 #include "ppapi/proxy/ppp_class_proxy.h" |
(...skipping 16 matching lines...) Expand all Loading... |
43 | 42 |
44 } // namespace | 43 } // namespace |
45 | 44 |
46 PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, | 45 PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, |
47 GetInterfaceFunc get_interface) | 46 GetInterfaceFunc get_interface) |
48 : Dispatcher(remote_process_handle, get_interface), | 47 : Dispatcher(remote_process_handle, get_interface), |
49 plugin_delegate_(NULL), | 48 plugin_delegate_(NULL), |
50 received_preferences_(false), | 49 received_preferences_(false), |
51 plugin_dispatcher_id_(0) { | 50 plugin_dispatcher_id_(0) { |
52 SetSerializationRules(new PluginVarSerializationRules); | 51 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 |
53 TrackerBase::Init(&PluginResourceTracker::GetTrackerBaseInstance); | 57 TrackerBase::Init(&PluginResourceTracker::GetTrackerBaseInstance); |
54 } | 58 } |
55 | 59 |
56 PluginDispatcher::~PluginDispatcher() { | 60 PluginDispatcher::~PluginDispatcher() { |
57 if (plugin_delegate_) | 61 if (plugin_delegate_) |
58 plugin_delegate_->Unregister(plugin_dispatcher_id_); | 62 plugin_delegate_->Unregister(plugin_dispatcher_id_); |
59 } | 63 } |
60 | 64 |
61 // static | 65 // static |
62 PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { | 66 PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { |
63 if (!g_instance_to_dispatcher) | 67 if (!g_instance_to_dispatcher) |
64 return NULL; | 68 return NULL; |
65 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( | 69 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( |
66 instance); | 70 instance); |
67 if (found == g_instance_to_dispatcher->end()) | 71 if (found == g_instance_to_dispatcher->end()) |
68 return NULL; | 72 return NULL; |
69 return found->second; | 73 return found->second; |
70 } | 74 } |
71 | 75 |
72 // static | 76 // static |
73 PluginDispatcher* PluginDispatcher::GetForResource(const Resource* resource) { | 77 PluginDispatcher* PluginDispatcher::GetForResource(const Resource* resource) { |
74 return GetForInstance(resource->pp_instance()); | 78 return GetForInstance(resource->pp_instance()); |
75 } | 79 } |
76 | 80 |
77 // static | 81 // static |
78 const void* PluginDispatcher::GetBrowserInterface(const char* interface) { | 82 const void* PluginDispatcher::GetInterfaceFromDispatcher( |
79 return InterfaceList::GetInstance()->GetInterfaceForPPB(interface); | 83 const char* dispatcher_interface) { |
80 } | 84 // All interfaces the plugin requests of the browser are "PPB". |
81 | 85 const InterfaceProxy::Info* info = GetPPBInterfaceInfo(dispatcher_interface); |
82 const void* PluginDispatcher::GetPluginInterface( | 86 if (!info) |
83 const std::string& interface_name) { | 87 return NULL; |
84 InterfaceMap::iterator found = plugin_interfaces_.find(interface_name); | 88 return info->interface_ptr; |
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; | |
91 } | 89 } |
92 | 90 |
93 bool PluginDispatcher::InitPluginWithChannel( | 91 bool PluginDispatcher::InitPluginWithChannel( |
94 PluginDelegate* delegate, | 92 PluginDelegate* delegate, |
95 const IPC::ChannelHandle& channel_handle, | 93 const IPC::ChannelHandle& channel_handle, |
96 bool is_client) { | 94 bool is_client) { |
97 if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client)) | 95 if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client)) |
98 return false; | 96 return false; |
99 plugin_delegate_ = delegate; | 97 plugin_delegate_ = delegate; |
100 plugin_dispatcher_id_ = plugin_delegate_->Register(this); | 98 plugin_dispatcher_id_ = plugin_delegate_->Register(this); |
(...skipping 21 matching lines...) Expand all Loading... |
122 // Allowing all async messages to unblock the renderer means more reentrancy | 120 // Allowing all async messages to unblock the renderer means more reentrancy |
123 // there but gives correct ordering. | 121 // there but gives correct ordering. |
124 msg->set_unblock(true); | 122 msg->set_unblock(true); |
125 return Dispatcher::Send(msg); | 123 return Dispatcher::Send(msg); |
126 } | 124 } |
127 | 125 |
128 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { | 126 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { |
129 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived", | 127 TRACE_EVENT2("ppapi proxy", "PluginDispatcher::OnMessageReceived", |
130 "Class", IPC_MESSAGE_ID_CLASS(msg.type()), | 128 "Class", IPC_MESSAGE_ID_CLASS(msg.type()), |
131 "Line", IPC_MESSAGE_ID_LINE(msg.type())); | 129 "Line", IPC_MESSAGE_ID_LINE(msg.type())); |
| 130 // Handle common control messages. |
| 131 if (Dispatcher::OnMessageReceived(msg)) |
| 132 return true; |
| 133 |
132 if (msg.routing_id() == MSG_ROUTING_CONTROL) { | 134 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
133 // Handle some plugin-specific control messages. | 135 // Handle some plugin-specific control messages. |
134 bool handled = true; | 136 bool handled = true; |
135 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) | 137 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) |
136 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) | 138 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) |
137 IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences) | 139 IPC_MESSAGE_HANDLER(PpapiMsg_SetPreferences, OnMsgSetPreferences) |
138 IPC_MESSAGE_UNHANDLED(handled = false); | |
139 IPC_END_MESSAGE_MAP() | 140 IPC_END_MESSAGE_MAP() |
140 if (handled) | 141 return handled; |
| 142 } |
| 143 |
| 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(); |
141 return true; | 173 return true; |
| 174 } |
| 175 proxy = info->create_proxy(this, NULL); |
| 176 target_proxies_[info->id].reset(proxy); |
142 } | 177 } |
143 return Dispatcher::OnMessageReceived(msg); | 178 |
| 179 return proxy->OnMessageReceived(msg); |
144 } | 180 } |
145 | 181 |
146 void PluginDispatcher::OnChannelError() { | 182 void PluginDispatcher::OnChannelError() { |
147 Dispatcher::OnChannelError(); | 183 Dispatcher::OnChannelError(); |
148 | 184 |
149 // The renderer has crashed or exited. This channel and all instances | 185 // The renderer has crashed or exited. This channel and all instances |
150 // associated with it are no longer valid. | 186 // associated with it are no longer valid. |
151 ForceFreeAllInstances(); | 187 ForceFreeAllInstances(); |
152 // TODO(brettw) free resources too! | 188 // TODO(brettw) free resources too! |
153 delete this; | 189 delete this; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 | 227 |
192 bool PluginDispatcher::SendToBrowser(IPC::Message* msg) { | 228 bool PluginDispatcher::SendToBrowser(IPC::Message* msg) { |
193 return plugin_delegate_->SendToBrowser(msg); | 229 return plugin_delegate_->SendToBrowser(msg); |
194 } | 230 } |
195 | 231 |
196 WebKitForwarding* PluginDispatcher::GetWebKitForwarding() { | 232 WebKitForwarding* PluginDispatcher::GetWebKitForwarding() { |
197 return plugin_delegate_->GetWebKitForwarding(); | 233 return plugin_delegate_->GetWebKitForwarding(); |
198 } | 234 } |
199 | 235 |
200 FunctionGroupBase* PluginDispatcher::GetFunctionAPI(InterfaceID id) { | 236 FunctionGroupBase* PluginDispatcher::GetFunctionAPI(InterfaceID id) { |
201 return GetInterfaceProxy(id); | 237 scoped_ptr<FunctionGroupBase >& proxy = function_proxies_[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(); |
202 } | 254 } |
203 | 255 |
204 void PluginDispatcher::ForceFreeAllInstances() { | 256 void PluginDispatcher::ForceFreeAllInstances() { |
205 if (!g_instance_to_dispatcher) | 257 if (!g_instance_to_dispatcher) |
206 return; | 258 return; |
207 | 259 |
208 // Iterating will remove each item from the map, so we need to make a copy | 260 // Iterating will remove each item from the map, so we need to make a copy |
209 // to avoid things changing out from under is. | 261 // to avoid things changing out from under is. |
210 InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher; | 262 InstanceToDispatcherMap temp_map = *g_instance_to_dispatcher; |
211 for (InstanceToDispatcherMap::iterator i = temp_map.begin(); | 263 for (InstanceToDispatcherMap::iterator i = temp_map.begin(); |
212 i != temp_map.end(); ++i) { | 264 i != temp_map.end(); ++i) { |
213 if (i->second == this) { | 265 if (i->second == this) { |
214 // Synthesize an "instance destroyed" message, this will notify the | 266 // Synthesize an "instance destroyed" message, this will notify the |
215 // plugin and also remove it from our list of tracked plugins. | 267 // plugin and also remove it from our list of tracked plugins. |
216 PpapiMsg_PPPInstance_DidDestroy msg(INTERFACE_ID_PPP_INSTANCE, i->first); | 268 PpapiMsg_PPPInstance_DidDestroy msg(INTERFACE_ID_PPP_INSTANCE, i->first); |
217 OnMessageReceived(msg); | 269 OnMessageReceived(msg); |
218 } | 270 } |
219 } | 271 } |
220 } | 272 } |
221 | 273 |
222 void PluginDispatcher::OnMsgSupportsInterface( | 274 void PluginDispatcher::OnMsgSupportsInterface( |
223 const std::string& interface_name, | 275 const std::string& interface_name, |
224 bool* result) { | 276 bool* result) { |
225 *result = !!GetPluginInterface(interface_name); | 277 *result = false; |
| 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; |
226 } | 297 } |
227 | 298 |
228 void PluginDispatcher::OnMsgSetPreferences(const Preferences& prefs) { | 299 void PluginDispatcher::OnMsgSetPreferences(const Preferences& prefs) { |
229 // The renderer may send us preferences more than once (currently this | 300 // The renderer may send us preferences more than once (currently this |
230 // happens every time a new plugin instance is created). Since we don't have | 301 // happens every time a new plugin instance is created). Since we don't have |
231 // a way to signal to the plugin that the preferences have changed, changing | 302 // a way to signal to the plugin that the preferences have changed, changing |
232 // the default fonts and such in the middle of a running plugin could be | 303 // the default fonts and such in the middle of a running plugin could be |
233 // confusing to it. As a result, we never allow the preferences to be changed | 304 // confusing to it. As a result, we never allow the preferences to be changed |
234 // once they're set. The user will have to restart to get new font prefs | 305 // once they're set. The user will have to restart to get new font prefs |
235 // propogated to plugins. | 306 // propogated to plugins. |
236 if (!received_preferences_) { | 307 if (!received_preferences_) { |
237 received_preferences_ = true; | 308 received_preferences_ = true; |
238 preferences_ = prefs; | 309 preferences_ = prefs; |
239 } | 310 } |
240 } | 311 } |
241 | 312 |
242 } // namespace proxy | 313 } // namespace proxy |
243 } // namespace ppapi | 314 } // namespace ppapi |
OLD | NEW |