Commit ad90070a authored by Mounir Lamouri's avatar Mounir Lamouri Committed by Commit Bot

Autoplay: records metrics in UKM entries.

This is using the UKM service to record the autoplay attempts and
the unmute results.

Bug: 744659
Change-Id: Ice9a259a4006beff1044e5ed62981619841895e5
Reviewed-on: https://chromium-review.googlesource.com/525692
Commit-Queue: Mounir Lamouri <mlamouri@chromium.org>
Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarSteven Holte <holte@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Cr-Commit-Position: refs/heads/master@{#509384}
parent 51058e68
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
}, },
"requires": { "requires": {
"*": [ "app" ], "*": [ "app" ],
"content_browser": [ "renderer" ], "content_browser": [ "renderer", "url_keyed_metrics" ],
"device": [ "device": [
"device:power_monitor", "device:power_monitor",
"device:screen_orientation", "device:screen_orientation",
......
...@@ -30,9 +30,11 @@ class METRICS_EXPORT MojoUkmRecorder : public UkmRecorder { ...@@ -30,9 +30,11 @@ class METRICS_EXPORT MojoUkmRecorder : public UkmRecorder {
explicit MojoUkmRecorder(mojom::UkmRecorderInterfacePtr interface); explicit MojoUkmRecorder(mojom::UkmRecorderInterfacePtr interface);
~MojoUkmRecorder() override; ~MojoUkmRecorder() override;
private:
// UkmRecorder: // UkmRecorder:
void UpdateSourceURL(SourceId source_id, const GURL& url) override; void UpdateSourceURL(SourceId source_id, const GURL& url) override;
private:
// UkmRecorder:
void AddEntry(mojom::UkmEntryPtr entry) override; void AddEntry(mojom::UkmEntryPtr entry) override;
mojom::UkmRecorderInterfacePtr interface_; mojom::UkmRecorderInterfacePtr interface_;
......
...@@ -26,6 +26,10 @@ class SubresourceFilterMetricsObserver; ...@@ -26,6 +26,10 @@ class SubresourceFilterMetricsObserver;
class UkmPageLoadMetricsObserver; class UkmPageLoadMetricsObserver;
class LocalNetworkRequestsPageLoadMetricsObserver; class LocalNetworkRequestsPageLoadMetricsObserver;
namespace blink {
class AutoplayUmaHelper;
}
namespace content { namespace content {
class RenderWidgetHostLatencyTracker; class RenderWidgetHostLatencyTracker;
} // namespace content } // namespace content
...@@ -76,6 +80,7 @@ class METRICS_EXPORT UkmRecorder { ...@@ -76,6 +80,7 @@ class METRICS_EXPORT UkmRecorder {
virtual void UpdateSourceURL(SourceId source_id, const GURL& url) = 0; virtual void UpdateSourceURL(SourceId source_id, const GURL& url) = 0;
private: private:
friend blink::AutoplayUmaHelper;
friend ContextualSearchRankerLoggerImpl; friend ContextualSearchRankerLoggerImpl;
friend PluginInfoMessageFilter; friend PluginInfoMessageFilter;
friend UkmPageLoadMetricsObserver; friend UkmPageLoadMetricsObserver;
......
...@@ -102,11 +102,11 @@ def _CheckForPrintfDebugging(input_api, output_api): ...@@ -102,11 +102,11 @@ def _CheckForPrintfDebugging(input_api, output_api):
return [] return []
def _CheckForForbiddenNamespace(input_api, output_api): def _CheckForForbiddenChromiumCode(input_api, output_api):
"""Checks that Blink uses Chromium namespaces only in permitted code.""" """Checks that Blink uses Chromium classes and namespaces only in permitted code."""
# This list is not exhaustive, but covers likely ones. # This list is not exhaustive, but covers likely ones.
chromium_namespaces = ["base", "cc", "content", "gfx", "net", "ui"] chromium_namespaces = ["base", "cc", "content", "gfx", "net", "ui"]
chromium_forbidden_classes = [] chromium_forbidden_classes = ["GURL"]
chromium_allowed_classes = [ chromium_allowed_classes = [
"base::make_span", "base::make_span",
"base::span", "base::span",
...@@ -161,7 +161,7 @@ def CheckChangeOnUpload(input_api, output_api): ...@@ -161,7 +161,7 @@ def CheckChangeOnUpload(input_api, output_api):
results.extend(_CommonChecks(input_api, output_api)) results.extend(_CommonChecks(input_api, output_api))
results.extend(_CheckStyle(input_api, output_api)) results.extend(_CheckStyle(input_api, output_api))
results.extend(_CheckForPrintfDebugging(input_api, output_api)) results.extend(_CheckForPrintfDebugging(input_api, output_api))
results.extend(_CheckForForbiddenNamespace(input_api, output_api)) results.extend(_CheckForForbiddenChromiumCode(input_api, output_api))
return results return results
......
...@@ -14,6 +14,7 @@ include_rules = [ ...@@ -14,6 +14,7 @@ include_rules = [
"+platform", "+platform",
"+public/platform", "+public/platform",
"+public/web", "+public/web",
"+services/metrics/public",
"+services/network/public/interfaces", "+services/network/public/interfaces",
"+services/service_manager/public/interfaces/interface_provider.mojom-blink.h", "+services/service_manager/public/interfaces/interface_provider.mojom-blink.h",
"+third_party/skia/include", "+third_party/skia/include",
......
...@@ -361,4 +361,9 @@ blink_core_sources("dom") { ...@@ -361,4 +361,9 @@ blink_core_sources("dom") {
public_deps = [ public_deps = [
"//third_party/WebKit/common:mojo_bindings_blink", "//third_party/WebKit/common:mojo_bindings_blink",
] ]
deps = [
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/interfaces",
]
} }
...@@ -256,11 +256,14 @@ ...@@ -256,11 +256,14 @@
#include "platform/wtf/text/CharacterNames.h" #include "platform/wtf/text/CharacterNames.h"
#include "platform/wtf/text/StringBuffer.h" #include "platform/wtf/text/StringBuffer.h"
#include "platform/wtf/text/TextEncodingRegistry.h" #include "platform/wtf/text/TextEncodingRegistry.h"
#include "public/platform/InterfaceProvider.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
#include "public/platform/WebAddressSpace.h" #include "public/platform/WebAddressSpace.h"
#include "public/platform/WebPrerenderingSupport.h" #include "public/platform/WebPrerenderingSupport.h"
#include "public/platform/modules/insecure_input/insecure_input_service.mojom-blink.h" #include "public/platform/modules/insecure_input/insecure_input_service.mojom-blink.h"
#include "public/platform/site_engagement.mojom-blink.h" #include "public/platform/site_engagement.mojom-blink.h"
#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
#include "services/metrics/public/interfaces/ukm_interface.mojom-shared.h"
#include "services/service_manager/public/cpp/interface_provider.h" #include "services/service_manager/public/cpp/interface_provider.h"
#ifndef NDEBUG #ifndef NDEBUG
...@@ -3696,6 +3699,9 @@ void Document::SetURL(const KURL& url) { ...@@ -3696,6 +3699,9 @@ void Document::SetURL(const KURL& url) {
access_entry_from_url_ = nullptr; access_entry_from_url_ = nullptr;
UpdateBaseURL(); UpdateBaseURL();
GetContextFeatures().UrlDidChange(this); GetContextFeatures().UrlDidChange(this);
if (ukm_recorder_)
ukm_recorder_->UpdateSourceURL(ukm_source_id_, url_);
} }
KURL Document::ValidBaseElementURL() const { KURL Document::ValidBaseElementURL() const {
...@@ -5960,6 +5966,24 @@ void Document::SetFeaturePolicy(const String& feature_policy_header) { ...@@ -5960,6 +5966,24 @@ void Document::SetFeaturePolicy(const String& feature_policy_header) {
frame_->Client()->DidSetFeaturePolicyHeader(parsed_header); frame_->Client()->DidSetFeaturePolicyHeader(parsed_header);
} }
ukm::UkmRecorder* Document::UkmRecorder() {
if (ukm_recorder_)
return ukm_recorder_.get();
ukm::mojom::UkmRecorderInterfacePtr interface;
Platform::Current()->GetInterfaceProvider()->GetInterface(
mojo::MakeRequest(&interface));
ukm_recorder_.reset(new ukm::MojoUkmRecorder(std::move(interface)));
ukm_source_id_ = ukm_recorder_->GetNewSourceID();
ukm_recorder_->UpdateSourceURL(ukm_source_id_, url_);
return ukm_recorder_.get();
}
int64_t Document::UkmSourceID() const {
DCHECK(ukm_recorder_);
return ukm_source_id_;
}
void Document::InitSecurityContext(const DocumentInit& initializer) { void Document::InitSecurityContext(const DocumentInit& initializer) {
DCHECK(!GetSecurityOrigin()); DCHECK(!GetSecurityOrigin());
......
...@@ -75,11 +75,15 @@ ...@@ -75,11 +75,15 @@
#include "public/platform/WebFocusType.h" #include "public/platform/WebFocusType.h"
#include "public/platform/WebInsecureRequestPolicy.h" #include "public/platform/WebInsecureRequestPolicy.h"
namespace ukm {
class UkmRecorder;
} // namespace ukm
namespace blink { namespace blink {
namespace mojom { namespace mojom {
enum class EngagementLevel : int32_t; enum class EngagementLevel : int32_t;
} } // namespace mojom
class AnimationClock; class AnimationClock;
class AXObjectCache; class AXObjectCache;
...@@ -1385,6 +1389,9 @@ class CORE_EXPORT Document : public ContainerNode, ...@@ -1385,6 +1389,9 @@ class CORE_EXPORT Document : public ContainerNode,
void captureEvents() {} void captureEvents() {}
void releaseEvents() {} void releaseEvents() {}
ukm::UkmRecorder* UkmRecorder();
int64_t UkmSourceID() const;
protected: protected:
Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass); Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass);
...@@ -1757,6 +1764,12 @@ class CORE_EXPORT Document : public ContainerNode, ...@@ -1757,6 +1764,12 @@ class CORE_EXPORT Document : public ContainerNode,
bool has_high_media_engagement_; bool has_high_media_engagement_;
std::unique_ptr<DocumentOutliveTimeReporter> document_outlive_time_reporter_; std::unique_ptr<DocumentOutliveTimeReporter> document_outlive_time_reporter_;
// |mojo_ukm_recorder_| and |source_id_| will allow objects that are part of
// the |ukm_recorder_| and |source_id_| will allow objects that are part of
// the document to recorde UKM.
std::unique_ptr<ukm::UkmRecorder> ukm_recorder_;
int64_t ukm_source_id_;
}; };
extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<Document>; extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<Document>;
......
...@@ -633,6 +633,10 @@ blink_core_sources("html") { ...@@ -633,6 +633,10 @@ blink_core_sources("html") {
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations. # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
"//build/config/compiler:no_size_t_to_int_warning", "//build/config/compiler:no_size_t_to_int_warning",
] ]
deps = [
"//services/metrics/public/cpp:metrics_cpp",
]
} }
fuzzer_test("blink_html_tokenizer_fuzzer") { fuzzer_test("blink_html_tokenizer_fuzzer") {
......
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
#include "core/html/media/HTMLMediaElement.h" #include "core/html/media/HTMLMediaElement.h"
#include "platform/Histogram.h" #include "platform/Histogram.h"
#include "platform/wtf/CurrentTime.h" #include "platform/wtf/CurrentTime.h"
#include "public/platform/InterfaceProvider.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
#include "services/metrics/public/cpp/ukm_entry_builder.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
namespace blink { namespace blink {
...@@ -24,6 +27,18 @@ const int32_t kOffscreenDurationUmaBucketCount = 50; ...@@ -24,6 +27,18 @@ const int32_t kOffscreenDurationUmaBucketCount = 50;
const int32_t kMaxWaitTimeUmaMS = 30 * 1000; const int32_t kMaxWaitTimeUmaMS = 30 * 1000;
const int32_t kWaitTimeBucketCount = 50; const int32_t kWaitTimeBucketCount = 50;
const char kAutoplayAttemptUkmEvent[] = "Media.Autoplay.Attempt";
const char kAutoplayAttemptUkmSourceMetric[] = "Source";
const char kAutoplayAttemptUkmAudioTrackMetric[] = "AudioTrack";
const char kAutoplayAttemptUkmVideoTrackMetric[] = "VideoTrack";
const char kAutoplayAttemptUkmUserGestureRequiredMetric[] =
"UserGestureRequired";
const char kAutoplayAttemptUkmMutedMetric[] = "Muted";
const char kAutoplayMutedUnmuteUkmEvent[] = "Media.Autoplay.Muted.UnmuteAction";
const char kAutoplayMutedUnmuteUkmSourceMetric[] = "Source";
const char kAutoplayMutedUnmuteUkmResultMetric[] = "Result";
} // namespace } // namespace
AutoplayUmaHelper* AutoplayUmaHelper::Create(HTMLMediaElement* element) { AutoplayUmaHelper* AutoplayUmaHelper::Create(HTMLMediaElement* element) {
...@@ -168,6 +183,22 @@ void AutoplayUmaHelper::OnAutoplayInitiated(AutoplaySource source) { ...@@ -168,6 +183,22 @@ void AutoplayUmaHelper::OnAutoplayInitiated(AutoplaySource source) {
} }
} }
// Record UKM autoplay event.
{
std::unique_ptr<ukm::UkmEntryBuilder> builder =
CreateUkmBuilder(kAutoplayAttemptUkmEvent);
builder->AddMetric(kAutoplayAttemptUkmSourceMetric,
source == AutoplaySource::kMethod);
builder->AddMetric(kAutoplayAttemptUkmAudioTrackMetric,
element_->HasAudio());
builder->AddMetric(kAutoplayAttemptUkmVideoTrackMetric,
element_->HasVideo());
builder->AddMetric(
kAutoplayAttemptUkmUserGestureRequiredMetric,
element_->GetAutoplayPolicy().IsGestureNeededForPlayback());
builder->AddMetric(kAutoplayAttemptUkmMutedMetric, element_->muted());
}
element_->addEventListener(EventTypeNames::playing, this, false); element_->addEventListener(EventTypeNames::playing, this, false);
} }
...@@ -257,6 +288,24 @@ void AutoplayUmaHelper::RecordAutoplayUnmuteStatus( ...@@ -257,6 +288,24 @@ void AutoplayUmaHelper::RecordAutoplayUnmuteStatus(
static_cast<int>(AutoplayUnmuteActionStatus::kNumberOfStatus))); static_cast<int>(AutoplayUnmuteActionStatus::kNumberOfStatus)));
autoplay_unmute_histogram.Count(static_cast<int>(status)); autoplay_unmute_histogram.Count(static_cast<int>(status));
// Record UKM event for unmute muted autoplay.
{
std::unique_ptr<ukm::UkmEntryBuilder> builder =
CreateUkmBuilder(kAutoplayMutedUnmuteUkmEvent);
int source = static_cast<int>(AutoplaySource::kAttribute);
if (sources_.size() ==
static_cast<size_t>(AutoplaySource::kNumberOfSources)) {
source = static_cast<int>(AutoplaySource::kDualSource);
} else if (sources_.count(AutoplaySource::kMethod)) {
source = static_cast<int>(AutoplaySource::kAttribute);
}
builder->AddMetric(kAutoplayMutedUnmuteUkmSourceMetric, source);
builder->AddMetric(kAutoplayMutedUnmuteUkmResultMetric,
status == AutoplayUnmuteActionStatus::kSuccess);
}
} }
void AutoplayUmaHelper::VideoWillBeDrawnToCanvas() { void AutoplayUmaHelper::VideoWillBeDrawnToCanvas() {
...@@ -442,6 +491,15 @@ bool AutoplayUmaHelper::ShouldRecordUserPausedAutoplayingCrossOriginVideo() ...@@ -442,6 +491,15 @@ bool AutoplayUmaHelper::ShouldRecordUserPausedAutoplayingCrossOriginVideo()
CrossOriginAutoplayResult::kUserPaused); CrossOriginAutoplayResult::kUserPaused);
} }
std::unique_ptr<ukm::UkmEntryBuilder> AutoplayUmaHelper::CreateUkmBuilder(
const char* event) {
ukm::UkmRecorder* ukm_recorder = element_->GetDocument().UkmRecorder();
DCHECK(ukm_recorder);
return ukm_recorder->GetEntryBuilder(element_->GetDocument().UkmSourceID(),
event);
}
DEFINE_TRACE(AutoplayUmaHelper) { DEFINE_TRACE(AutoplayUmaHelper) {
EventListener::Trace(visitor); EventListener::Trace(visitor);
ContextLifecycleObserver::Trace(visitor); ContextLifecycleObserver::Trace(visitor);
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
#include <set> #include <set>
namespace ukm {
class UkmEntryBuilder;
} // namespace ukm
namespace blink { namespace blink {
// These values are used for histograms. Do not reorder. // These values are used for histograms. Do not reorder.
...@@ -114,6 +118,10 @@ class CORE_EXPORT AutoplayUmaHelper : public EventListener, ...@@ -114,6 +118,10 @@ class CORE_EXPORT AutoplayUmaHelper : public EventListener,
bool ShouldListenToContextDestroyed() const; bool ShouldListenToContextDestroyed() const;
bool ShouldRecordUserPausedAutoplayingCrossOriginVideo() const; bool ShouldRecordUserPausedAutoplayingCrossOriginVideo() const;
// Returns a ukm::UkmEntryBuilder created from the UkmRecorder associated with
// the Document.
std::unique_ptr<ukm::UkmEntryBuilder> CreateUkmBuilder(const char*);
// The autoplay sources. // The autoplay sources.
std::set<AutoplaySource> sources_; std::set<AutoplaySource> sources_;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "platform/wtf/text/StringStatics.h" #include "platform/wtf/text/StringStatics.h"
#include "platform/wtf/text/StringUTF8Adaptor.h" #include "platform/wtf/text/StringUTF8Adaptor.h"
#include "platform/wtf/text/TextEncoding.h" #include "platform/wtf/text/TextEncoding.h"
#include "url/gurl.h"
#include "url/url_util.h" #include "url/url_util.h"
#ifndef NDEBUG #ifndef NDEBUG
#include <stdio.h> #include <stdio.h>
...@@ -881,4 +882,8 @@ bool KURL::IsSafeToSendToAnotherThread() const { ...@@ -881,4 +882,8 @@ bool KURL::IsSafeToSendToAnotherThread() const {
(!inner_url_ || inner_url_->IsSafeToSendToAnotherThread()); (!inner_url_ || inner_url_->IsSafeToSendToAnotherThread());
} }
KURL::operator GURL() const {
return GURL(string_.Utf8().data(), parsed_, is_valid_);
}
} // namespace blink } // namespace blink
...@@ -61,6 +61,8 @@ namespace WTF { ...@@ -61,6 +61,8 @@ namespace WTF {
class TextEncoding; class TextEncoding;
} }
class GURL;
namespace blink { namespace blink {
struct KURLHash; struct KURLHash;
...@@ -212,6 +214,11 @@ class PLATFORM_EXPORT KURL { ...@@ -212,6 +214,11 @@ class PLATFORM_EXPORT KURL {
return parsed_.potentially_dangling_markup; return parsed_.potentially_dangling_markup;
} }
// Returns a GURL with the same properties. This can be used in platform/ and
// web/. However, in core/ and modules/, this should only be used to pass
// a GURL to a layer that is expecting one instead of a KURL or a WebURL.
operator GURL() const;
private: private:
friend struct WTF::HashTraits<blink::KURL>; friend struct WTF::HashTraits<blink::KURL>;
......
...@@ -514,6 +514,64 @@ be describing additional metrics about the same event. ...@@ -514,6 +514,64 @@ be describing additional metrics about the same event.
</metric> </metric>
</event> </event>
<event name="Media.Autoplay.Attempt">
<owner>mlamouri@chromium.org</owner>
<owner>media-dev@chromium.org</owner>
<summary>
Event recorded when there is an attempt to autoplay (ie. no user gesture).
It will be recorded regardless of the result of this attempt.
</summary>
<metric name="AudioTrack">
<summary>
Whether the element had an audio track when autoplay was attempted.
</summary>
</metric>
<metric name="Muted">
<summary>
Whether the element was muted when autoplay was attempted.
</summary>
</metric>
<metric name="Source">
<summary>
Source of the autoplay attempt: 0 for attribute; 1 for play().
</summary>
</metric>
<metric name="UserGestureRequirement">
<summary>
Whether a user gesture was required per autoplay rules at the time of
attempt. By definition there is no user gesture on the stack when the
attempt is registered.
</summary>
</metric>
<metric name="VideoTrack">
<summary>
Whether the element had a video track when autoplay was attempted.
</summary>
</metric>
</event>
<event name="Media.Autoplay.Muted.UnmuteAction">
<owner>mlamouri@chromium.org</owner>
<owner>media-dev@chromium.org</owner>
<summary>
Event recorded when there is an attempt to unmute an media that was
autoplaying following the rules of autoplay muted.
</summary>
<metric name="Result">
<summary>
0 means that the unmute failed because it happened without a user gesture.
1 means that it succeeded because it had a user gesture.
</summary>
</metric>
<metric name="Source">
<summary>
Similar to &quot;Source&quot; in &quot;Media.Autoplay.Attempt&quot; with
the addition of a value for both sources being used: 0 for attribute; 1
for play(); 2 for both attempted.
</summary>
</metric>
</event>
<event name="Media.Engagement.SessionFinished"> <event name="Media.Engagement.SessionFinished">
<owner>beccahughes@chromium.org</owner> <owner>beccahughes@chromium.org</owner>
<owner>media-dev@chromium.org</owner> <owner>media-dev@chromium.org</owner>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment