| 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 |