1 // Copyright (c) 2012 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.
5 #include "content/ppapi_plugin/ppapi_thread.h"
9 #include "base/command_line.h"
10 #include "base/process_util.h"
11 #include "base/rand_util.h"
12 #include "base/stringprintf.h"
13 #include "base/utf_string_conversions.h"
14 #include "content/common/child_process.h"
15 #include "content/common/child_process_messages.h"
16 #include "content/ppapi_plugin/broker_process_dispatcher.h"
17 #include "content/ppapi_plugin/plugin_process_dispatcher.h"
18 #include "content/ppapi_plugin/ppapi_webkitplatformsupport_impl.h"
19 #include "content/public/common/content_client.h"
20 #include "content/public/common/pepper_plugin_info.h"
21 #include "content/public/common/sandbox_init.h"
22 #include "content/public/plugin/content_plugin_client.h"
23 #include "ipc/ipc_channel_handle.h"
24 #include "ipc/ipc_platform_file.h"
25 #include "ipc/ipc_sync_channel.h"
26 #include "ipc/ipc_sync_message_filter.h"
27 #include "ppapi/c/dev/ppp_network_state_dev.h"
28 #include "ppapi/c/pp_errors.h"
29 #include "ppapi/c/ppp.h"
30 #include "ppapi/proxy/plugin_globals.h"
31 #include "ppapi/proxy/ppapi_messages.h"
32 #include "ppapi/proxy/interface_list.h"
33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
34 #include "ui/base/ui_base_switches.h"
35 #include "webkit/plugins/plugin_switches.h"
38 #include "base/win/win_util.h"
39 #include "sandbox/win/src/sandbox.h"
40 #elif defined(OS_MACOSX)
41 #include "content/common/sandbox_init_mac.h"
45 extern sandbox::TargetServices
* g_target_services
;
47 extern void* g_target_services
;
52 typedef int32_t (*InitializeBrokerFunc
)
53 (PP_ConnectInstance_Func
* connect_instance_func
);
55 PpapiThread::PpapiThread(const CommandLine
& command_line
, bool is_broker
)
56 : is_broker_(is_broker
),
57 connect_instance_func_(NULL
),
59 base::RandInt(0, std::numeric_limits
<PP_Module
>::max())),
60 next_plugin_dispatcher_id_(1) {
61 ppapi::proxy::PluginGlobals
* globals
= ppapi::proxy::PluginGlobals::Get();
62 globals
->set_plugin_proxy_delegate(this);
63 globals
->set_command_line(
64 command_line
.GetSwitchValueASCII(switches::kPpapiFlashArgs
));
65 if (command_line
.HasSwitch(switches::kDisablePepperThreading
)) {
66 globals
->set_enable_threading(false);
67 } else if (command_line
.HasSwitch(switches::kEnablePepperThreading
)) {
68 globals
->set_enable_threading(true);
70 globals
->set_enable_threading(false);
73 webkit_platform_support_
.reset(new PpapiWebKitPlatformSupportImpl
);
74 WebKit::initialize(webkit_platform_support_
.get());
77 PpapiThread::~PpapiThread() {
78 ppapi::proxy::PluginGlobals::Get()->set_plugin_proxy_delegate(NULL
);
79 if (plugin_entry_points_
.shutdown_module
)
80 plugin_entry_points_
.shutdown_module();
84 if (permissions_
.HasPermission(ppapi::PERMISSION_FLASH
))
85 base::win::SetShouldCrashOnProcessDetach(false);
89 bool PpapiThread::Send(IPC::Message
* msg
) {
90 // Allow access from multiple threads.
91 if (MessageLoop::current() == message_loop())
92 return ChildThread::Send(msg
);
94 return sync_message_filter()->Send(msg
);
97 // The "regular" ChildThread implements this function and does some standard
98 // dispatching, then uses the message router. We don't actually need any of
99 // this so this function just overrides that one.
101 // Note that this function is called only for messages from the channel to the
102 // browser process. Messages from the renderer process are sent via a different
103 // channel that ends up at Dispatcher::OnMessageReceived.
104 bool PpapiThread::OnMessageReceived(const IPC::Message
& msg
) {
105 IPC_BEGIN_MESSAGE_MAP(PpapiThread
, msg
)
106 IPC_MESSAGE_HANDLER(PpapiMsg_LoadPlugin
, OnMsgLoadPlugin
)
107 IPC_MESSAGE_HANDLER(PpapiMsg_CreateChannel
, OnMsgCreateChannel
)
109 IPC_MESSAGE_HANDLER(PpapiPluginMsg_ResourceReply
, OnMsgResourceReply
)
111 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBTCPServerSocket_ListenACK
,
112 OnPluginDispatcherMessageReceived(msg
))
113 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBTCPServerSocket_AcceptACK
,
114 OnPluginDispatcherMessageReceived(msg
))
115 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBTCPSocket_ConnectACK
,
116 OnPluginDispatcherMessageReceived(msg
))
117 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBTCPSocket_SSLHandshakeACK
,
118 OnPluginDispatcherMessageReceived(msg
))
119 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBTCPSocket_ReadACK
,
120 OnPluginDispatcherMessageReceived(msg
))
121 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBTCPSocket_WriteACK
,
122 OnPluginDispatcherMessageReceived(msg
))
123 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBUDPSocket_RecvFromACK
,
124 OnPluginDispatcherMessageReceived(msg
))
125 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBUDPSocket_SendToACK
,
126 OnPluginDispatcherMessageReceived(msg
))
127 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBUDPSocket_BindACK
,
128 OnPluginDispatcherMessageReceived(msg
))
129 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBHostResolver_ResolveACK
,
130 OnPluginDispatcherMessageReceived(msg
))
131 IPC_MESSAGE_HANDLER_GENERIC(PpapiMsg_PPBNetworkMonitor_NetworkList
,
132 OnPluginDispatcherMessageReceived(msg
))
133 IPC_MESSAGE_HANDLER(PpapiMsg_SetNetworkState
, OnMsgSetNetworkState
)
134 IPC_END_MESSAGE_MAP()
138 void PpapiThread::OnChannelConnected(int32 peer_pid
) {
139 ChildThread::OnChannelConnected(peer_pid
);
142 peer_handle_
.Set(::OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, peer_pid
));
146 base::MessageLoopProxy
* PpapiThread::GetIPCMessageLoop() {
147 return ChildProcess::current()->io_message_loop_proxy();
150 base::WaitableEvent
* PpapiThread::GetShutdownEvent() {
151 return ChildProcess::current()->GetShutDownEvent();
154 IPC::PlatformFileForTransit
PpapiThread::ShareHandleWithRemote(
155 base::PlatformFile handle
,
156 const IPC::SyncChannel
& channel
,
157 bool should_close_source
) {
159 if (peer_handle_
.IsValid()) {
161 return IPC::GetFileHandleForProcess(handle
, peer_handle_
,
162 should_close_source
);
166 return BrokerGetFileHandleForProcess(handle
, channel
.peer_pid(),
167 should_close_source
);
170 std::set
<PP_Instance
>* PpapiThread::GetGloballySeenInstanceIDSet() {
171 return &globally_seen_instance_ids_
;
174 IPC::Sender
* PpapiThread::GetBrowserSender() {
178 std::string
PpapiThread::GetUILanguage() {
179 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
180 return command_line
->GetSwitchValueASCII(switches::kLang
);
183 void PpapiThread::PreCacheFont(const void* logfontw
) {
185 Send(new ChildProcessHostMsg_PreCacheFont(
186 *static_cast<const LOGFONTW
*>(logfontw
)));
190 void PpapiThread::SetActiveURL(const std::string
& url
) {
191 GetContentClient()->SetActiveURL(GURL(url
));
194 uint32
PpapiThread::Register(ppapi::proxy::PluginDispatcher
* plugin_dispatcher
) {
195 if (!plugin_dispatcher
||
196 plugin_dispatchers_
.size() >= std::numeric_limits
<uint32
>::max()) {
202 // Although it is unlikely, make sure that we won't cause any trouble when
203 // the counter overflows.
204 id
= next_plugin_dispatcher_id_
++;
206 plugin_dispatchers_
.find(id
) != plugin_dispatchers_
.end());
207 plugin_dispatchers_
[id
] = plugin_dispatcher
;
211 void PpapiThread::Unregister(uint32 plugin_dispatcher_id
) {
212 plugin_dispatchers_
.erase(plugin_dispatcher_id
);
215 void PpapiThread::OnMsgLoadPlugin(const FilePath
& path
,
216 const ppapi::PpapiPermissions
& permissions
) {
217 SavePluginName(path
);
219 // This must be set before calling into the plugin so it can get the
220 // interfaces it has permission for.
221 ppapi::proxy::InterfaceList::SetProcessGlobalPermissions(permissions
);
222 permissions_
= permissions
;
224 // Trusted Pepper plugins may be "internal", i.e. built-in to the browser
225 // binary. If we're being asked to load such a plugin (e.g. the Chromoting
226 // client) then fetch the entry points from the embedder, rather than a DLL.
227 std::vector
<content::PepperPluginInfo
> plugins
;
228 GetContentClient()->AddPepperPlugins(&plugins
);
229 for (size_t i
= 0; i
< plugins
.size(); ++i
) {
230 if (plugins
[i
].is_internal
&& plugins
[i
].path
== path
) {
231 // An internal plugin is being loaded, so fetch the entry points.
232 plugin_entry_points_
= plugins
[i
].internal_entry_points
;
236 // If the plugin isn't internal then load it from |path|.
237 base::ScopedNativeLibrary library
;
238 if (plugin_entry_points_
.initialize_module
== NULL
) {
239 // Load the plugin from the specified library.
241 library
.Reset(base::LoadNativeLibrary(path
, &error
));
242 if (!library
.is_valid()) {
243 LOG(ERROR
) << "Failed to load Pepper module from "
244 << path
.value() << " (error: " << error
<< ")";
248 // Get the GetInterface function (required).
249 plugin_entry_points_
.get_interface
=
250 reinterpret_cast<PP_GetInterface_Func
>(
251 library
.GetFunctionPointer("PPP_GetInterface"));
252 if (!plugin_entry_points_
.get_interface
) {
253 LOG(WARNING
) << "No PPP_GetInterface in plugin library";
257 // The ShutdownModule/ShutdownBroker function is optional.
258 plugin_entry_points_
.shutdown_module
=
260 reinterpret_cast<PP_ShutdownModule_Func
>(
261 library
.GetFunctionPointer("PPP_ShutdownBroker")) :
262 reinterpret_cast<PP_ShutdownModule_Func
>(
263 library
.GetFunctionPointer("PPP_ShutdownModule"));
266 // Get the InitializeModule function (required for non-broker code).
267 plugin_entry_points_
.initialize_module
=
268 reinterpret_cast<PP_InitializeModule_Func
>(
269 library
.GetFunctionPointer("PPP_InitializeModule"));
270 if (!plugin_entry_points_
.initialize_module
) {
271 LOG(WARNING
) << "No PPP_InitializeModule in plugin library";
278 // If code subsequently tries to exit using abort(), force a crash (since
279 // otherwise these would be silent terminations and fly under the radar).
280 base::win::SetAbortBehaviorForCrashReporting();
281 if (permissions
.HasPermission(ppapi::PERMISSION_FLASH
)) {
282 // Force a crash for exit(), _exit(), or ExitProcess(), but only do that for
284 base::win::SetShouldCrashOnProcessDetach(true);
287 // Once we lower the token the sandbox is locked down and no new modules
288 // can be loaded. TODO(cpu): consider changing to the loading style of
290 if (g_target_services
) {
291 // Cause advapi32 to load before the sandbox is turned on.
292 unsigned int dummy_rand
;
294 // Warm up language subsystems before the sandbox is turned on.
295 ::GetUserDefaultLangID();
296 ::GetUserDefaultLCID();
298 g_target_services
->LowerToken();
303 // Get the InitializeBroker function (required).
304 InitializeBrokerFunc init_broker
=
305 reinterpret_cast<InitializeBrokerFunc
>(
306 library
.GetFunctionPointer("PPP_InitializeBroker"));
308 LOG(WARNING
) << "No PPP_InitializeBroker in plugin library";
312 int32_t init_error
= init_broker(&connect_instance_func_
);
313 if (init_error
!= PP_OK
) {
314 LOG(WARNING
) << "InitBroker failed with error " << init_error
;
317 if (!connect_instance_func_
) {
318 LOG(WARNING
) << "InitBroker did not provide PP_ConnectInstance_Func";
322 #if defined(OS_MACOSX)
323 // We need to do this after getting |PPP_GetInterface()| (or presumably
324 // doing something nontrivial with the library), else the sandbox
326 CHECK(InitializeSandbox());
329 int32_t init_error
= plugin_entry_points_
.initialize_module(
331 &ppapi::proxy::PluginDispatcher::GetBrowserInterface
);
332 if (init_error
!= PP_OK
) {
333 LOG(WARNING
) << "InitModule failed with error " << init_error
;
338 // Initialization succeeded, so keep the plugin DLL loaded.
339 library_
.Reset(library
.Release());
342 void PpapiThread::OnMsgCreateChannel(int renderer_id
, bool incognito
) {
343 IPC::ChannelHandle channel_handle
;
345 if (!plugin_entry_points_
.get_interface
|| // Plugin couldn't be loaded.
346 !SetupRendererChannel(renderer_id
, incognito
, &channel_handle
)) {
347 Send(new PpapiHostMsg_ChannelCreated(IPC::ChannelHandle()));
351 Send(new PpapiHostMsg_ChannelCreated(channel_handle
));
354 void PpapiThread::OnMsgResourceReply(
355 const ppapi::proxy::ResourceMessageReplyParams
& reply_params
,
356 const IPC::Message
& nested_msg
) {
357 ppapi::proxy::PluginDispatcher::DispatchResourceReply(reply_params
,
361 void PpapiThread::OnMsgSetNetworkState(bool online
) {
362 // Note the browser-process side shouldn't send us these messages in the
363 // first unless the plugin has dev permissions, so we don't need to check
364 // again here. We don't want random plugins depending on this dev interface.
365 if (!plugin_entry_points_
.get_interface
)
367 const PPP_NetworkState_Dev
* ns
= static_cast<const PPP_NetworkState_Dev
*>(
368 plugin_entry_points_
.get_interface(PPP_NETWORK_STATE_DEV_INTERFACE
));
370 ns
->SetOnLine(PP_FromBool(online
));
373 void PpapiThread::OnPluginDispatcherMessageReceived(const IPC::Message
& msg
) {
374 // The first parameter should be a plugin dispatcher ID.
375 PickleIterator
iter(msg
);
377 if (!msg
.ReadUInt32(&iter
, &id
)) {
381 std::map
<uint32
, ppapi::proxy::PluginDispatcher
*>::iterator dispatcher
=
382 plugin_dispatchers_
.find(id
);
383 if (dispatcher
!= plugin_dispatchers_
.end())
384 dispatcher
->second
->OnMessageReceived(msg
);
387 bool PpapiThread::SetupRendererChannel(int renderer_id
,
389 IPC::ChannelHandle
* handle
) {
390 DCHECK(is_broker_
== (connect_instance_func_
!= NULL
));
391 IPC::ChannelHandle plugin_handle
;
392 plugin_handle
.name
= IPC::Channel::GenerateVerifiedChannelID(
393 StringPrintf("%d.r%d", base::GetCurrentProcId(), renderer_id
));
395 ppapi::proxy::ProxyChannel
* dispatcher
= NULL
;
396 bool init_result
= false;
398 BrokerProcessDispatcher
* broker_dispatcher
=
399 new BrokerProcessDispatcher(plugin_entry_points_
.get_interface
,
400 connect_instance_func_
);
401 init_result
= broker_dispatcher
->InitBrokerWithChannel(this,
404 dispatcher
= broker_dispatcher
;
406 PluginProcessDispatcher
* plugin_dispatcher
=
407 new PluginProcessDispatcher(plugin_entry_points_
.get_interface
,
410 init_result
= plugin_dispatcher
->InitPluginWithChannel(this,
413 dispatcher
= plugin_dispatcher
;
421 handle
->name
= plugin_handle
.name
;
422 #if defined(OS_POSIX)
423 // On POSIX, transfer ownership of the renderer-side (client) FD.
424 // This ensures this process will be notified when it is closed even if a
425 // connection is not established.
426 handle
->socket
= base::FileDescriptor(dispatcher
->TakeRendererFD(), true);
427 if (handle
->socket
.fd
== -1)
431 // From here, the dispatcher will manage its own lifetime according to the
432 // lifetime of the attached channel.
436 void PpapiThread::SavePluginName(const FilePath
& path
) {
437 ppapi::proxy::PluginGlobals::Get()->set_plugin_name(
438 path
.BaseName().AsUTF8Unsafe());
440 // plugin() is NULL when in-process. Which is fine, because this is
441 // just a hook for setting the process name.
442 if (GetContentClient()->plugin()) {
443 GetContentClient()->plugin()->PluginProcessStarted(
444 path
.BaseName().RemoveExtension().LossyDisplayName());
448 } // namespace content