1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// 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(base::ProcessHandle host_process_handle,
const FilePath& path,
int renderer_id) {
IPC::ChannelHandle channel_handle;
if (!LoadPluginLib(host_process_handle, 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(base::ProcessHandle host_process_handle,
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(
host_process_handle, 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
|