OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/ppapi_plugin/ppapi_thread.h" |
| 6 |
| 7 #include "base/process_util.h" |
| 8 #include "chrome/common/child_process.h" |
| 9 #include "ipc/ipc_channel_handle.h" |
| 10 #include "ipc/ipc_sync_channel.h" |
| 11 #include "ppapi/c/ppp.h" |
| 12 #include "ppapi/proxy/plugin_dispatcher.h" |
| 13 #include "ppapi/proxy/ppapi_messages.h" |
| 14 |
| 15 #if defined(OS_POSIX) |
| 16 #include "base/eintr_wrapper.h" |
| 17 #include "ipc/ipc_channel_posix.h" |
| 18 #endif |
| 19 |
| 20 PpapiThread::PpapiThread() |
| 21 : |
| 22 #if defined(OS_POSIX) |
| 23 renderer_fd_(-1) |
| 24 #endif |
| 25 { |
| 26 } |
| 27 |
| 28 PpapiThread::~PpapiThread() { |
| 29 pp::proxy::PluginDispatcher::SetGlobal(NULL); |
| 30 } |
| 31 |
| 32 // The "regular" ChildThread implements this function and does some standard |
| 33 // dispatching, then uses the message router. We don't actually need any of |
| 34 // this so this function just overrides that one. |
| 35 // |
| 36 // Note that this function is called only for messages from the channel to the |
| 37 // browser process. Messages from the renderer process are sent via a different |
| 38 // channel that ends up at Dispatcher::OnMessageReceived. |
| 39 void PpapiThread::OnMessageReceived(const IPC::Message& msg) { |
| 40 IPC_BEGIN_MESSAGE_MAP(PpapiThread, msg) |
| 41 IPC_MESSAGE_HANDLER(PpapiMsg_LoadPlugin, OnLoadPlugin) |
| 42 |
| 43 // The rest of the messages go to the dispatcher. |
| 44 /*IPC_MESSAGE_UNHANDLED( |
| 45 if (dispatcher_.get()) |
| 46 dispatcher_->OnMessageReceived(msg) |
| 47 )*/ |
| 48 IPC_END_MESSAGE_MAP() |
| 49 } |
| 50 |
| 51 void PpapiThread::OnLoadPlugin(const FilePath& path, int renderer_id) { |
| 52 IPC::ChannelHandle channel_handle; |
| 53 if (!LoadPluginLib(path) || |
| 54 !SetupRendererChannel(renderer_id, &channel_handle)) { |
| 55 // An empty channel handle indicates error. |
| 56 Send(new PpapiHostMsg_PluginLoaded(IPC::ChannelHandle())); |
| 57 return; |
| 58 } |
| 59 |
| 60 Send(new PpapiHostMsg_PluginLoaded(channel_handle)); |
| 61 } |
| 62 |
| 63 bool PpapiThread::LoadPluginLib(const FilePath& path) { |
| 64 base::ScopedNativeLibrary library(base::LoadNativeLibrary(path)); |
| 65 if (!library.is_valid()) |
| 66 return false; |
| 67 |
| 68 // Get the GetInterface function (required). |
| 69 pp::proxy::Dispatcher::GetInterfaceFunc get_interface = |
| 70 reinterpret_cast<pp::proxy::Dispatcher::GetInterfaceFunc>( |
| 71 library.GetFunctionPointer("PPP_GetInterface")); |
| 72 if (!get_interface) { |
| 73 LOG(WARNING) << "No PPP_GetInterface in plugin library"; |
| 74 return false; |
| 75 } |
| 76 |
| 77 // Get the InitializeModule function (required). |
| 78 pp::proxy::Dispatcher::InitModuleFunc init_module = |
| 79 reinterpret_cast<pp::proxy::Dispatcher::InitModuleFunc>( |
| 80 library.GetFunctionPointer("PPP_InitializeModule")); |
| 81 if (!init_module) { |
| 82 LOG(WARNING) << "No PPP_InitializeModule in plugin library"; |
| 83 return false; |
| 84 } |
| 85 |
| 86 // Get the ShutdownModule function (optional). |
| 87 pp::proxy::Dispatcher::ShutdownModuleFunc shutdown_module = |
| 88 reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>( |
| 89 library.GetFunctionPointer("PPP_ShutdownModule")); |
| 90 |
| 91 library_.Reset(library.Release()); |
| 92 dispatcher_.reset(new pp::proxy::PluginDispatcher(get_interface, init_module, |
| 93 shutdown_module)); |
| 94 pp::proxy::PluginDispatcher::SetGlobal(dispatcher_.get()); |
| 95 return true; |
| 96 } |
| 97 |
| 98 bool PpapiThread::SetupRendererChannel(int renderer_id, |
| 99 IPC::ChannelHandle* handle) { |
| 100 std::string channel_key = StringPrintf( |
| 101 "%d.r%d", base::GetCurrentProcId(), renderer_id); |
| 102 |
| 103 #if defined(OS_POSIX) |
| 104 // This gets called when the PluginChannel is initially created. At this |
| 105 // point, create the socketpair and assign the plugin side FD to the channel |
| 106 // name. Keep the renderer side FD as a member variable in the PluginChannel |
| 107 // to be able to transmit it through IPC. |
| 108 int plugin_fd; |
| 109 if (!IPC::SocketPair(&plugin_fd, &renderer_fd_)) |
| 110 return false; |
| 111 IPC::AddChannelSocket(channel_key, plugin_fd); |
| 112 #endif |
| 113 |
| 114 if (!dispatcher_->InitWithChannel( |
| 115 ChildProcess::current()->io_message_loop(), |
| 116 channel_key, false, |
| 117 ChildProcess::current()->GetShutDownEvent())) |
| 118 return false; |
| 119 |
| 120 handle->name = channel_key; |
| 121 #if defined(OS_POSIX) |
| 122 // On POSIX, pass the renderer-side FD. |
| 123 handle->socket = base::FileDescriptor(renderer_fd_, false); |
| 124 #endif |
| 125 return true; |
| 126 } |
| 127 |
| 128 #if defined(OS_POSIX) |
| 129 void PpapiThread::CloseRendererFD() { |
| 130 if (renderer_fd_ != -1) { |
| 131 if (HANDLE_EINTR(close(renderer_fd_)) < 0) |
| 132 PLOG(ERROR) << "close"; |
| 133 renderer_fd_ = -1; |
| 134 } |
| 135 } |
| 136 #endif |
OLD | NEW |