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.
4
5 #include "ppapi/proxy/plugin_globals.h"
6
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"
19
20 namespace ppapi {
21 namespace proxy {
22
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 {
26 public:
27 // |underlying_sender| must outlive this object.
BrowserSender(IPC::Sender * underlying_sender)28 explicit BrowserSender(IPC::Sender* underlying_sender)
29 : underlying_sender_(underlying_sender) {
30 }
31
~BrowserSender()32 virtual ~BrowserSender() {}
33
34 // IPC::Sender implementation.
Send(IPC::Message * msg)35 virtual bool Send(IPC::Message* msg) OVERRIDE {
36 if (msg->is_sync()) {
37 // Synchronous messages might be re-entrant, so we need to drop the lock.
38 ProxyAutoUnlock unlock;
39 return underlying_sender_->Send(msg);
40 }
41
42 return underlying_sender_->Send(msg);
43 }
44
45 private:
46 // Non-owning pointer.
47 IPC::Sender* underlying_sender_;
48
49 DISALLOW_COPY_AND_ASSIGN(BrowserSender);
50 };
51
52 PluginGlobals* PluginGlobals::plugin_globals_ = NULL;
53
PluginGlobals()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),
63 weak_factory_(this) {
64 DCHECK(!plugin_globals_);
65 plugin_globals_ = this;
66
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.
70 ProxyAutoLock lock;
71 loop_for_main_thread_ =
72 new MessageLoopResource(MessageLoopResource::ForMainThread());
73 }
74
PluginGlobals(PerThreadForTest per_thread_for_test)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),
84 weak_factory_(this) {
85 DCHECK(!plugin_globals_);
86 }
87
~PluginGlobals()88 PluginGlobals::~PluginGlobals() {
89 DCHECK(plugin_globals_ == this || !plugin_globals_);
90 {
91 ProxyAutoLock lock;
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;
98 }
99 plugin_globals_ = NULL;
100 }
101
GetResourceTracker()102 ResourceTracker* PluginGlobals::GetResourceTracker() {
103 return &plugin_resource_tracker_;
104 }
105
GetVarTracker()106 VarTracker* PluginGlobals::GetVarTracker() {
107 return &plugin_var_tracker_;
108 }
109
GetCallbackTrackerForInstance(PP_Instance instance)110 CallbackTracker* PluginGlobals::GetCallbackTrackerForInstance(
111 PP_Instance instance) {
112 // In the plugin process, the callback tracker is always the same, regardless
113 // of the instance.
114 return callback_tracker_.get();
115 }
116
GetInstanceAPI(PP_Instance instance)117 thunk::PPB_Instance_API* PluginGlobals::GetInstanceAPI(PP_Instance instance) {
118 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
119 if (dispatcher)
120 return dispatcher->GetInstanceAPI();
121 return NULL;
122 }
123
GetResourceCreationAPI(PP_Instance instance)124 thunk::ResourceCreationAPI* PluginGlobals::GetResourceCreationAPI(
125 PP_Instance instance) {
126 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
127 if (dispatcher)
128 return dispatcher->GetResourceCreationAPI();
129 return NULL;
130 }
131
GetModuleForInstance(PP_Instance instance)132 PP_Module PluginGlobals::GetModuleForInstance(PP_Instance instance) {
133 // Currently proxied plugins don't use the PP_Module for anything useful.
134 return 0;
135 }
136
GetCmdLine()137 std::string PluginGlobals::GetCmdLine() {
138 return command_line_;
139 }
140
PreCacheFontForFlash(const void * logfontw)141 void PluginGlobals::PreCacheFontForFlash(const void* logfontw) {
142 ProxyAutoUnlock unlock;
143 plugin_proxy_delegate_->PreCacheFont(logfontw);
144 }
145
LogWithSource(PP_Instance instance,PP_LogLevel level,const std::string & source,const std::string & value)146 void PluginGlobals::LogWithSource(PP_Instance instance,
147 PP_LogLevel level,
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);
152 }
153
BroadcastLogWithSource(PP_Module,PP_LogLevel level,const std::string & source,const std::string & value)154 void PluginGlobals::BroadcastLogWithSource(PP_Module /* module */,
155 PP_LogLevel level,
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);
162 }
163
GetCurrentMessageLoop()164 MessageLoopShared* PluginGlobals::GetCurrentMessageLoop() {
165 return MessageLoopResource::GetCurrent();
166 }
167
GetFileTaskRunner()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);
174 }
175 return file_thread_->message_loop_proxy().get();
176 }
177
MarkPluginIsActive()178 void PluginGlobals::MarkPluginIsActive() {
179 if (!plugin_recently_active_) {
180 plugin_recently_active_ = true;
181 if (!GetBrowserSender() || !base::MessageLoop::current())
182 return;
183 GetBrowserSender()->Send(new PpapiHostMsg_Keepalive());
184 DCHECK(keepalive_throttle_interval_milliseconds_);
185 GetMainThreadMessageLoop()->PostDelayedTask(
186 FROM_HERE,
187 RunWhileLocked(base::Bind(&PluginGlobals::OnReleaseKeepaliveThrottle,
188 weak_factory_.GetWeakPtr())),
189 base::TimeDelta::FromMilliseconds(
190 keepalive_throttle_interval_milliseconds_));
191 }
192 }
193
GetBrowserSender()194 IPC::Sender* PluginGlobals::GetBrowserSender() {
195 // CAUTION: This function is called without the ProxyLock. See also
196 // InterfaceList::GetInterfaceForPPB.
197 //
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();
203 }
204
GetUILanguage()205 std::string PluginGlobals::GetUILanguage() {
206 return plugin_proxy_delegate_->GetUILanguage();
207 }
208
SetActiveURL(const std::string & url)209 void PluginGlobals::SetActiveURL(const std::string& url) {
210 plugin_proxy_delegate_->SetActiveURL(url);
211 }
212
CreateBrowserFont(Connection connection,PP_Instance instance,const PP_BrowserFont_Trusted_Description & desc,const ppapi::Preferences & prefs)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);
220 }
221
SetPluginProxyDelegate(PluginProxyDelegate * delegate)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()));
227 }
228
ResetPluginProxyDelegate()229 void PluginGlobals::ResetPluginProxyDelegate() {
230 DCHECK(plugin_proxy_delegate_);
231 plugin_proxy_delegate_ = NULL;
232 browser_sender_.reset();
233 }
234
loop_for_main_thread()235 MessageLoopResource* PluginGlobals::loop_for_main_thread() {
236 return loop_for_main_thread_.get();
237 }
238
set_keepalive_throttle_interval_milliseconds(unsigned i)239 void PluginGlobals::set_keepalive_throttle_interval_milliseconds(unsigned i) {
240 keepalive_throttle_interval_milliseconds_ = i;
241 }
242
IsPluginGlobals() const243 bool PluginGlobals::IsPluginGlobals() const {
244 return true;
245 }
246
OnReleaseKeepaliveThrottle()247 void PluginGlobals::OnReleaseKeepaliveThrottle() {
248 ppapi::ProxyLock::AssertAcquiredDebugOnly();
249 plugin_recently_active_ = false;
250 }
251
252 } // namespace proxy
253 } // namespace ppapi
254