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; | |
65 } | |
66 | |
67 // static | |
68 void PluginDispatcher::SetForInstance(PP_Instance instance, | |
69 PluginDispatcher* dispatcher) { | |
70 if (!g_instance_to_dispatcher) | |
71 g_instance_to_dispatcher = new InstanceToDispatcherMap; | |
72 (*g_instance_to_dispatcher)[instance] = dispatcher; | |
73 } | |
74 | |
75 // static | |
76 void PluginDispatcher::RemoveForInstance(PP_Instance instance) { | |
77 if (!g_instance_to_dispatcher) | |
78 return; | |
79 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( | |
80 instance); | |
81 if (found != g_instance_to_dispatcher->end()) | |
82 g_instance_to_dispatcher->erase(found); | |
69 } | 83 } |
70 | 84 |
71 bool PluginDispatcher::IsPlugin() const { | 85 bool PluginDispatcher::IsPlugin() const { |
72 return true; | 86 return true; |
73 } | 87 } |
74 | 88 |
75 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { | 89 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { |
90 // Handle common control messages. | |
91 if (Dispatcher::OnMessageReceived(msg)) | |
92 return true; | |
93 | |
76 if (msg.routing_id() == MSG_ROUTING_CONTROL) { | 94 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
77 // Handle some plugin-specific control messages. | 95 // Handle some plugin-specific control messages. |
78 bool handled = true; | 96 bool handled = true; |
79 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) | 97 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) |
98 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) | |
80 IPC_MESSAGE_HANDLER(PpapiMsg_InitializeModule, OnMsgInitializeModule) | 99 IPC_MESSAGE_HANDLER(PpapiMsg_InitializeModule, OnMsgInitializeModule) |
81 IPC_MESSAGE_HANDLER(PpapiMsg_Shutdown, OnMsgShutdown) | 100 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() | 101 IPC_END_MESSAGE_MAP() |
86 return handled; | 102 return handled; |
87 } | 103 } |
88 | 104 |
89 // All non-control messages get handled by the superclass. | 105 if (msg.routing_id() <= 0 && msg.routing_id() >= INTERFACE_ID_COUNT) { |
90 return Dispatcher::OnMessageReceived(msg); | 106 // Host is sending us garbage. Since it's supposed to be trusted, this |
107 // isn't supposed to happen. | |
piman
2011/02/07 21:29:22
Should we just crash here ? To prevent a compromis
brettw
2011/02/08 00:28:04
Sure.
| |
108 NOTREACHED(); | |
109 return true; | |
110 } | |
111 | |
112 // There are two cases: | |
113 // | |
114 // * The first case is that the host is calling a PPP interface. It will | |
115 // always do a check for the interface before sending messages, and this | |
116 // will create the necessary interface proxy at that time. So when we | |
117 // actually receive a message, we know such a proxy will exist. | |
118 // | |
119 // * The second case is that the host is sending a response to the plugin | |
120 // side of a PPB interface (some, like the URL loader, have complex | |
121 // response messages). Since the host is trusted and not supposed to be | |
122 // doing silly things, we can just create a PPB proxy project on demand the | |
123 // first time it's needed. | |
124 | |
125 InterfaceProxy* proxy = target_proxies_[msg.routing_id()].get(); | |
126 if (!proxy) { | |
127 // Handle the first time the host calls a PPB reply interface by | |
128 // autocreating it. | |
129 const InterfaceProxy::Info* info = GetPPBInterfaceInfo( | |
130 static_cast<InterfaceID>(msg.routing_id())); | |
131 if (!info) { | |
132 NOTREACHED(); | |
133 return true; | |
134 } | |
135 proxy = info->create(this, NULL); | |
136 target_proxies_[info->id].reset(proxy); | |
137 } | |
138 | |
139 return proxy->OnMessageReceived(msg); | |
91 } | 140 } |
92 | 141 |
93 void PluginDispatcher::DidCreateInstance(PP_Instance instance) { | 142 void PluginDispatcher::DidCreateInstance(PP_Instance instance) { |
94 instance_map_[instance] = InstanceData(); | 143 instance_map_[instance] = InstanceData(); |
95 } | 144 } |
96 | 145 |
97 void PluginDispatcher::DidDestroyInstance(PP_Instance instance) { | 146 void PluginDispatcher::DidDestroyInstance(PP_Instance instance) { |
98 InstanceDataMap::iterator it = instance_map_.find(instance); | 147 InstanceDataMap::iterator it = instance_map_.find(instance); |
99 if (it != instance_map_.end()) | 148 if (it != instance_map_.end()) |
100 instance_map_.erase(it); | 149 instance_map_.erase(it); |
101 } | 150 } |
102 | 151 |
103 InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { | 152 InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { |
104 InstanceDataMap::iterator it = instance_map_.find(instance); | 153 InstanceDataMap::iterator it = instance_map_.find(instance); |
105 return (it == instance_map_.end()) ? NULL : &it->second; | 154 return (it == instance_map_.end()) ? NULL : &it->second; |
106 } | 155 } |
107 | 156 |
108 void PluginDispatcher::OnMsgInitializeModule(PP_Module pp_module, | 157 void PluginDispatcher::OnMsgInitializeModule(PP_Module pp_module, |
109 bool* result) { | 158 bool* result) { |
110 set_pp_module(pp_module); | 159 set_pp_module(pp_module); |
111 *result = init_module_(pp_module, &GetInterfaceFromDispatcher) == PP_OK; | 160 *result = init_module_(pp_module, &GetInterfaceFromDispatcher) == PP_OK; |
112 } | 161 } |
113 | 162 |
114 void PluginDispatcher::OnMsgShutdown() { | 163 void PluginDispatcher::OnMsgShutdown() { |
115 if (shutdown_module_) | 164 if (shutdown_module_) |
116 shutdown_module_(); | 165 shutdown_module_(); |
117 MessageLoop::current()->Quit(); | 166 MessageLoop::current()->Quit(); |
118 } | 167 } |
119 | 168 |
169 void PluginDispatcher::OnMsgSupportsInterface( | |
170 const std::string& interface_name, | |
171 bool* result) { | |
172 *result = false; | |
173 | |
174 // Setup a proxy for receiving the messages from this interface. | |
175 const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface_name); | |
176 if (!info) | |
177 return; // Interface not supported by proxy. | |
178 | |
179 // Check for a cached result. | |
180 if (target_proxies_[info->id].get()) { | |
181 *result = true; | |
182 return; | |
183 } | |
184 | |
185 // Query the plugin & cache the result. | |
186 const void* interface_functions = GetLocalInterface(interface_name.c_str()); | |
187 if (!interface_functions) | |
188 return; | |
189 target_proxies_[info->id].reset(info->create(this, interface_functions)); | |
190 *result = true; | |
191 } | |
192 | |
120 } // namespace proxy | 193 } // namespace proxy |
121 } // namespace pp | 194 } // namespace pp |
122 | 195 |
OLD | NEW |