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/proxy_lock.h"
17 #include "ppapi/thunk/enter.h"
21 const int kKeepaliveThrottleIntervalDefault = 5000;
28 // It performs necessary locking/unlocking of the proxy lock, and forwards all
29 // messages to the underlying sender.
30 class PluginGlobals::BrowserSender : public IPC::Sender {
32 // |underlying_sender| must outlive this object.
33 explicit BrowserSender(IPC::Sender* underlying_sender)
34 : underlying_sender_(underlying_sender) {
37 virtual ~BrowserSender() {}
39 // IPC::Sender implementation.
40 virtual bool Send(IPC::Message* msg) OVERRIDE {
42 // Synchronous messages might be re-entrant, so we need to drop the lock.
43 ProxyAutoUnlock unlock;
44 return underlying_sender_->Send(msg);
47 return underlying_sender_->Send(msg);
51 // Non-owning pointer.
52 IPC::Sender* underlying_sender_;
54 DISALLOW_COPY_AND_ASSIGN(BrowserSender);
57 PluginGlobals* PluginGlobals::plugin_globals_ = NULL;
59 PluginGlobals::PluginGlobals()
60 : ppapi::PpapiGlobals(),
61 plugin_proxy_delegate_(NULL),
62 callback_tracker_(new CallbackTracker),
63 resource_reply_thread_registrar_(
64 new ResourceReplyThreadRegistrar(GetMainThreadMessageLoop())),
65 plugin_recently_active_(false),
66 keepalive_throttle_interval_milliseconds_(
67 kKeepaliveThrottleIntervalDefault),
69 DCHECK(!plugin_globals_);
70 plugin_globals_ = this;
72 // ResourceTracker asserts that we have the lock when we add new resources,
73 // so we lock when creating the MessageLoopResource even though there is no
74 // chance of race conditions.
76 loop_for_main_thread_ =
77 new MessageLoopResource(MessageLoopResource::ForMainThread());
80 PluginGlobals::PluginGlobals(PerThreadForTest per_thread_for_test)
81 : ppapi::PpapiGlobals(per_thread_for_test),
82 plugin_proxy_delegate_(NULL),
83 callback_tracker_(new CallbackTracker),
84 resource_reply_thread_registrar_(
85 new ResourceReplyThreadRegistrar(GetMainThreadMessageLoop())),
86 plugin_recently_active_(false),
87 keepalive_throttle_interval_milliseconds_(
88 kKeepaliveThrottleIntervalDefault),
90 DCHECK(!plugin_globals_);
93 PluginGlobals::~PluginGlobals() {
94 DCHECK(plugin_globals_ == this || !plugin_globals_);
97 // Release the main-thread message loop. We should have the last reference
98 // count, so this will delete the MessageLoop resource. We do this before
99 // we clear plugin_globals_, because the Resource destructor tries to access
100 // this PluginGlobals.
101 DCHECK(!loop_for_main_thread_.get() || loop_for_main_thread_->HasOneRef());
102 loop_for_main_thread_ = NULL;
104 plugin_globals_ = NULL;
107 ResourceTracker* PluginGlobals::GetResourceTracker() {
108 return &plugin_resource_tracker_;
111 VarTracker* PluginGlobals::GetVarTracker() {
112 return &plugin_var_tracker_;
115 CallbackTracker* PluginGlobals::GetCallbackTrackerForInstance(
116 PP_Instance instance) {
117 // In the plugin process, the callback tracker is always the same, regardless
119 return callback_tracker_.get();
122 thunk::PPB_Instance_API* PluginGlobals::GetInstanceAPI(PP_Instance instance) {
123 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
125 return dispatcher->GetInstanceAPI();
129 thunk::ResourceCreationAPI* PluginGlobals::GetResourceCreationAPI(
130 PP_Instance instance) {
131 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
133 return dispatcher->GetResourceCreationAPI();
137 PP_Module PluginGlobals::GetModuleForInstance(PP_Instance instance) {
138 // Currently proxied plugins don't use the PP_Module for anything useful.
142 std::string PluginGlobals::GetCmdLine() {
143 return command_line_;
146 void PluginGlobals::PreCacheFontForFlash(const void* logfontw) {
147 ProxyAutoUnlock unlock;
148 plugin_proxy_delegate_->PreCacheFont(logfontw);
151 void PluginGlobals::LogWithSource(PP_Instance instance,
153 const std::string& source,
154 const std::string& value) {
155 const std::string& fixed_up_source = source.empty() ? plugin_name_ : source;
156 PluginDispatcher::LogWithSource(instance, level, fixed_up_source, value);
159 void PluginGlobals::BroadcastLogWithSource(PP_Module /* module */,
161 const std::string& source,
162 const std::string& value) {
163 // Since we have only one module in a plugin process, broadcast is always
164 // the same as "send to everybody" which is what the dispatcher implements
165 // for the "instance = 0" case.
166 LogWithSource(0, level, source, value);
169 MessageLoopShared* PluginGlobals::GetCurrentMessageLoop() {
170 return MessageLoopResource::GetCurrent();
173 base::TaskRunner* PluginGlobals::GetFileTaskRunner() {
174 if (!file_thread_.get()) {
175 file_thread_.reset(new base::Thread("Plugin::File"));
176 base::Thread::Options options;
177 options.message_loop_type = base::MessageLoop::TYPE_IO;
178 file_thread_->StartWithOptions(options);
180 return file_thread_->message_loop_proxy();
183 void PluginGlobals::MarkPluginIsActive() {
184 if (!plugin_recently_active_) {
185 plugin_recently_active_ = true;
186 if (!GetBrowserSender() || !base::MessageLoop::current())
188 GetBrowserSender()->Send(new PpapiHostMsg_Keepalive());
190 GetMainThreadMessageLoop()->PostDelayedTask(FROM_HERE,
191 RunWhileLocked(base::Bind(&PluginGlobals::OnReleaseKeepaliveThrottle,
192 weak_factory_.GetWeakPtr())),
193 base::TimeDelta::FromMilliseconds(
194 keepalive_throttle_interval_milliseconds()));
198 IPC::Sender* PluginGlobals::GetBrowserSender() {
199 if (!browser_sender_.get()) {
200 browser_sender_.reset(
201 new BrowserSender(plugin_proxy_delegate_->GetBrowserSender()));
204 return browser_sender_.get();
207 std::string PluginGlobals::GetUILanguage() {
208 return plugin_proxy_delegate_->GetUILanguage();
211 void PluginGlobals::SetActiveURL(const std::string& url) {
212 plugin_proxy_delegate_->SetActiveURL(url);
215 PP_Resource PluginGlobals::CreateBrowserFont(
216 Connection connection,
217 PP_Instance instance,
218 const PP_BrowserFont_Trusted_Description& desc,
219 const ppapi::Preferences& prefs) {
220 return plugin_proxy_delegate_->CreateBrowserFont(
221 connection, instance, desc, prefs);
224 MessageLoopResource* PluginGlobals::loop_for_main_thread() {
225 return loop_for_main_thread_.get();
228 int PluginGlobals::keepalive_throttle_interval_milliseconds() const {
229 return keepalive_throttle_interval_milliseconds_;
232 void PluginGlobals::set_keepalive_throttle_interval_milliseconds(int i) {
233 keepalive_throttle_interval_milliseconds_ = i;
236 bool PluginGlobals::IsPluginGlobals() const {
240 void PluginGlobals::OnReleaseKeepaliveThrottle() {
241 ppapi::ProxyLock::AssertAcquiredDebugOnly();
242 plugin_recently_active_ = false;