| 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
|
|
|