1 // Copyright 2014 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 "ppapi/nacl_irt/ppapi_dispatcher.h"
10 #include "base/command_line.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "build/build_config.h"
15 #include "components/tracing/child_trace_message_filter.h"
16 #include "ipc/ipc_channel_handle.h"
17 #include "ipc/ipc_logging.h"
18 #include "ipc/ipc_message.h"
19 #include "ppapi/c/ppp.h"
20 #include "ppapi/c/ppp_instance.h"
21 #include "ppapi/nacl_irt/manifest_service.h"
22 #include "ppapi/nacl_irt/plugin_startup.h"
23 #include "ppapi/proxy/plugin_dispatcher.h"
24 #include "ppapi/proxy/plugin_globals.h"
25 #include "ppapi/proxy/plugin_message_filter.h"
26 #include "ppapi/proxy/plugin_proxy_delegate.h"
27 #include "ppapi/proxy/ppapi_messages.h"
28 #include "ppapi/proxy/resource_reply_thread_registrar.h"
32 PpapiDispatcher::PpapiDispatcher(
33 scoped_refptr
<base::SingleThreadTaskRunner
> io_task_runner
,
34 base::WaitableEvent
* shutdown_event
,
37 : next_plugin_dispatcher_id_(0),
38 task_runner_(io_task_runner
),
39 shutdown_event_(shutdown_event
),
40 renderer_ipc_fd_(renderer_ipc_fd
) {
41 IPC::ChannelHandle
channel_handle(
42 "NaCl IPC", base::FileDescriptor(browser_ipc_fd
, false));
44 proxy::PluginGlobals
* globals
= proxy::PluginGlobals::Get();
45 // Delay initializing the SyncChannel until after we add filters. This
46 // ensures that the filters won't miss any messages received by
49 IPC::SyncChannel::Create(this, GetIPCTaskRunner(), GetShutdownEvent());
50 scoped_refptr
<ppapi::proxy::PluginMessageFilter
> plugin_filter(
51 new ppapi::proxy::PluginMessageFilter(
52 NULL
, globals
->resource_reply_thread_registrar()));
53 channel_
->AddFilter(plugin_filter
.get());
54 globals
->RegisterResourceMessageFilters(plugin_filter
.get());
56 channel_
->AddFilter(new tracing::ChildTraceMessageFilter(task_runner_
.get()));
57 channel_
->Init(channel_handle
, IPC::Channel::MODE_SERVER
, true);
60 base::SingleThreadTaskRunner
* PpapiDispatcher::GetIPCTaskRunner() {
61 return task_runner_
.get();
64 base::WaitableEvent
* PpapiDispatcher::GetShutdownEvent() {
65 return shutdown_event_
;
68 IPC::PlatformFileForTransit
PpapiDispatcher::ShareHandleWithRemote(
69 base::PlatformFile handle
,
70 base::ProcessId peer_pid
,
71 bool should_close_source
) {
72 return IPC::InvalidPlatformFileForTransit();
75 base::SharedMemoryHandle
PpapiDispatcher::ShareSharedMemoryHandleWithRemote(
76 const base::SharedMemoryHandle
& handle
,
77 base::ProcessId remote_pid
) {
78 return base::SharedMemory::NULLHandle();
81 std::set
<PP_Instance
>* PpapiDispatcher::GetGloballySeenInstanceIDSet() {
85 uint32
PpapiDispatcher::Register(proxy::PluginDispatcher
* plugin_dispatcher
) {
86 if (!plugin_dispatcher
||
87 plugin_dispatchers_
.size() >= std::numeric_limits
<uint32
>::max()) {
93 // Although it is unlikely, make sure that we won't cause any trouble
94 // when the counter overflows.
95 id
= next_plugin_dispatcher_id_
++;
97 plugin_dispatchers_
.find(id
) != plugin_dispatchers_
.end());
98 plugin_dispatchers_
[id
] = plugin_dispatcher
;
102 void PpapiDispatcher::Unregister(uint32 plugin_dispatcher_id
) {
103 plugin_dispatchers_
.erase(plugin_dispatcher_id
);
106 IPC::Sender
* PpapiDispatcher::GetBrowserSender() {
110 std::string
PpapiDispatcher::GetUILanguage() {
112 return std::string();
115 void PpapiDispatcher::PreCacheFont(const void* logfontw
) {
119 void PpapiDispatcher::SetActiveURL(const std::string
& url
) {
123 PP_Resource
PpapiDispatcher::CreateBrowserFont(
124 proxy::Connection connection
,
125 PP_Instance instance
,
126 const PP_BrowserFont_Trusted_Description
& desc
,
127 const Preferences
& prefs
) {
132 bool PpapiDispatcher::OnMessageReceived(const IPC::Message
& msg
) {
133 IPC_BEGIN_MESSAGE_MAP(PpapiDispatcher
, msg
)
134 IPC_MESSAGE_HANDLER(PpapiMsg_InitializeNaClDispatcher
,
135 OnMsgInitializeNaClDispatcher
)
136 // All other messages are simply forwarded to a PluginDispatcher.
137 IPC_MESSAGE_UNHANDLED(OnPluginDispatcherMessageReceived(msg
))
138 IPC_END_MESSAGE_MAP()
142 void PpapiDispatcher::OnChannelError() {
146 bool PpapiDispatcher::Send(IPC::Message
* msg
) {
147 return channel_
->Send(msg
);
150 void PpapiDispatcher::OnMsgInitializeNaClDispatcher(
151 const PpapiNaClPluginArgs
& args
) {
152 static bool command_line_and_logging_initialized
= false;
153 if (command_line_and_logging_initialized
) {
154 LOG(FATAL
) << "InitializeNaClDispatcher must be called once per plugin.";
158 command_line_and_logging_initialized
= true;
159 base::CommandLine::Init(0, NULL
);
160 for (size_t i
= 0; i
< args
.switch_names
.size(); ++i
) {
161 DCHECK(i
< args
.switch_values
.size());
162 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
163 args
.switch_names
[i
], args
.switch_values
[i
]);
165 logging::LoggingSettings settings
;
166 settings
.logging_dest
= logging::LOG_TO_SYSTEM_DEBUG_LOG
;
167 logging::InitLogging(settings
);
169 proxy::PluginGlobals::Get()->set_keepalive_throttle_interval_milliseconds(
170 args
.keepalive_throttle_interval_milliseconds
);
172 // Tell the process-global GetInterface which interfaces it can return to the
174 proxy::InterfaceList::SetProcessGlobalPermissions(args
.permissions
);
176 int32_t error
= ::PPP_InitializeModule(
178 &proxy::PluginDispatcher::GetBrowserInterface
);
182 proxy::PluginDispatcher
* dispatcher
=
183 new proxy::PluginDispatcher(::PPP_GetInterface
, args
.permissions
,
184 args
.off_the_record
);
185 IPC::ChannelHandle
channel_handle(
187 base::FileDescriptor(renderer_ipc_fd_
, false));
188 if (!dispatcher
->InitPluginWithChannel(this, base::kNullProcessId
,
189 channel_handle
, false)) {
193 // From here, the dispatcher will manage its own lifetime according to the
194 // lifetime of the attached channel.
196 // Notify the renderer process, if necessary.
197 ManifestService
* manifest_service
= GetManifestService();
198 if (manifest_service
)
199 manifest_service
->StartupInitializationComplete();
202 void PpapiDispatcher::OnPluginDispatcherMessageReceived(
203 const IPC::Message
& msg
) {
204 // The first parameter should be a plugin dispatcher ID.
205 base::PickleIterator
iter(msg
);
207 if (!iter
.ReadUInt32(&id
)) {
211 std::map
<uint32
, proxy::PluginDispatcher
*>::iterator dispatcher
=
212 plugin_dispatchers_
.find(id
);
213 if (dispatcher
!= plugin_dispatchers_
.end())
214 dispatcher
->second
->OnMessageReceived(msg
);