diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-10 01:16:11 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-10 01:16:11 +0000 |
commit | 709a847ee12e1380df59db8cd3c972ec4f9c674e (patch) | |
tree | 48217fd87c7e1fe15afdd90db26a925f7db28a1b /chrome/ppapi_plugin | |
parent | f30e74751217091c0b6050080f46cd6eb4914226 (diff) | |
download | chromium_src-709a847ee12e1380df59db8cd3c972ec4f9c674e.zip chromium_src-709a847ee12e1380df59db8cd3c972ec4f9c674e.tar.gz chromium_src-709a847ee12e1380df59db8cd3c972ec4f9c674e.tar.bz2 |
Implement a new process type for running PPAPI plugins. The process itself is
quite simple and just sets up the PPAPI dispatcher and loads the library.
There is a new command line switch --ppapi-out-of-process which runs PPAPI
plugins out of process using the new code path. There is some logic in
RenderView and PepperPluginModule for setting up this connection, but it should
be straightforward.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/3915002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@65614 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/ppapi_plugin')
-rw-r--r-- | chrome/ppapi_plugin/ppapi_plugin_main.cc | 34 | ||||
-rw-r--r-- | chrome/ppapi_plugin/ppapi_process.cc | 11 | ||||
-rw-r--r-- | chrome/ppapi_plugin/ppapi_process.h | 20 | ||||
-rw-r--r-- | chrome/ppapi_plugin/ppapi_thread.cc | 135 | ||||
-rw-r--r-- | chrome/ppapi_plugin/ppapi_thread.h | 67 |
5 files changed, 267 insertions, 0 deletions
diff --git a/chrome/ppapi_plugin/ppapi_plugin_main.cc b/chrome/ppapi_plugin/ppapi_plugin_main.cc new file mode 100644 index 0000000..6738860 --- /dev/null +++ b/chrome/ppapi_plugin/ppapi_plugin_main.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_loop.h" +#include "build/build_config.h" +#include "chrome/common/child_process.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/main_function_params.h" +#include "chrome/ppapi_plugin/ppapi_thread.h" + +// Main function for starting the PPAPI plugin process. +int PpapiPluginMain(const MainFunctionParams& parameters) { +#if defined(OS_LINUX) + // On Linux we exec ourselves from /proc/self/exe, but that makes the + // process name that shows up in "ps" etc. for this process show as + // "exe" instead of "chrome" or something reasonable. Try to fix it. + CommandLine::SetProcTitle(); +#endif + + const CommandLine& command_line = parameters.command_line_; + if (command_line.HasSwitch(switches::kPpapiStartupDialog)) { + ChildProcess::WaitForDebugger(L"Ppapi"); + } + + MessageLoop main_message_loop(MessageLoop::TYPE_UI); + PlatformThread::SetName("CrPPAPIMain"); + + ChildProcess ppapi_process; + ppapi_process.set_main_thread(new PpapiThread()); + + main_message_loop.Run(); + return 0; +} diff --git a/chrome/ppapi_plugin/ppapi_process.cc b/chrome/ppapi_plugin/ppapi_process.cc new file mode 100644 index 0000000..8cb9c7d --- /dev/null +++ b/chrome/ppapi_plugin/ppapi_process.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/ppapi_plugin/ppapi_process.h" + +PpapiProcess::PpapiProcess() { +} + +PpapiProcess::~PpapiProcess() { +} diff --git a/chrome/ppapi_plugin/ppapi_process.h b/chrome/ppapi_plugin/ppapi_process.h new file mode 100644 index 0000000..590f995 --- /dev/null +++ b/chrome/ppapi_plugin/ppapi_process.h @@ -0,0 +1,20 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_PPAPI_PLUGIN_PPAPI_PROCESS_H_ +#define CHROME_PPAPI_PLUGIN_PPAPI_PROCESS_H_ +#pragma once + +#include "chrome/common/child_process.h" + +class PpapiProcess : public ChildProcess { + public: + PpapiProcess(); + ~PpapiProcess(); + + private: + DISALLOW_COPY_AND_ASSIGN(PpapiProcess); +}; + +#endif // CHROME_PPAPI_PLUGIN_PPAPI_PROCESS_H_ diff --git a/chrome/ppapi_plugin/ppapi_thread.cc b/chrome/ppapi_plugin/ppapi_thread.cc new file mode 100644 index 0000000..36ea9f6 --- /dev/null +++ b/chrome/ppapi_plugin/ppapi_thread.cc @@ -0,0 +1,135 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/ppapi_plugin/ppapi_thread.h" + +#include "base/process_util.h" +#include "chrome/common/child_process.h" +#include "ipc/ipc_channel_handle.h" +#include "ipc/ipc_sync_channel.h" +#include "ppapi/c/ppp.h" +#include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/ppapi_messages.h" + +#if defined(OS_POSIX) +#include "base/eintr_wrapper.h" +#include "ipc/ipc_channel_posix.h" +#endif + +PpapiThread::PpapiThread() +#if defined(OS_POSIX) + : renderer_fd_(-1) +#endif + { +} + +PpapiThread::~PpapiThread() { + pp::proxy::PluginDispatcher::SetGlobal(NULL); +} + +// The "regular" ChildThread implements this function and does some standard +// dispatching, then uses the message router. We don't actually need any of +// this so this function just overrides that one. +// +// Note that this function is called only for messages from the channel to the +// browser process. Messages from the renderer process are sent via a different +// channel that ends up at Dispatcher::OnMessageReceived. +void PpapiThread::OnMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(PpapiThread, msg) + IPC_MESSAGE_HANDLER(PpapiMsg_LoadPlugin, OnLoadPlugin) + + // The rest of the messages go to the dispatcher. + /*IPC_MESSAGE_UNHANDLED( + if (dispatcher_.get()) + dispatcher_->OnMessageReceived(msg) + )*/ + IPC_END_MESSAGE_MAP() +} + +void PpapiThread::OnLoadPlugin(const FilePath& path, int renderer_id) { + IPC::ChannelHandle channel_handle; + if (!LoadPluginLib(path) || + !SetupRendererChannel(renderer_id, &channel_handle)) { + // An empty channel handle indicates error. + Send(new PpapiHostMsg_PluginLoaded(IPC::ChannelHandle())); + return; + } + + Send(new PpapiHostMsg_PluginLoaded(channel_handle)); +} + +bool PpapiThread::LoadPluginLib(const FilePath& path) { + base::ScopedNativeLibrary library(base::LoadNativeLibrary(path)); + if (!library.is_valid()) + return false; + + // Get the GetInterface function (required). + pp::proxy::Dispatcher::GetInterfaceFunc get_interface = + reinterpret_cast<pp::proxy::Dispatcher::GetInterfaceFunc>( + library.GetFunctionPointer("PPP_GetInterface")); + if (!get_interface) { + LOG(WARNING) << "No PPP_GetInterface in plugin library"; + return false; + } + + // Get the InitializeModule function (required). + pp::proxy::Dispatcher::InitModuleFunc init_module = + reinterpret_cast<pp::proxy::Dispatcher::InitModuleFunc>( + library.GetFunctionPointer("PPP_InitializeModule")); + if (!init_module) { + LOG(WARNING) << "No PPP_InitializeModule in plugin library"; + return false; + } + + // Get the ShutdownModule function (optional). + pp::proxy::Dispatcher::ShutdownModuleFunc shutdown_module = + reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>( + library.GetFunctionPointer("PPP_ShutdownModule")); + + library_.Reset(library.Release()); + dispatcher_.reset(new pp::proxy::PluginDispatcher(get_interface, init_module, + shutdown_module)); + pp::proxy::PluginDispatcher::SetGlobal(dispatcher_.get()); + return true; +} + +bool PpapiThread::SetupRendererChannel(int renderer_id, + IPC::ChannelHandle* handle) { + std::string channel_key = StringPrintf( + "%d.r%d", base::GetCurrentProcId(), renderer_id); + +#if defined(OS_POSIX) + // This gets called when the PluginChannel is initially created. At this + // point, create the socketpair and assign the plugin side FD to the channel + // name. Keep the renderer side FD as a member variable in the PluginChannel + // to be able to transmit it through IPC. + int plugin_fd; + if (!IPC::SocketPair(&plugin_fd, &renderer_fd_)) + return false; + IPC::AddChannelSocket(channel_key, plugin_fd); +#endif + + if (!dispatcher_->InitWithChannel( + ChildProcess::current()->io_message_loop(), + channel_key, false, + ChildProcess::current()->GetShutDownEvent())) + return false; + + handle->name = channel_key; +#if defined(OS_POSIX) + // On POSIX, pass the renderer-side FD. + handle->socket = base::FileDescriptor(renderer_fd_, false); +#endif + return true; +} + +#if defined(OS_POSIX) +void PpapiThread::CloseRendererFD() { + if (renderer_fd_ != -1) { + if (HANDLE_EINTR(close(renderer_fd_)) < 0) + PLOG(ERROR) << "close"; + renderer_fd_ = -1; + } +} +#endif diff --git a/chrome/ppapi_plugin/ppapi_thread.h b/chrome/ppapi_plugin/ppapi_thread.h new file mode 100644 index 0000000..ed7b024 --- /dev/null +++ b/chrome/ppapi_plugin/ppapi_thread.h @@ -0,0 +1,67 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_PPAPI_PLUGIN_PPAPI_THREAD_H_ +#define CHROME_PPAPI_PLUGIN_PPAPI_THREAD_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/scoped_native_library.h" +#include "base/scoped_ptr.h" +#include "build/build_config.h" +#include "chrome/common/child_thread.h" + +class FilePath; + +namespace IPC { +struct ChannelHandle; +} + +namespace pp { +namespace proxy { +class PluginDispatcher; +} +} + +class PpapiThread : public ChildThread { + public: + PpapiThread(); + ~PpapiThread(); + + private: + // ChildThread overrides. + virtual void OnMessageReceived(const IPC::Message& msg); + + // Message handlers. + void OnLoadPlugin(const FilePath& path, int renderer_id); + + bool LoadPluginLib(const FilePath& path); + + // Sets up the channel to the given renderer. On success, returns true and + // fills the given ChannelHandle with the information from the new channel. + bool SetupRendererChannel(int renderer_id, + IPC::ChannelHandle* handle); + +#if defined(OS_POSIX) + // Close the plugin process' copy of the renderer's side of the plugin + // channel. This can be called after the renderer is known to have its own + // copy of renderer_fd_. + void CloseRendererFD(); +#endif + + base::ScopedNativeLibrary library_; + + scoped_ptr<pp::proxy::PluginDispatcher> dispatcher_; + +#if defined(OS_POSIX) + // FD for the renderer end of the socket. It is closed when the IPC layer + // indicates that the channel is connected, proving that the renderer has + // access to its side of the socket. + int renderer_fd_; +#endif + + DISALLOW_COPY_AND_ASSIGN(PpapiThread); +}; + +#endif // CHROME_PPAPI_PLUGIN_PPAPI_THREAD_H_ |