OLD | NEW |
1 // Copyright (c) 2011 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 "chrome/ppapi_plugin/ppapi_thread.h" | 5 #include "chrome/ppapi_plugin/ppapi_thread.h" |
6 | 6 |
| 7 #include <limits> |
| 8 |
7 #include "base/process_util.h" | 9 #include "base/process_util.h" |
| 10 #include "base/rand_util.h" |
8 #include "chrome/common/child_process.h" | 11 #include "chrome/common/child_process.h" |
9 #include "ipc/ipc_channel_handle.h" | 12 #include "ipc/ipc_channel_handle.h" |
10 #include "ipc/ipc_sync_channel.h" | 13 #include "ipc/ipc_sync_channel.h" |
| 14 #include "ppapi/c/pp_errors.h" |
11 #include "ppapi/c/ppp.h" | 15 #include "ppapi/c/ppp.h" |
12 #include "ppapi/proxy/plugin_dispatcher.h" | 16 #include "ppapi/proxy/plugin_dispatcher.h" |
13 #include "ppapi/proxy/ppapi_messages.h" | 17 #include "ppapi/proxy/ppapi_messages.h" |
14 | 18 |
15 #if defined(OS_POSIX) | |
16 #include "base/eintr_wrapper.h" | |
17 #include "ipc/ipc_channel_posix.h" | |
18 #endif | |
19 | |
20 PpapiThread::PpapiThread() | 19 PpapiThread::PpapiThread() |
21 #if defined(OS_POSIX) | 20 : get_plugin_interface_(NULL), |
22 : renderer_fd_(-1) | 21 local_pp_module_( |
23 #endif | 22 base::RandInt(0, std::numeric_limits<PP_Module>::max())) { |
24 { | |
25 } | 23 } |
26 | 24 |
27 PpapiThread::~PpapiThread() { | 25 PpapiThread::~PpapiThread() { |
| 26 if (library_.is_valid()) { |
| 27 // The ShutdownModule function is optional. |
| 28 pp::proxy::Dispatcher::ShutdownModuleFunc shutdown_module = |
| 29 reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>( |
| 30 library_.GetFunctionPointer("PPP_ShutdownModule")); |
| 31 if (shutdown_module) |
| 32 shutdown_module(); |
| 33 } |
28 } | 34 } |
29 | 35 |
30 // The "regular" ChildThread implements this function and does some standard | 36 // The "regular" ChildThread implements this function and does some standard |
31 // dispatching, then uses the message router. We don't actually need any of | 37 // dispatching, then uses the message router. We don't actually need any of |
32 // this so this function just overrides that one. | 38 // this so this function just overrides that one. |
33 // | 39 // |
34 // Note that this function is called only for messages from the channel to the | 40 // Note that this function is called only for messages from the channel to the |
35 // browser process. Messages from the renderer process are sent via a different | 41 // browser process. Messages from the renderer process are sent via a different |
36 // channel that ends up at Dispatcher::OnMessageReceived. | 42 // channel that ends up at Dispatcher::OnMessageReceived. |
37 bool PpapiThread::OnMessageReceived(const IPC::Message& msg) { | 43 bool PpapiThread::OnMessageReceived(const IPC::Message& msg) { |
38 IPC_BEGIN_MESSAGE_MAP(PpapiThread, msg) | 44 IPC_BEGIN_MESSAGE_MAP(PpapiThread, msg) |
39 IPC_MESSAGE_HANDLER(PpapiMsg_LoadPlugin, OnMsgLoadPlugin) | 45 IPC_MESSAGE_HANDLER(PpapiMsg_LoadPlugin, OnMsgLoadPlugin) |
| 46 IPC_MESSAGE_HANDLER(PpapiMsg_CreateChannel, OnMsgCreateChannel) |
40 IPC_END_MESSAGE_MAP() | 47 IPC_END_MESSAGE_MAP() |
41 return true; | 48 return true; |
42 } | 49 } |
43 | 50 |
44 void PpapiThread::OnMsgLoadPlugin(base::ProcessHandle host_process_handle, | 51 void PpapiThread::OnMsgLoadPlugin(const FilePath& path) { |
45 const FilePath& path, | 52 base::ScopedNativeLibrary library(base::LoadNativeLibrary(path)); |
46 int renderer_id) { | 53 if (!library.is_valid()) |
47 IPC::ChannelHandle channel_handle; | 54 return; |
48 if (!LoadPluginLib(host_process_handle, path) || | 55 |
49 !SetupRendererChannel(renderer_id, &channel_handle)) { | 56 // Get the GetInterface function (required). |
50 // An empty channel handle indicates error. | 57 get_plugin_interface_ = |
51 Send(new PpapiHostMsg_PluginLoaded(IPC::ChannelHandle())); | 58 reinterpret_cast<pp::proxy::Dispatcher::GetInterfaceFunc>( |
| 59 library.GetFunctionPointer("PPP_GetInterface")); |
| 60 if (!get_plugin_interface_) { |
| 61 LOG(WARNING) << "No PPP_GetInterface in plugin library"; |
52 return; | 62 return; |
53 } | 63 } |
54 | 64 |
55 Send(new PpapiHostMsg_PluginLoaded(channel_handle)); | |
56 } | |
57 | |
58 bool PpapiThread::LoadPluginLib(base::ProcessHandle host_process_handle, | |
59 const FilePath& path) { | |
60 base::ScopedNativeLibrary library(base::LoadNativeLibrary(path)); | |
61 if (!library.is_valid()) | |
62 return false; | |
63 | |
64 // Get the GetInterface function (required). | |
65 pp::proxy::Dispatcher::GetInterfaceFunc get_interface = | |
66 reinterpret_cast<pp::proxy::Dispatcher::GetInterfaceFunc>( | |
67 library.GetFunctionPointer("PPP_GetInterface")); | |
68 if (!get_interface) { | |
69 LOG(WARNING) << "No PPP_GetInterface in plugin library"; | |
70 return false; | |
71 } | |
72 | |
73 // Get the InitializeModule function (required). | 65 // Get the InitializeModule function (required). |
74 pp::proxy::Dispatcher::InitModuleFunc init_module = | 66 pp::proxy::Dispatcher::InitModuleFunc init_module = |
75 reinterpret_cast<pp::proxy::Dispatcher::InitModuleFunc>( | 67 reinterpret_cast<pp::proxy::Dispatcher::InitModuleFunc>( |
76 library.GetFunctionPointer("PPP_InitializeModule")); | 68 library.GetFunctionPointer("PPP_InitializeModule")); |
77 if (!init_module) { | 69 if (!init_module) { |
78 LOG(WARNING) << "No PPP_InitializeModule in plugin library"; | 70 LOG(WARNING) << "No PPP_InitializeModule in plugin library"; |
79 return false; | 71 return; |
| 72 } |
| 73 int32_t init_error = init_module( |
| 74 local_pp_module_, |
| 75 &pp::proxy::PluginDispatcher::GetInterfaceFromDispatcher); |
| 76 if (init_error != PP_OK) { |
| 77 LOG(WARNING) << "InitModule failed with error " << init_error; |
| 78 return; |
80 } | 79 } |
81 | 80 |
82 // Get the ShutdownModule function (optional). | |
83 pp::proxy::Dispatcher::ShutdownModuleFunc shutdown_module = | |
84 reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>( | |
85 library.GetFunctionPointer("PPP_ShutdownModule")); | |
86 | |
87 library_.Reset(library.Release()); | 81 library_.Reset(library.Release()); |
88 dispatcher_.reset(new pp::proxy::PluginDispatcher( | |
89 host_process_handle, get_interface, init_module, shutdown_module)); | |
90 return true; | |
91 } | 82 } |
92 | 83 |
93 bool PpapiThread::SetupRendererChannel(int renderer_id, | 84 void PpapiThread::OnMsgCreateChannel(base::ProcessHandle host_process_handle, |
| 85 int renderer_id) { |
| 86 IPC::ChannelHandle channel_handle; |
| 87 if (!library_.is_valid() || // Plugin couldn't be loaded. |
| 88 !SetupRendererChannel(host_process_handle, renderer_id, |
| 89 &channel_handle)) { |
| 90 Send(new PpapiHostMsg_ChannelCreated(IPC::ChannelHandle())); |
| 91 return; |
| 92 } |
| 93 |
| 94 Send(new PpapiHostMsg_ChannelCreated(channel_handle)); |
| 95 } |
| 96 |
| 97 bool PpapiThread::SetupRendererChannel(base::ProcessHandle host_process_handle, |
| 98 int renderer_id, |
94 IPC::ChannelHandle* handle) { | 99 IPC::ChannelHandle* handle) { |
| 100 pp::proxy::PluginDispatcher* dispatcher = new pp::proxy::PluginDispatcher( |
| 101 host_process_handle, get_plugin_interface_); |
| 102 |
95 IPC::ChannelHandle plugin_handle; | 103 IPC::ChannelHandle plugin_handle; |
96 plugin_handle.name = StringPrintf("%d.r%d", base::GetCurrentProcId(), | 104 plugin_handle.name = StringPrintf("%d.r%d", base::GetCurrentProcId(), |
97 renderer_id); | 105 renderer_id); |
98 if (!dispatcher_->InitWithChannel( | 106 if (!dispatcher->InitWithChannel( |
99 ChildProcess::current()->io_message_loop(), | 107 ChildProcess::current()->io_message_loop(), |
100 plugin_handle, false, | 108 plugin_handle, false, |
101 ChildProcess::current()->GetShutDownEvent())) | 109 ChildProcess::current()->GetShutDownEvent())) |
102 return false; | 110 return false; |
103 | 111 |
104 handle->name = plugin_handle.name; | 112 handle->name = plugin_handle.name; |
105 #if defined(OS_POSIX) | 113 #if defined(OS_POSIX) |
106 // On POSIX, pass the renderer-side FD. | 114 // On POSIX, pass the renderer-side FD. |
107 renderer_fd_ = dispatcher_->channel()->GetClientFileDescriptor(); | 115 handle->socket = base::FileDescriptor(dispatcher->GetRendererFD(), false); |
108 handle->socket = base::FileDescriptor(renderer_fd_, false); | |
109 #endif | 116 #endif |
| 117 |
110 return true; | 118 return true; |
111 } | 119 } |
112 | 120 |
113 #if defined(OS_POSIX) | |
114 void PpapiThread::CloseRendererFD() { | |
115 if (renderer_fd_ != -1) { | |
116 if (HANDLE_EINTR(close(renderer_fd_)) < 0) | |
117 PLOG(ERROR) << "close"; | |
118 renderer_fd_ = -1; | |
119 } | |
120 } | |
121 #endif | |
OLD | NEW |