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 IPC::MessageFilter).
     30 class PepperHungPluginFilter
     31     : public ppapi::proxy::HostDispatcher::SyncMessageStatusObserver,
     32       public IPC::MessageFilter {
     33  public:
     34   // The |frame_routing_id| is the ID of the render_frame so that this class can
     35   // send messages to the browser via that frame's route. The |plugin_child_id|
     36   // is the ID in the browser process of the pepper plugin process host. We use
     37   // this to identify the proper plugin process to terminate.
     38   PepperHungPluginFilter(const base::FilePath& plugin_path,
     39                          int frame_routing_id,
     40                          int plugin_child_id);
     41 
     42   // SyncMessageStatusReceiver implementation.
     43   virtual void BeginBlockOnSyncMessage() OVERRIDE;
     44   virtual void EndBlockOnSyncMessage() OVERRIDE;
     45 
     46   // MessageFilter implementation.
     47   virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE;
     48   virtual void OnFilterRemoved() OVERRIDE;
     49   virtual void OnChannelError() OVERRIDE;
     50   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
     51 
     52  protected:
     53   virtual ~PepperHungPluginFilter();
     54 
     55  private:
     56   // Makes sure that the hung timer is scheduled.
     57   void EnsureTimerScheduled();
     58 
     59   // Checks whether the plugin could have transitioned from hung to unhung and
     60   // notifies the browser if so.
     61   void MayHaveBecomeUnhung();
     62 
     63   // Calculate the point at which the plugin could next be considered hung.
     64   base::TimeTicks GetHungTime() const;
     65 
     66   // Checks if the plugin is considered hung based on whether it has been
     67   // blocked for long enough.
     68   bool IsHung() const;
     69 
     70   // Timer handler that checks for a hang after a timeout.
     71   void OnHangTimer();
     72 
     73   // Sends the hung/unhung message to the browser process.
     74   void SendHungMessage(bool is_hung);
     75 
     76   base::Lock lock_;
     77 
     78   base::FilePath plugin_path_;
     79   int frame_routing_id_;
     80   int plugin_child_id_;
     81 
     82   // Used to post messages to the renderer <-> browser message channel from
     83   // other threads without having to worry about the lifetime of that object.
     84   // We don't actually use the "sync" feature of this filter.
     85   scoped_refptr<IPC::SyncMessageFilter> filter_;
     86 
     87   scoped_refptr<base::MessageLoopProxy> io_loop_;
     88 
     89   // The time when we start being blocked on a sync message. If there are
     90   // nested ones, this is the time of the outermost one.
     91   //
     92   // This will be is_null() if we've never blocked.
     93   base::TimeTicks began_blocking_time_;
     94 
     95   // Time that the last message was received from the plugin.
     96   //
     97   // This will be is_null() if we've never received any messages.
     98   base::TimeTicks last_message_received_;
     99 
    100   // Number of nested sync messages that we're blocked on.
    101   int pending_sync_message_count_;
    102 
    103   // True when we've sent the "plugin is hung" message to the browser. We track
    104   // this so we know to look for it becoming unhung and send the corresponding
    105   // message to the browser.
    106   bool hung_plugin_showing_;
    107 
    108   bool timer_task_pending_;
    109 
    110   DISALLOW_COPY_AND_ASSIGN(PepperHungPluginFilter);
    111 };
    112 
    113 }  // namespace content
    114 
    115 #endif  // CONTENT_RENDERER_PEPPER_PEPPER_HUNG_PLUGIN_FILTER_H_
    116