Home | History | Annotate | Download | only in pepper
      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 #ifndef CONTENT_RENDERER_PEPPER_PEPPER_HUNG_PLUGIN_FILTER_H_
      6 #define CONTENT_RENDERER_PEPPER_PEPPER_HUNG_PLUGIN_FILTER_H_
      7 
      8 #include "base/files/file_path.h"
      9 #include "base/memory/ref_counted.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/synchronization/lock.h"
     12 #include "ipc/ipc_channel_proxy.h"
     13 #include "ipc/ipc_sync_message_filter.h"
     14 #include "ppapi/proxy/host_dispatcher.h"
     15 
     16 namespace content {
     17 
     18 // This class monitors a renderer <-> pepper plugin channel on the I/O thread
     19 // of the renderer for a hung plugin.
     20 //
     21 // If the plugin is not responding to sync messages, it will notify the browser
     22 // process and give the user the option to kill the hung plugin.
     23 //
     24 // Note that this class must be threadsafe since it will get the begin/end
     25 // block notifications on the main thread, but the filter is run on the I/O
     26 // thread. This is important since when we're blocked on a sync message to a
     27 // hung plugin, the main thread is frozen.
     28 //
     29 // NOTE: This class is refcounted (via SyncMessageStatusReceiver).
     30 class PepperHungPluginFilter
     31     : public ppapi::proxy::HostDispatcher::SyncMessageStatusReceiver {
     32  public:
     33   // The |view_routing_id| is the ID of the render_view so that this class can
     34   // send messages to the browser via that view's route. The |plugin_child_id|
     35   // is the ID in the browser process of the pepper plugin process host. We use
     36   // this to identify the proper plugin process to terminate.
     37   PepperHungPluginFilter(const base::FilePath& plugin_path,
     38                          int view_routing_id,
     39                          int plugin_child_id);
     40 
     41   // SyncMessageStatusReceiver implementation.
     42   virtual void BeginBlockOnSyncMessage() OVERRIDE;
     43   virtual void EndBlockOnSyncMessage() OVERRIDE;
     44 
     45   // MessageFilter implementation.
     46   virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE;
     47   virtual void OnFilterRemoved() OVERRIDE;
     48   virtual void OnChannelError() OVERRIDE;
     49   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
     50 
     51  protected:
     52   virtual ~PepperHungPluginFilter();
     53 
     54  private:
     55   // Makes sure that the hung timer is scheduled.
     56   void EnsureTimerScheduled();
     57 
     58   // Checks whether the plugin could have transitioned from hung to unhung and
     59   // notifies the browser if so.
     60   void MayHaveBecomeUnhung();
     61 
     62   // Calculate the point at which the plugin could next be considered hung.
     63   base::TimeTicks GetHungTime() const;
     64 
     65   // Checks if the plugin is considered hung based on whether it has been
     66   // blocked for long enough.
     67   bool IsHung() const;
     68 
     69   // Timer handler that checks for a hang after a timeout.
     70   void OnHangTimer();
     71 
     72   // Sends the hung/unhung message to the browser process.
     73   void SendHungMessage(bool is_hung);
     74 
     75   base::Lock lock_;
     76 
     77   base::FilePath plugin_path_;
     78   int view_routing_id_;
     79   int plugin_child_id_;
     80 
     81   // Used to post messages to the renderer <-> browser message channel from
     82   // other threads without having to worry about the lifetime of that object.
     83   // We don't actually use the "sync" feature of this filter.
     84   scoped_refptr<IPC::SyncMessageFilter> filter_;
     85 
     86   scoped_refptr<base::MessageLoopProxy> io_loop_;
     87 
     88   // The time when we start being blocked on a sync message. If there are
     89   // nested ones, this is the time of the outermost one.
     90   //
     91   // This will be is_null() if we've never blocked.
     92   base::TimeTicks began_blocking_time_;
     93 
     94   // Time that the last message was received from the plugin.
     95   //
     96   // This will be is_null() if we've never received any messages.
     97   base::TimeTicks last_message_received_;
     98 
     99   // Number of nested sync messages that we're blocked on.
    100   int pending_sync_message_count_;
    101 
    102   // True when we've sent the "plugin is hung" message to the browser. We track
    103   // this so we know to look for it becoming unhung and send the corresponding
    104   // message to the browser.
    105   bool hung_plugin_showing_;
    106 
    107   bool timer_task_pending_;
    108 
    109   DISALLOW_COPY_AND_ASSIGN(PepperHungPluginFilter);
    110 };
    111 
    112 }  // namespace content
    113 
    114 #endif  // CONTENT_RENDERER_PEPPER_PEPPER_HUNG_PLUGIN_FILTER_H_
    115