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 #ifndef CONTENT_RENDERER_PEPPER_PEPPER_HUNG_PLUGIN_FILTER_H_
6 #define CONTENT_RENDERER_PEPPER_PEPPER_HUNG_PLUGIN_FILTER_H_
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"
18 // This class monitors a renderer <-> pepper plugin channel on the I/O thread
19 // of the renderer for a hung plugin.
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.
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.
29 // NOTE: This class is refcounted (via IPC::MessageFilter).
30 class PepperHungPluginFilter
31 : public ppapi::proxy::HostDispatcher::SyncMessageStatusObserver,
32 public IPC::MessageFilter {
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,
42 // SyncMessageStatusReceiver implementation.
43 virtual void BeginBlockOnSyncMessage() OVERRIDE;
44 virtual void EndBlockOnSyncMessage() OVERRIDE;
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;
53 virtual ~PepperHungPluginFilter();
56 // Makes sure that the hung timer is scheduled.
57 void EnsureTimerScheduled();
59 // Checks whether the plugin could have transitioned from hung to unhung and
60 // notifies the browser if so.
61 void MayHaveBecomeUnhung();
63 // Calculate the point at which the plugin could next be considered hung.
64 base::TimeTicks GetHungTime() const;
66 // Checks if the plugin is considered hung based on whether it has been
67 // blocked for long enough.
70 // Timer handler that checks for a hang after a timeout.
73 // Sends the hung/unhung message to the browser process.
74 void SendHungMessage(bool is_hung);
78 base::FilePath plugin_path_;
79 int frame_routing_id_;
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_;
87 scoped_refptr<base::MessageLoopProxy> io_loop_;
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.
92 // This will be is_null() if we've never blocked.
93 base::TimeTicks began_blocking_time_;
95 // Time that the last message was received from the plugin.
97 // This will be is_null() if we've never received any messages.
98 base::TimeTicks last_message_received_;
100 // Number of nested sync messages that we're blocked on.
101 int pending_sync_message_count_;
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_;
108 bool timer_task_pending_;
110 DISALLOW_COPY_AND_ASSIGN(PepperHungPluginFilter);
113 } // namespace content
115 #endif // CONTENT_RENDERER_PEPPER_PEPPER_HUNG_PLUGIN_FILTER_H_