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 "ppapi/proxy/plugin_globals.h"
7 #include "base/task_runner.h"
8 #include "base/threading/thread.h"
9 #include "ipc/ipc_message.h"
10 #include "ipc/ipc_sender.h"
11 #include "ppapi/proxy/plugin_dispatcher.h"
12 #include "ppapi/proxy/plugin_proxy_delegate.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/proxy/ppb_message_loop_proxy.h"
15 #include "ppapi/proxy/resource_reply_thread_registrar.h"
16 #include "ppapi/shared_impl/ppapi_constants.h"
17 #include "ppapi/shared_impl/proxy_lock.h"
18 #include "ppapi/thunk/enter.h"
23 // It performs necessary locking/unlocking of the proxy lock, and forwards all
24 // messages to the underlying sender.
25 class PluginGlobals::BrowserSender
: public IPC::Sender
{
27 // |underlying_sender| must outlive this object.
28 explicit BrowserSender(IPC::Sender
* underlying_sender
)
29 : underlying_sender_(underlying_sender
) {
32 virtual ~BrowserSender() {}
34 // IPC::Sender implementation.
35 virtual bool Send(IPC::Message
* msg
) override
{
37 // Synchronous messages might be re-entrant, so we need to drop the lock.
38 ProxyAutoUnlock unlock
;
39 return underlying_sender_
->Send(msg
);
42 return underlying_sender_
->Send(msg
);
46 // Non-owning pointer.
47 IPC::Sender
* underlying_sender_
;
49 DISALLOW_COPY_AND_ASSIGN(BrowserSender
);
52 PluginGlobals
* PluginGlobals::plugin_globals_
= NULL
;
54 PluginGlobals::PluginGlobals()
55 : ppapi::PpapiGlobals(),
56 plugin_proxy_delegate_(NULL
),
57 callback_tracker_(new CallbackTracker
),
58 resource_reply_thread_registrar_(
59 new ResourceReplyThreadRegistrar(GetMainThreadMessageLoop())),
60 plugin_recently_active_(false),
61 keepalive_throttle_interval_milliseconds_(
62 ppapi::kKeepaliveThrottleIntervalDefaultMilliseconds
),
64 DCHECK(!plugin_globals_
);
65 plugin_globals_
= this;
67 // ResourceTracker asserts that we have the lock when we add new resources,
68 // so we lock when creating the MessageLoopResource even though there is no
69 // chance of race conditions.
71 loop_for_main_thread_
=
72 new MessageLoopResource(MessageLoopResource::ForMainThread());
75 PluginGlobals::PluginGlobals(PerThreadForTest per_thread_for_test
)
76 : ppapi::PpapiGlobals(per_thread_for_test
),
77 plugin_proxy_delegate_(NULL
),
78 callback_tracker_(new CallbackTracker
),
79 resource_reply_thread_registrar_(
80 new ResourceReplyThreadRegistrar(GetMainThreadMessageLoop())),
81 plugin_recently_active_(false),
82 keepalive_throttle_interval_milliseconds_(
83 kKeepaliveThrottleIntervalDefaultMilliseconds
),
85 DCHECK(!plugin_globals_
);
88 PluginGlobals::~PluginGlobals() {
89 DCHECK(plugin_globals_
== this || !plugin_globals_
);
92 // Release the main-thread message loop. We should have the last reference
93 // count, so this will delete the MessageLoop resource. We do this before
94 // we clear plugin_globals_, because the Resource destructor tries to access
95 // this PluginGlobals.
96 DCHECK(!loop_for_main_thread_
.get() || loop_for_main_thread_
->HasOneRef());
97 loop_for_main_thread_
= NULL
;
99 plugin_globals_
= NULL
;
102 ResourceTracker
* PluginGlobals::GetResourceTracker() {
103 return &plugin_resource_tracker_
;
106 VarTracker
* PluginGlobals::GetVarTracker() {
107 return &plugin_var_tracker_
;
110 CallbackTracker
* PluginGlobals::GetCallbackTrackerForInstance(
111 PP_Instance instance
) {
112 // In the plugin process, the callback tracker is always the same, regardless
114 return callback_tracker_
.get();
117 thunk::PPB_Instance_API
* PluginGlobals::GetInstanceAPI(PP_Instance instance
) {
118 PluginDispatcher
* dispatcher
= PluginDispatcher::GetForInstance(instance
);
120 return dispatcher
->GetInstanceAPI();
124 thunk::ResourceCreationAPI
* PluginGlobals::GetResourceCreationAPI(
125 PP_Instance instance
) {
126 PluginDispatcher
* dispatcher
= PluginDispatcher::GetForInstance(instance
);
128 return dispatcher
->GetResourceCreationAPI();
132 PP_Module
PluginGlobals::GetModuleForInstance(PP_Instance instance
) {
133 // Currently proxied plugins don't use the PP_Module for anything useful.
137 std::string
PluginGlobals::GetCmdLine() {
138 return command_line_
;
141 void PluginGlobals::PreCacheFontForFlash(const void* logfontw
) {
142 ProxyAutoUnlock unlock
;
143 plugin_proxy_delegate_
->PreCacheFont(logfontw
);
146 void PluginGlobals::LogWithSource(PP_Instance instance
,
148 const std::string
& source
,
149 const std::string
& value
) {
150 const std::string
& fixed_up_source
= source
.empty() ? plugin_name_
: source
;
151 PluginDispatcher::LogWithSource(instance
, level
, fixed_up_source
, value
);
154 void PluginGlobals::BroadcastLogWithSource(PP_Module
/* module */,
156 const std::string
& source
,
157 const std::string
& value
) {
158 // Since we have only one module in a plugin process, broadcast is always
159 // the same as "send to everybody" which is what the dispatcher implements
160 // for the "instance = 0" case.
161 LogWithSource(0, level
, source
, value
);
164 MessageLoopShared
* PluginGlobals::GetCurrentMessageLoop() {
165 return MessageLoopResource::GetCurrent();
168 base::TaskRunner
* PluginGlobals::GetFileTaskRunner() {
169 if (!file_thread_
.get()) {
170 file_thread_
.reset(new base::Thread("Plugin::File"));
171 base::Thread::Options options
;
172 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
173 file_thread_
->StartWithOptions(options
);
175 return file_thread_
->message_loop_proxy().get();
178 void PluginGlobals::MarkPluginIsActive() {
179 if (!plugin_recently_active_
) {
180 plugin_recently_active_
= true;
181 if (!GetBrowserSender() || !base::MessageLoop::current())
183 GetBrowserSender()->Send(new PpapiHostMsg_Keepalive());
184 DCHECK(keepalive_throttle_interval_milliseconds_
);
185 GetMainThreadMessageLoop()->PostDelayedTask(
187 RunWhileLocked(base::Bind(&PluginGlobals::OnReleaseKeepaliveThrottle
,
188 weak_factory_
.GetWeakPtr())),
189 base::TimeDelta::FromMilliseconds(
190 keepalive_throttle_interval_milliseconds_
));
194 IPC::Sender
* PluginGlobals::GetBrowserSender() {
195 // CAUTION: This function is called without the ProxyLock. See also
196 // InterfaceList::GetInterfaceForPPB.
198 // See also SetPluginProxyDelegate. That initializes browser_sender_ before
199 // the plugin can start threads, and it may be cleared after the
200 // plugin has torn down threads. So this pointer is expected to remain valid
201 // during the lifetime of the plugin.
202 return browser_sender_
.get();
205 std::string
PluginGlobals::GetUILanguage() {
206 return plugin_proxy_delegate_
->GetUILanguage();
209 void PluginGlobals::SetActiveURL(const std::string
& url
) {
210 plugin_proxy_delegate_
->SetActiveURL(url
);
213 PP_Resource
PluginGlobals::CreateBrowserFont(
214 Connection connection
,
215 PP_Instance instance
,
216 const PP_BrowserFont_Trusted_Description
& desc
,
217 const ppapi::Preferences
& prefs
) {
218 return plugin_proxy_delegate_
->CreateBrowserFont(
219 connection
, instance
, desc
, prefs
);
222 void PluginGlobals::SetPluginProxyDelegate(PluginProxyDelegate
* delegate
) {
223 DCHECK(delegate
&& !plugin_proxy_delegate_
);
224 plugin_proxy_delegate_
= delegate
;
225 browser_sender_
.reset(
226 new BrowserSender(plugin_proxy_delegate_
->GetBrowserSender()));
229 void PluginGlobals::ResetPluginProxyDelegate() {
230 DCHECK(plugin_proxy_delegate_
);
231 plugin_proxy_delegate_
= NULL
;
232 browser_sender_
.reset();
235 MessageLoopResource
* PluginGlobals::loop_for_main_thread() {
236 return loop_for_main_thread_
.get();
239 void PluginGlobals::set_keepalive_throttle_interval_milliseconds(unsigned i
) {
240 keepalive_throttle_interval_milliseconds_
= i
;
243 bool PluginGlobals::IsPluginGlobals() const {
247 void PluginGlobals::OnReleaseKeepaliveThrottle() {
248 ppapi::ProxyLock::AssertAcquiredDebugOnly();
249 plugin_recently_active_
= false;