1 // Copyright 2014 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 #include "content/renderer/pepper/pepper_plugin_instance_throttler.h"
7 #include "base/metrics/histogram.h"
8 #include "base/metrics/sparse_histogram.h"
9 #include "base/time/time.h"
10 #include "content/public/common/content_constants.h"
11 #include "content/public/renderer/render_thread.h"
12 #include "third_party/WebKit/public/web/WebInputEvent.h"
13 #include "ui/gfx/color_utils.h"
20 static const int kInfiniteRatio
= 99999;
22 #define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \
23 UMA_HISTOGRAM_SPARSE_SLOWLY( \
24 name, (height) ? ((width)*100) / (height) : kInfiniteRatio);
26 // Histogram tracking prevalence of tiny Flash instances. Units in pixels.
27 enum PluginFlashTinyContentSize
{
28 TINY_CONTENT_SIZE_1_1
= 0,
29 TINY_CONTENT_SIZE_5_5
= 1,
30 TINY_CONTENT_SIZE_10_10
= 2,
31 TINY_CONTENT_SIZE_LARGE
= 3,
32 TINY_CONTENT_SIZE_NUM_ITEMS
35 // How the throttled power saver is unthrottled, if ever.
36 // These numeric values are used in UMA logs; do not change them.
37 enum PowerSaverUnthrottleMethod
{
38 UNTHROTTLE_METHOD_NEVER
= 0,
39 UNTHROTTLE_METHOD_BY_CLICK
= 1,
40 UNTHROTTLE_METHOD_BY_WHITELIST
= 2,
41 UNTHROTTLE_METHOD_NUM_ITEMS
44 const char kFlashClickSizeAspectRatioHistogram
[] =
45 "Plugin.Flash.ClickSize.AspectRatio";
46 const char kFlashClickSizeHeightHistogram
[] = "Plugin.Flash.ClickSize.Height";
47 const char kFlashClickSizeWidthHistogram
[] = "Plugin.Flash.ClickSize.Width";
48 const char kFlashTinyContentSizeHistogram
[] = "Plugin.Flash.TinyContentSize";
49 const char kPowerSaverUnthrottleHistogram
[] = "Plugin.PowerSaver.Unthrottle";
51 // Record size metrics for all Flash instances.
52 void RecordFlashSizeMetric(int width
, int height
) {
53 PluginFlashTinyContentSize size
= TINY_CONTENT_SIZE_LARGE
;
55 if (width
<= 1 && height
<= 1)
56 size
= TINY_CONTENT_SIZE_1_1
;
57 else if (width
<= 5 && height
<= 5)
58 size
= TINY_CONTENT_SIZE_5_5
;
59 else if (width
<= 10 && height
<= 10)
60 size
= TINY_CONTENT_SIZE_10_10
;
62 UMA_HISTOGRAM_ENUMERATION(kFlashTinyContentSizeHistogram
, size
,
63 TINY_CONTENT_SIZE_NUM_ITEMS
);
66 void RecordUnthrottleMethodMetric(PowerSaverUnthrottleMethod method
) {
67 UMA_HISTOGRAM_ENUMERATION(kPowerSaverUnthrottleHistogram
, method
,
68 UNTHROTTLE_METHOD_NUM_ITEMS
);
71 // Records size metrics for Flash instances that are clicked.
72 void RecordFlashClickSizeMetric(int width
, int height
) {
73 base::HistogramBase
* width_histogram
= base::LinearHistogram::FactoryGet(
74 kFlashClickSizeWidthHistogram
,
77 100, // number of buckets.
78 base::HistogramBase::kUmaTargetedHistogramFlag
);
79 width_histogram
->Add(width
);
81 base::HistogramBase
* height_histogram
= base::LinearHistogram::FactoryGet(
82 kFlashClickSizeHeightHistogram
,
84 400, // maximum height
85 100, // number of buckets.
86 base::HistogramBase::kUmaTargetedHistogramFlag
);
87 height_histogram
->Add(height
);
89 UMA_HISTOGRAM_ASPECT_RATIO(kFlashClickSizeAspectRatioHistogram
, width
,
93 // When we give up waiting for a suitable preview frame, and simply suspend
94 // the plugin where it's at. In milliseconds.
95 const int kThrottleTimeout
= 5000;
97 // Threshold for 'boring' score to accept a frame as good enough to be a
98 // representative keyframe. Units are the ratio of all pixels that are within
99 // the most common luma bin. The same threshold is used for history thumbnails.
100 const double kAcceptableFrameMaximumBoringness
= 0.94;
102 const int kMinimumConsecutiveInterestingFrames
= 4;
106 PepperPluginInstanceThrottler::PepperPluginInstanceThrottler(
108 const blink::WebRect
& bounds
,
109 const std::string
& module_name
,
110 const GURL
& plugin_url
,
111 RenderFrame::PluginPowerSaverMode power_saver_mode
,
112 const base::Closure
& throttle_change_callback
)
114 throttle_change_callback_(throttle_change_callback
),
115 is_flash_plugin_(module_name
== kFlashPluginName
),
116 needs_representative_keyframe_(false),
117 consecutive_interesting_frames_(0),
118 has_been_clicked_(false),
119 power_saver_enabled_(false),
120 is_peripheral_content_(power_saver_mode
!=
121 RenderFrame::POWER_SAVER_MODE_ESSENTIAL
),
122 plugin_throttled_(false),
123 weak_factory_(this) {
124 if (is_flash_plugin_
&& RenderThread::Get()) {
125 RenderThread::Get()->RecordAction(
126 base::UserMetricsAction("Flash.PluginInstanceCreated"));
127 RecordFlashSizeMetric(bounds
.width
, bounds
.height
);
130 power_saver_enabled_
=
132 power_saver_mode
== RenderFrame::POWER_SAVER_MODE_PERIPHERAL_THROTTLED
;
134 GURL content_origin
= plugin_url
.GetOrigin();
136 // To collect UMAs, register peripheral content even if power saver disabled.
138 frame
->RegisterPeripheralPlugin(
139 content_origin
, base::Bind(&PepperPluginInstanceThrottler::
140 DisablePowerSaverByRetroactiveWhitelist
,
141 weak_factory_
.GetWeakPtr()));
144 if (power_saver_enabled_
) {
145 needs_representative_keyframe_
= true;
146 base::MessageLoop::current()->PostDelayedTask(
148 base::Bind(&PepperPluginInstanceThrottler::SetPluginThrottled
,
149 weak_factory_
.GetWeakPtr(), true /* throttled */),
150 base::TimeDelta::FromMilliseconds(kThrottleTimeout
));
154 PepperPluginInstanceThrottler::~PepperPluginInstanceThrottler() {
157 void PepperPluginInstanceThrottler::OnImageFlush(const SkBitmap
* bitmap
) {
158 if (!needs_representative_keyframe_
|| !bitmap
)
161 double boring_score
= color_utils::CalculateBoringScore(*bitmap
);
162 if (boring_score
<= kAcceptableFrameMaximumBoringness
)
163 ++consecutive_interesting_frames_
;
165 consecutive_interesting_frames_
= 0;
167 if (consecutive_interesting_frames_
>= kMinimumConsecutiveInterestingFrames
)
168 SetPluginThrottled(true);
171 bool PepperPluginInstanceThrottler::ConsumeInputEvent(
172 const blink::WebInputEvent
& event
) {
173 if (!has_been_clicked_
&& is_flash_plugin_
&&
174 event
.type
== blink::WebInputEvent::MouseDown
) {
175 has_been_clicked_
= true;
176 RecordFlashClickSizeMetric(bounds_
.width
, bounds_
.height
);
179 if (event
.type
== blink::WebInputEvent::MouseUp
&& is_peripheral_content_
) {
180 is_peripheral_content_
= false;
181 power_saver_enabled_
= false;
183 RecordUnthrottleMethodMetric(UNTHROTTLE_METHOD_BY_CLICK
);
185 if (plugin_throttled_
) {
186 SetPluginThrottled(false /* throttled */);
191 return plugin_throttled_
;
194 void PepperPluginInstanceThrottler::SetPluginThrottled(bool throttled
) {
195 // Do not throttle if we've already disabled power saver.
196 if (!power_saver_enabled_
&& throttled
)
199 // Once we change the throttle state, we will never need the snapshot again.
200 needs_representative_keyframe_
= false;
202 plugin_throttled_
= throttled
;
203 throttle_change_callback_
.Run();
206 void PepperPluginInstanceThrottler::DisablePowerSaverByRetroactiveWhitelist() {
207 if (!is_peripheral_content_
)
210 is_peripheral_content_
= false;
211 power_saver_enabled_
= false;
212 SetPluginThrottled(false);
214 RecordUnthrottleMethodMetric(UNTHROTTLE_METHOD_BY_WHITELIST
);
217 } // namespace content