Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1400)

Unified Diff: content/renderer/pepper/pepper_hung_plugin_filter.cc

Issue 10014013: Add a hang monitor for Pepper plugins (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/pepper/pepper_hung_plugin_filter.cc
diff --git a/content/renderer/pepper/pepper_hung_plugin_filter.cc b/content/renderer/pepper/pepper_hung_plugin_filter.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4da00fc16431cf1c17951e09f5b215b6f2c2af58
--- /dev/null
+++ b/content/renderer/pepper/pepper_hung_plugin_filter.cc
@@ -0,0 +1,153 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/pepper/pepper_hung_plugin_filter.h"
+
+#include "base/bind.h"
+#include "content/common/view_messages.h"
+#include "content/renderer/render_thread_impl.h"
+
+namespace content {
+
+namespace {
+
+// We'll consider the plugin hung after not hearing anything for this long.
+const int kHungThresholdSec = 10;
+
+// If we ever are blocked for this long, we'll consider the plugin hung, even
+// if we continue to get messages (which is why the above hung threshold never
+// kicked in). Maybe the plugin is spamming us with events and never unblocking
+// and never processing our sync message.
+const int kBlockedHardThresholdSec = kHungThresholdSec * 1.5;
+
+} // namespace
+
+PepperHungPluginFilter::PepperHungPluginFilter(const FilePath& plugin_path,
+ int view_routing_id,
+ int plugin_child_id)
+ : plugin_path_(plugin_path),
+ view_routing_id_(view_routing_id),
+ plugin_child_id_(plugin_child_id),
+ filter_(RenderThread::Get()->GetSyncMessageFilter()),
+ io_loop_(RenderThreadImpl::current()->GetIOLoopProxy()),
+ pending_sync_message_count_(0),
+ hung_plugin_showing_(false),
+ timer_task_pending_(false) {
+}
+
+PepperHungPluginFilter::~PepperHungPluginFilter() {
+}
+
+void PepperHungPluginFilter::BeginBlockOnSyncMessage() {
+ base::AutoLock lock(lock_);
+ if (pending_sync_message_count_ == 0)
+ began_blocking_time_ = base::TimeTicks::Now();
+ pending_sync_message_count_++;
+
+ EnsureTimerScheduled();
+}
+
+void PepperHungPluginFilter::EndBlockOnSyncMessage() {
+ base::AutoLock lock(lock_);
+ pending_sync_message_count_--;
+ DCHECK(pending_sync_message_count_ >= 0);
+
+ MayHaveBecomeUnhung();
+}
+
+void PepperHungPluginFilter::OnFilterAdded(IPC::Channel* channel) {
+}
+
+void PepperHungPluginFilter::OnFilterRemoved() {
+ base::AutoLock lock(lock_);
+ MayHaveBecomeUnhung();
+}
+
+void PepperHungPluginFilter::OnChannelError() {
+ base::AutoLock lock(lock_);
+ MayHaveBecomeUnhung();
+}
+
+bool PepperHungPluginFilter::OnMessageReceived(const IPC::Message& message) {
+ // Just track incoming message times but don't handle any messages.
+ base::AutoLock lock(lock_);
+ last_message_received_ = base::TimeTicks::Now();
+ MayHaveBecomeUnhung();
+ return false;
+}
+
+void PepperHungPluginFilter::EnsureTimerScheduled() {
+ lock_.AssertAcquired();
+ if (timer_task_pending_)
+ return;
+
+ timer_task_pending_ = true;
+ io_loop_->PostDelayedTask(FROM_HERE,
+ base::Bind(&PepperHungPluginFilter::OnHangTimer, this),
+ base::TimeDelta::FromSeconds(kHungThresholdSec));
+}
+
+void PepperHungPluginFilter::MayHaveBecomeUnhung() {
+ if (!hung_plugin_showing_ || IsHung())
+ return;
+
+ SendHungMessage(false);
+ hung_plugin_showing_ = false;
+}
+
+bool PepperHungPluginFilter::IsHung() const {
+ lock_.AssertAcquired();
+
+ if (!pending_sync_message_count_)
+ return false; // Not blocked on a sync message.
+
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ DCHECK(!began_blocking_time_.is_null());
+ if (now - began_blocking_time_ >=
+ base::TimeDelta::FromSeconds(kBlockedHardThresholdSec))
+ return true; // Been blocked too long regardless of what the plugin is
+ // sending us.
+
+ base::TimeDelta hung_threshold =
+ base::TimeDelta::FromSeconds(kHungThresholdSec);
+ if (now - began_blocking_time_ >= hung_threshold &&
+ (last_message_received_.is_null() ||
+ now - last_message_received_ >= hung_threshold))
+ return true; // Blocked and haven't received a message in too long.
+
+ return false;
+}
+
+void PepperHungPluginFilter::OnHangTimer() {
+ base::AutoLock lock(lock_);
+ timer_task_pending_ = false;
+
+ if (!IsHung()) {
+ if (pending_sync_message_count_ > 0) {
+ // Got a timer message while we're waiting on a sync message. We need
+ // to schedule another timer message because the latest sync message
+ // would not have scheduled one (we only have one out-standing timer at
+ // a time).
+ DCHECK(!began_blocking_time_.is_null());
+ base::TimeDelta delay =
+ base::TimeDelta::FromSeconds(kHungThresholdSec) -
+ (base::TimeTicks::Now() - began_blocking_time_);
+ io_loop_->PostDelayedTask(FROM_HERE,
+ base::Bind(&PepperHungPluginFilter::OnHangTimer, this),
+ delay);
+ }
+ return;
+ }
+
+ hung_plugin_showing_ = true;
+ SendHungMessage(true);
+}
+
+void PepperHungPluginFilter::SendHungMessage(bool is_hung) {
+ filter_->Send(new ViewHostMsg_PepperPluginHung(
+ view_routing_id_, plugin_child_id_, plugin_path_, is_hung));
+}
+
+} // namespace content
« no previous file with comments | « content/renderer/pepper/pepper_hung_plugin_filter.h ('k') | content/renderer/pepper/pepper_plugin_delegate_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698