blob: 7b5c4db65f4c490f0462213ab8ae45220ebf2ed8 [file] [log] [blame]
// Copyright 2014 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/plugin_power_saver_helper.h"
#include <string>
#include "base/command_line.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/common/frame_messages.h"
#include "content/public/common/content_switches.h"
#include "content/public/renderer/render_frame.h"
#include "content/renderer/peripheral_content_heuristic.h"
#include "ppapi/shared_impl/ppapi_constants.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "ui/gfx/geometry/size.h"
namespace content {
namespace {
const char kPeripheralHeuristicHistogram[] =
"Plugin.PowerSaver.PeripheralHeuristicInitialDecision";
} // namespace
PluginPowerSaverHelper::PeripheralPlugin::PeripheralPlugin(
const url::Origin& content_origin,
const base::Closure& unthrottle_callback)
: content_origin(content_origin),
unthrottle_callback(unthrottle_callback) {}
PluginPowerSaverHelper::PeripheralPlugin::PeripheralPlugin(
const PeripheralPlugin& other) = default;
PluginPowerSaverHelper::PeripheralPlugin::~PeripheralPlugin() {
}
PluginPowerSaverHelper::PluginPowerSaverHelper(RenderFrame* render_frame)
: RenderFrameObserver(render_frame) {}
PluginPowerSaverHelper::~PluginPowerSaverHelper() {
}
void PluginPowerSaverHelper::DidCommitProvisionalLoad(
bool is_same_document_navigation,
ui::PageTransition transition) {
blink::WebFrame* frame = render_frame()->GetWebFrame();
// Only apply to top-level and new page navigation.
if (frame->Parent() || is_same_document_navigation)
return; // Not a top-level navigation.
origin_whitelist_.clear();
}
bool PluginPowerSaverHelper::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PluginPowerSaverHelper, message)
IPC_MESSAGE_HANDLER(FrameMsg_UpdatePluginContentOriginWhitelist,
OnUpdatePluginContentOriginWhitelist)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PluginPowerSaverHelper::OnDestruct() {
delete this;
}
void PluginPowerSaverHelper::OnUpdatePluginContentOriginWhitelist(
const std::set<url::Origin>& origin_whitelist) {
origin_whitelist_ = origin_whitelist;
// Check throttled plugin instances to see if any can be unthrottled.
auto it = peripheral_plugins_.begin();
while (it != peripheral_plugins_.end()) {
if (origin_whitelist.count(it->content_origin)) {
// Because the unthrottle callback may register another peripheral plugin
// and invalidate our iterator, we cannot run it synchronously.
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
it->unthrottle_callback);
it = peripheral_plugins_.erase(it);
} else {
++it;
}
}
}
void PluginPowerSaverHelper::RegisterPeripheralPlugin(
const url::Origin& content_origin,
const base::Closure& unthrottle_callback) {
peripheral_plugins_.push_back(
PeripheralPlugin(content_origin, unthrottle_callback));
}
RenderFrame::PeripheralContentStatus
PluginPowerSaverHelper::GetPeripheralContentStatus(
const url::Origin& main_frame_origin,
const url::Origin& content_origin,
const gfx::Size& unobscured_size,
RenderFrame::RecordPeripheralDecision record_decision) const {
if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kOverridePluginPowerSaverForTesting) == "always") {
return RenderFrame::CONTENT_STATUS_PERIPHERAL;
}
auto status = PeripheralContentHeuristic::GetPeripheralStatus(
origin_whitelist_, main_frame_origin, content_origin, unobscured_size);
if (record_decision == RenderFrame::RECORD_DECISION) {
UMA_HISTOGRAM_ENUMERATION(kPeripheralHeuristicHistogram, status,
RenderFrame::CONTENT_STATUS_NUM_ITEMS);
}
return status;
}
void PluginPowerSaverHelper::WhitelistContentOrigin(
const url::Origin& content_origin) {
if (origin_whitelist_.insert(content_origin).second) {
Send(new FrameHostMsg_PluginContentOriginAllowed(
render_frame()->GetRoutingID(), content_origin));
}
}
} // namespace content