OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "ipc/ipc_message.h" | 11 #include "ipc/ipc_message.h" |
12 #include "ipc/ipc_sync_channel.h" | 12 #include "ipc/ipc_sync_channel.h" |
13 #include "ppapi/c/pp_errors.h" | 13 #include "ppapi/c/pp_errors.h" |
14 #include "ppapi/proxy/interface_proxy.h" | 14 #include "ppapi/proxy/interface_proxy.h" |
15 #include "ppapi/proxy/plugin_var_serialization_rules.h" | 15 #include "ppapi/proxy/plugin_var_serialization_rules.h" |
16 #include "ppapi/proxy/ppapi_messages.h" | 16 #include "ppapi/proxy/ppapi_messages.h" |
17 #include "ppapi/proxy/ppp_class_proxy.h" | 17 #include "ppapi/proxy/ppp_class_proxy.h" |
18 | 18 |
19 namespace pp { | 19 namespace pp { |
20 namespace proxy { | 20 namespace proxy { |
21 | 21 |
22 namespace { | 22 namespace { |
23 | 23 |
24 PluginDispatcher* g_dispatcher = NULL; | 24 typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap; |
| 25 InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; |
25 | 26 |
26 const void* GetInterfaceFromDispatcher(const char* interface) { | 27 const void* GetInterfaceFromDispatcher(const char* interface) { |
27 // TODO(brettw) need some kind of lock for multi-thread access. | 28 // All interfaces the plugin requests of the browser are "PPB". |
28 return pp::proxy::PluginDispatcher::Get()->GetProxiedInterface(interface); | 29 const InterfaceProxy::Info* info = Dispatcher::GetPPBInterfaceInfo(interface); |
| 30 if (!info) |
| 31 return NULL; |
| 32 return info->interface; |
29 } | 33 } |
30 | 34 |
31 } // namespace | 35 } // namespace |
32 | 36 |
33 PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, | 37 PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, |
34 GetInterfaceFunc get_interface, | 38 GetInterfaceFunc get_interface, |
35 InitModuleFunc init_module, | 39 InitModuleFunc init_module, |
36 ShutdownModuleFunc shutdown_module) | 40 ShutdownModuleFunc shutdown_module) |
37 : Dispatcher(remote_process_handle, get_interface), | 41 : Dispatcher(remote_process_handle, get_interface), |
38 init_module_(init_module), | 42 init_module_(init_module), |
39 shutdown_module_(shutdown_module) { | 43 shutdown_module_(shutdown_module) { |
40 SetSerializationRules(new PluginVarSerializationRules); | 44 SetSerializationRules(new PluginVarSerializationRules); |
41 | 45 |
42 // As a plugin, we always support the PPP_Class interface. There's no | 46 // As a plugin, we always support the PPP_Class interface. There's no |
43 // GetInterface call or name for it, so we insert it into our table now. | 47 // GetInterface call or name for it, so we insert it into our table now. |
44 InjectProxy(INTERFACE_ID_PPP_CLASS, "$Internal_PPP_Class", | 48 target_proxies_[INTERFACE_ID_PPP_CLASS].reset(new PPP_Class_Proxy(this)); |
45 new PPP_Class_Proxy(this)); | |
46 } | 49 } |
47 | 50 |
48 PluginDispatcher::~PluginDispatcher() { | 51 PluginDispatcher::~PluginDispatcher() { |
49 if (shutdown_module_) | 52 if (shutdown_module_) |
50 shutdown_module_(); | 53 shutdown_module_(); |
51 } | 54 } |
52 | 55 |
53 // static | 56 // static |
54 PluginDispatcher* PluginDispatcher::Get() { | |
55 return g_dispatcher; | |
56 } | |
57 | |
58 // static | |
59 void PluginDispatcher::SetGlobal(PluginDispatcher* dispatcher) { | |
60 DCHECK(!dispatcher || !g_dispatcher); | |
61 g_dispatcher = dispatcher; | |
62 } | |
63 | |
64 // static | |
65 PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { | 57 PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { |
66 // TODO(brettw) implement "real" per-instance dispatcher map. | 58 if (!g_instance_to_dispatcher) |
67 DCHECK(instance != 0); | 59 return NULL; |
68 return Get(); | 60 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( |
| 61 instance); |
| 62 if (found == g_instance_to_dispatcher->end()) |
| 63 return NULL; |
| 64 return found->second; |
69 } | 65 } |
70 | 66 |
71 bool PluginDispatcher::IsPlugin() const { | 67 bool PluginDispatcher::IsPlugin() const { |
72 return true; | 68 return true; |
73 } | 69 } |
74 | 70 |
75 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { | 71 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { |
| 72 // Handle common control messages. |
| 73 if (Dispatcher::OnMessageReceived(msg)) |
| 74 return true; |
| 75 |
76 if (msg.routing_id() == MSG_ROUTING_CONTROL) { | 76 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
77 // Handle some plugin-specific control messages. | 77 // Handle some plugin-specific control messages. |
78 bool handled = true; | 78 bool handled = true; |
79 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) | 79 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) |
| 80 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) |
80 IPC_MESSAGE_HANDLER(PpapiMsg_InitializeModule, OnMsgInitializeModule) | 81 IPC_MESSAGE_HANDLER(PpapiMsg_InitializeModule, OnMsgInitializeModule) |
81 IPC_MESSAGE_HANDLER(PpapiMsg_Shutdown, OnMsgShutdown) | 82 IPC_MESSAGE_HANDLER(PpapiMsg_Shutdown, OnMsgShutdown) |
82 | |
83 // Forward all other control messages to the superclass. | |
84 IPC_MESSAGE_UNHANDLED(handled = Dispatcher::OnMessageReceived(msg)) | |
85 IPC_END_MESSAGE_MAP() | 83 IPC_END_MESSAGE_MAP() |
86 return handled; | 84 return handled; |
87 } | 85 } |
88 | 86 |
89 // All non-control messages get handled by the superclass. | 87 if (msg.routing_id() <= 0 && msg.routing_id() >= INTERFACE_ID_COUNT) { |
90 return Dispatcher::OnMessageReceived(msg); | 88 // Host is sending us garbage. Since it's supposed to be trusted, this |
| 89 // isn't supposed to happen. Crash here in all builds in case the renderer |
| 90 // is compromised. |
| 91 CHECK(false); |
| 92 return true; |
| 93 } |
| 94 |
| 95 // There are two cases: |
| 96 // |
| 97 // * The first case is that the host is calling a PPP interface. It will |
| 98 // always do a check for the interface before sending messages, and this |
| 99 // will create the necessary interface proxy at that time. So when we |
| 100 // actually receive a message, we know such a proxy will exist. |
| 101 // |
| 102 // * The second case is that the host is sending a response to the plugin |
| 103 // side of a PPB interface (some, like the URL loader, have complex |
| 104 // response messages). Since the host is trusted and not supposed to be |
| 105 // doing silly things, we can just create a PPB proxy project on demand the |
| 106 // first time it's needed. |
| 107 |
| 108 InterfaceProxy* proxy = target_proxies_[msg.routing_id()].get(); |
| 109 if (!proxy) { |
| 110 // Handle the first time the host calls a PPB reply interface by |
| 111 // autocreating it. |
| 112 const InterfaceProxy::Info* info = GetPPBInterfaceInfo( |
| 113 static_cast<InterfaceID>(msg.routing_id())); |
| 114 if (!info) { |
| 115 NOTREACHED(); |
| 116 return true; |
| 117 } |
| 118 proxy = info->create_proxy(this, NULL); |
| 119 target_proxies_[info->id].reset(proxy); |
| 120 } |
| 121 |
| 122 return proxy->OnMessageReceived(msg); |
91 } | 123 } |
92 | 124 |
93 void PluginDispatcher::DidCreateInstance(PP_Instance instance) { | 125 void PluginDispatcher::DidCreateInstance(PP_Instance instance) { |
| 126 if (!g_instance_to_dispatcher) |
| 127 g_instance_to_dispatcher = new InstanceToDispatcherMap; |
| 128 (*g_instance_to_dispatcher)[instance] = this; |
| 129 |
94 instance_map_[instance] = InstanceData(); | 130 instance_map_[instance] = InstanceData(); |
95 } | 131 } |
96 | 132 |
97 void PluginDispatcher::DidDestroyInstance(PP_Instance instance) { | 133 void PluginDispatcher::DidDestroyInstance(PP_Instance instance) { |
98 InstanceDataMap::iterator it = instance_map_.find(instance); | 134 InstanceDataMap::iterator it = instance_map_.find(instance); |
99 if (it != instance_map_.end()) | 135 if (it != instance_map_.end()) |
100 instance_map_.erase(it); | 136 instance_map_.erase(it); |
| 137 |
| 138 if (g_instance_to_dispatcher) { |
| 139 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( |
| 140 instance); |
| 141 if (found != g_instance_to_dispatcher->end()) { |
| 142 DCHECK(found->second == this); |
| 143 g_instance_to_dispatcher->erase(found); |
| 144 } else { |
| 145 NOTREACHED(); |
| 146 } |
| 147 } |
101 } | 148 } |
102 | 149 |
103 InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { | 150 InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { |
104 InstanceDataMap::iterator it = instance_map_.find(instance); | 151 InstanceDataMap::iterator it = instance_map_.find(instance); |
105 return (it == instance_map_.end()) ? NULL : &it->second; | 152 return (it == instance_map_.end()) ? NULL : &it->second; |
106 } | 153 } |
107 | 154 |
108 void PluginDispatcher::OnMsgInitializeModule(PP_Module pp_module, | 155 void PluginDispatcher::OnMsgInitializeModule(PP_Module pp_module, |
109 bool* result) { | 156 bool* result) { |
110 set_pp_module(pp_module); | 157 set_pp_module(pp_module); |
111 *result = init_module_(pp_module, &GetInterfaceFromDispatcher) == PP_OK; | 158 *result = init_module_(pp_module, &GetInterfaceFromDispatcher) == PP_OK; |
112 } | 159 } |
113 | 160 |
114 void PluginDispatcher::OnMsgShutdown() { | 161 void PluginDispatcher::OnMsgShutdown() { |
115 if (shutdown_module_) | 162 if (shutdown_module_) |
116 shutdown_module_(); | 163 shutdown_module_(); |
117 MessageLoop::current()->Quit(); | 164 MessageLoop::current()->Quit(); |
118 } | 165 } |
119 | 166 |
| 167 void PluginDispatcher::OnMsgSupportsInterface( |
| 168 const std::string& interface_name, |
| 169 bool* result) { |
| 170 *result = false; |
| 171 |
| 172 // Setup a proxy for receiving the messages from this interface. |
| 173 const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface_name); |
| 174 if (!info) |
| 175 return; // Interface not supported by proxy. |
| 176 |
| 177 // Check for a cached result. |
| 178 if (target_proxies_[info->id].get()) { |
| 179 *result = true; |
| 180 return; |
| 181 } |
| 182 |
| 183 // Query the plugin & cache the result. |
| 184 const void* interface_functions = GetLocalInterface(interface_name.c_str()); |
| 185 if (!interface_functions) |
| 186 return; |
| 187 target_proxies_[info->id].reset( |
| 188 info->create_proxy(this, interface_functions)); |
| 189 *result = true; |
| 190 } |
| 191 |
120 } // namespace proxy | 192 } // namespace proxy |
121 } // namespace pp | 193 } // namespace pp |
122 | 194 |
OLD | NEW |