Home | History | Annotate | Download | only in proxy
      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.
     28   explicit BrowserSender(IPC::Sender* underlying_sender)
     29       : underlying_sender_(underlying_sender) {
     30   }
     31 
     32   virtual ~BrowserSender() {}
     33 
     34   // IPC::Sender implementation.
     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 
     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 
     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 
     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 
    102 ResourceTracker* PluginGlobals::GetResourceTracker() {
    103   return &plugin_resource_tracker_;
    104 }
    105 
    106 VarTracker* PluginGlobals::GetVarTracker() {
    107   return &plugin_var_tracker_;
    108 }
    109 
    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 
    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 
    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 
    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 
    137 std::string PluginGlobals::GetCmdLine() {
    138   return command_line_;
    139 }
    140 
    141 void PluginGlobals::PreCacheFontForFlash(const void* logfontw) {
    142   ProxyAutoUnlock unlock;
    143   plugin_proxy_delegate_->PreCacheFont(logfontw);
    144 }
    145 
    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 
    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 
    164 MessageLoopShared* PluginGlobals::GetCurrentMessageLoop() {
    165   return MessageLoopResource::GetCurrent();
    166 }
    167 
    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 
    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 
    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 
    205 std::string PluginGlobals::GetUILanguage() {
    206   return plugin_proxy_delegate_->GetUILanguage();
    207 }
    208 
    209 void PluginGlobals::SetActiveURL(const std::string& url) {
    210   plugin_proxy_delegate_->SetActiveURL(url);
    211 }
    212 
    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 
    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 
    229 void PluginGlobals::ResetPluginProxyDelegate() {
    230   DCHECK(plugin_proxy_delegate_);
    231   plugin_proxy_delegate_ = NULL;
    232   browser_sender_.reset();
    233 }
    234 
    235 MessageLoopResource* PluginGlobals::loop_for_main_thread() {
    236   return loop_for_main_thread_.get();
    237 }
    238 
    239 void PluginGlobals::set_keepalive_throttle_interval_milliseconds(unsigned i) {
    240   keepalive_throttle_interval_milliseconds_ = i;
    241 }
    242 
    243 bool PluginGlobals::IsPluginGlobals() const {
    244   return true;
    245 }
    246 
    247 void PluginGlobals::OnReleaseKeepaliveThrottle() {
    248   ppapi::ProxyLock::AssertAcquiredDebugOnly();
    249   plugin_recently_active_ = false;
    250 }
    251 
    252 }  // namespace proxy
    253 }  // namespace ppapi
    254