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 |