Chromium Code Reviews| 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 |