| OLD | NEW |
| 1 // Copyright (c) 2010 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 "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 #if defined(OS_POSIX) |
| 20 #include "base/eintr_wrapper.h" |
| 21 #include "ipc/ipc_channel_posix.h" |
| 22 #endif |
| 23 |
| 19 namespace pp { | 24 namespace pp { |
| 20 namespace proxy { | 25 namespace proxy { |
| 21 | 26 |
| 22 namespace { | 27 namespace { |
| 23 | 28 |
| 24 typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap; | 29 typedef std::map<PP_Instance, PluginDispatcher*> InstanceToDispatcherMap; |
| 25 InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; | 30 InstanceToDispatcherMap* g_instance_to_dispatcher = NULL; |
| 26 | 31 |
| 27 const void* GetInterfaceFromDispatcher(const char* interface) { | |
| 28 // All interfaces the plugin requests of the browser are "PPB". | |
| 29 const InterfaceProxy::Info* info = Dispatcher::GetPPBInterfaceInfo(interface); | |
| 30 if (!info) | |
| 31 return NULL; | |
| 32 return info->interface; | |
| 33 } | |
| 34 | |
| 35 } // namespace | 32 } // namespace |
| 36 | 33 |
| 37 PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, | 34 PluginDispatcher::PluginDispatcher(base::ProcessHandle remote_process_handle, |
| 38 GetInterfaceFunc get_interface, | 35 GetInterfaceFunc get_interface) |
| 39 InitModuleFunc init_module, | 36 : Dispatcher(remote_process_handle, get_interface) |
| 40 ShutdownModuleFunc shutdown_module) | 37 #if defined(OS_POSIX) |
| 41 : Dispatcher(remote_process_handle, get_interface), | 38 , renderer_fd_(-1) |
| 42 init_module_(init_module), | 39 #endif |
| 43 shutdown_module_(shutdown_module) { | 40 { |
| 44 SetSerializationRules(new PluginVarSerializationRules); | 41 SetSerializationRules(new PluginVarSerializationRules); |
| 45 | 42 |
| 46 // As a plugin, we always support the PPP_Class interface. There's no | 43 // As a plugin, we always support the PPP_Class interface. There's no |
| 47 // GetInterface call or name for it, so we insert it into our table now. | 44 // GetInterface call or name for it, so we insert it into our table now. |
| 48 target_proxies_[INTERFACE_ID_PPP_CLASS].reset(new PPP_Class_Proxy(this)); | 45 target_proxies_[INTERFACE_ID_PPP_CLASS].reset(new PPP_Class_Proxy(this)); |
| 49 } | 46 } |
| 50 | 47 |
| 51 PluginDispatcher::~PluginDispatcher() { | 48 PluginDispatcher::~PluginDispatcher() { |
| 52 if (shutdown_module_) | 49 #if defined(OS_POSIX) |
| 53 shutdown_module_(); | 50 CloseRendererFD(); |
| 51 #endif |
| 54 } | 52 } |
| 55 | 53 |
| 56 // static | 54 // static |
| 57 PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { | 55 PluginDispatcher* PluginDispatcher::GetForInstance(PP_Instance instance) { |
| 58 if (!g_instance_to_dispatcher) | 56 if (!g_instance_to_dispatcher) |
| 59 return NULL; | 57 return NULL; |
| 60 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( | 58 InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find( |
| 61 instance); | 59 instance); |
| 62 if (found == g_instance_to_dispatcher->end()) | 60 if (found == g_instance_to_dispatcher->end()) |
| 63 return NULL; | 61 return NULL; |
| 64 return found->second; | 62 return found->second; |
| 65 } | 63 } |
| 66 | 64 |
| 65 // static |
| 66 const void* PluginDispatcher::GetInterfaceFromDispatcher( |
| 67 const char* interface) { |
| 68 // All interfaces the plugin requests of the browser are "PPB". |
| 69 const InterfaceProxy::Info* info = GetPPBInterfaceInfo(interface); |
| 70 if (!info) |
| 71 return NULL; |
| 72 return info->interface; |
| 73 } |
| 74 |
| 67 bool PluginDispatcher::IsPlugin() const { | 75 bool PluginDispatcher::IsPlugin() const { |
| 68 return true; | 76 return true; |
| 69 } | 77 } |
| 70 | 78 |
| 71 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { | 79 bool PluginDispatcher::OnMessageReceived(const IPC::Message& msg) { |
| 72 // Handle common control messages. | 80 // Handle common control messages. |
| 73 if (Dispatcher::OnMessageReceived(msg)) | 81 if (Dispatcher::OnMessageReceived(msg)) |
| 74 return true; | 82 return true; |
| 75 | 83 |
| 76 if (msg.routing_id() == MSG_ROUTING_CONTROL) { | 84 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
| 77 // Handle some plugin-specific control messages. | 85 // Handle some plugin-specific control messages. |
| 78 bool handled = true; | 86 bool handled = true; |
| 79 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) | 87 IPC_BEGIN_MESSAGE_MAP(PluginDispatcher, msg) |
| 80 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) | 88 IPC_MESSAGE_HANDLER(PpapiMsg_SupportsInterface, OnMsgSupportsInterface) |
| 81 IPC_MESSAGE_HANDLER(PpapiMsg_InitializeModule, OnMsgInitializeModule) | |
| 82 IPC_MESSAGE_HANDLER(PpapiMsg_Shutdown, OnMsgShutdown) | |
| 83 IPC_END_MESSAGE_MAP() | 89 IPC_END_MESSAGE_MAP() |
| 84 return handled; | 90 return handled; |
| 85 } | 91 } |
| 86 | 92 |
| 87 if (msg.routing_id() <= 0 && msg.routing_id() >= INTERFACE_ID_COUNT) { | 93 if (msg.routing_id() <= 0 && msg.routing_id() >= INTERFACE_ID_COUNT) { |
| 88 // Host is sending us garbage. Since it's supposed to be trusted, this | 94 // 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 | 95 // isn't supposed to happen. Crash here in all builds in case the renderer |
| 90 // is compromised. | 96 // is compromised. |
| 91 CHECK(false); | 97 CHECK(false); |
| 92 return true; | 98 return true; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 115 NOTREACHED(); | 121 NOTREACHED(); |
| 116 return true; | 122 return true; |
| 117 } | 123 } |
| 118 proxy = info->create_proxy(this, NULL); | 124 proxy = info->create_proxy(this, NULL); |
| 119 target_proxies_[info->id].reset(proxy); | 125 target_proxies_[info->id].reset(proxy); |
| 120 } | 126 } |
| 121 | 127 |
| 122 return proxy->OnMessageReceived(msg); | 128 return proxy->OnMessageReceived(msg); |
| 123 } | 129 } |
| 124 | 130 |
| 131 void PluginDispatcher::OnChannelError() { |
| 132 // The renderer has crashed. This channel and all instances associated with |
| 133 // it are no longer valid. |
| 134 ForceFreeAllInstances(); |
| 135 // TODO(brettw) free resources too! |
| 136 delete this; |
| 137 } |
| 138 |
| 125 void PluginDispatcher::DidCreateInstance(PP_Instance instance) { | 139 void PluginDispatcher::DidCreateInstance(PP_Instance instance) { |
| 126 if (!g_instance_to_dispatcher) | 140 if (!g_instance_to_dispatcher) |
| 127 g_instance_to_dispatcher = new InstanceToDispatcherMap; | 141 g_instance_to_dispatcher = new InstanceToDispatcherMap; |
| 128 (*g_instance_to_dispatcher)[instance] = this; | 142 (*g_instance_to_dispatcher)[instance] = this; |
| 129 | 143 |
| 130 instance_map_[instance] = InstanceData(); | 144 instance_map_[instance] = InstanceData(); |
| 131 } | 145 } |
| 132 | 146 |
| 133 void PluginDispatcher::DidDestroyInstance(PP_Instance instance) { | 147 void PluginDispatcher::DidDestroyInstance(PP_Instance instance) { |
| 134 InstanceDataMap::iterator it = instance_map_.find(instance); | 148 InstanceDataMap::iterator it = instance_map_.find(instance); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 145 NOTREACHED(); | 159 NOTREACHED(); |
| 146 } | 160 } |
| 147 } | 161 } |
| 148 } | 162 } |
| 149 | 163 |
| 150 InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { | 164 InstanceData* PluginDispatcher::GetInstanceData(PP_Instance instance) { |
| 151 InstanceDataMap::iterator it = instance_map_.find(instance); | 165 InstanceDataMap::iterator it = instance_map_.find(instance); |
| 152 return (it == instance_map_.end()) ? NULL : &it->second; | 166 return (it == instance_map_.end()) ? NULL : &it->second; |
| 153 } | 167 } |
| 154 | 168 |
| 155 void PluginDispatcher::OnMsgInitializeModule(PP_Module pp_module, | 169 #if defined(OS_POSIX) |
| 156 bool* result) { | 170 int PluginDispatcher::GetRendererFD() { |
| 157 set_pp_module(pp_module); | 171 if (renderer_fd_ == -1) |
| 158 *result = init_module_(pp_module, &GetInterfaceFromDispatcher) == PP_OK; | 172 renderer_fd_ = channel()->GetClientFileDescriptor(); |
| 173 return renderer_fd_; |
| 159 } | 174 } |
| 160 | 175 |
| 161 void PluginDispatcher::OnMsgShutdown() { | 176 void PluginDispatcher::CloseRendererFD() { |
| 162 if (shutdown_module_) | 177 if (renderer_fd_ != -1) { |
| 163 shutdown_module_(); | 178 if (HANDLE_EINTR(close(renderer_fd_)) < 0) |
| 164 MessageLoop::current()->Quit(); | 179 PLOG(ERROR) << "close"; |
| 180 renderer_fd_ = -1; |
| 181 } |
| 182 } |
| 183 #endif |
| 184 |
| 185 void PluginDispatcher::ForceFreeAllInstances() { |
| 186 // TODO(brettw) implement freeing instances on crash. |
| 165 } | 187 } |
| 166 | 188 |
| 167 void PluginDispatcher::OnMsgSupportsInterface( | 189 void PluginDispatcher::OnMsgSupportsInterface( |
| 168 const std::string& interface_name, | 190 const std::string& interface_name, |
| 169 bool* result) { | 191 bool* result) { |
| 170 *result = false; | 192 *result = false; |
| 171 | 193 |
| 172 // Setup a proxy for receiving the messages from this interface. | 194 // Setup a proxy for receiving the messages from this interface. |
| 173 const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface_name); | 195 const InterfaceProxy::Info* info = GetPPPInterfaceInfo(interface_name); |
| 174 if (!info) | 196 if (!info) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 185 if (!interface_functions) | 207 if (!interface_functions) |
| 186 return; | 208 return; |
| 187 target_proxies_[info->id].reset( | 209 target_proxies_[info->id].reset( |
| 188 info->create_proxy(this, interface_functions)); | 210 info->create_proxy(this, interface_functions)); |
| 189 *result = true; | 211 *result = true; |
| 190 } | 212 } |
| 191 | 213 |
| 192 } // namespace proxy | 214 } // namespace proxy |
| 193 } // namespace pp | 215 } // namespace pp |
| 194 | 216 |
| OLD | NEW |