diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-17 13:57:45 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-07-19 13:44:40 +0000 |
commit | 6ec7b8da05d21a3878bd21c691b41e675d74bb1c (patch) | |
tree | b87f250bc19413750b9bb9cdbf2da20ef5014820 /chromium/components/ukm | |
parent | ec02ee4181c49b61fce1c8fb99292dbb8139cc90 (diff) | |
download | qtwebengine-chromium-6ec7b8da05d21a3878bd21c691b41e675d74bb1c.tar.gz |
BASELINE: Update Chromium to 60.0.3112.70
Change-Id: I9911c2280a014d4632f254857876a395d4baed2d
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/components/ukm')
28 files changed, 910 insertions, 540 deletions
diff --git a/chromium/components/ukm/BUILD.gn b/chromium/components/ukm/BUILD.gn index dc9c405b757..ab5807fd644 100644 --- a/chromium/components/ukm/BUILD.gn +++ b/chromium/components/ukm/BUILD.gn @@ -11,12 +11,10 @@ static_library("ukm") { sources = [ "persisted_logs_metrics_impl.cc", "persisted_logs_metrics_impl.h", - "ukm_entry.cc", - "ukm_entry.h", - "ukm_entry_builder.cc", - "ukm_entry_builder.h", "ukm_pref_names.cc", "ukm_pref_names.h", + "ukm_recorder_impl.cc", + "ukm_recorder_impl.h", "ukm_reporting_service.cc", "ukm_reporting_service.h", "ukm_rotation_scheduler.cc", @@ -27,6 +25,12 @@ static_library("ukm") { "ukm_source.h", ] + public_deps = [ + "//components/metrics/proto", + "//components/ukm/public", + "//components/ukm/public/interfaces", + ] + deps = [ "//base", "//components/data_use_measurement/core", @@ -56,12 +60,13 @@ static_library("observers") { static_library("test_support") { testonly = true sources = [ - "test_ukm_service.cc", - "test_ukm_service.h", + "test_ukm_recorder.cc", + "test_ukm_recorder.h", ] public_deps = [ ":ukm", + "//components/metrics/proto", ] deps = [ "//base", @@ -90,7 +95,7 @@ source_set("unit_tests") { "//components/variations", "//net:test_support", "//testing/gtest", - "//third_party/zlib:compression_utils", + "//third_party/zlib/google:compression_utils", "//url", ] } diff --git a/chromium/components/ukm/DEPS b/chromium/components/ukm/DEPS index 6a9008e619f..abd3591f71b 100644 --- a/chromium/components/ukm/DEPS +++ b/chromium/components/ukm/DEPS @@ -2,5 +2,6 @@ include_rules = [ "+components/metrics", "+components/prefs", "+components/variations", + "+mojo/public", "+third_party/zlib/google", ] diff --git a/chromium/components/ukm/debug_page/BUILD.gn b/chromium/components/ukm/debug_page/BUILD.gn new file mode 100644 index 00000000000..9fa09128304 --- /dev/null +++ b/chromium/components/ukm/debug_page/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2017 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. + +static_library("debug_page") { + sources = [ + "debug_page.cc", + "debug_page.h", + ] + + deps = [ + "//base", + "//components/ukm", + "//content/public/browser", + "//url", + ] +} diff --git a/chromium/components/ukm/debug_page/DEPS b/chromium/components/ukm/debug_page/DEPS new file mode 100644 index 00000000000..fe7bb13183f --- /dev/null +++ b/chromium/components/ukm/debug_page/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+content/public", +] diff --git a/chromium/components/ukm/debug_page/debug_page.cc b/chromium/components/ukm/debug_page/debug_page.cc new file mode 100644 index 00000000000..72df62fea95 --- /dev/null +++ b/chromium/components/ukm/debug_page/debug_page.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2017 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 "components/ukm/debug_page/debug_page.h" + +#include <inttypes.h> + +#include "base/memory/ref_counted_memory.h" +#include "base/strings/stringprintf.h" +#include "components/ukm/ukm_service.h" +#include "components/ukm/ukm_source.h" +#include "url/gurl.h" + +namespace ukm { +namespace debug { + +DebugPage::DebugPage(ServiceGetter service_getter) + : service_getter_(service_getter) {} + +DebugPage::~DebugPage() {} + +std::string DebugPage::GetSource() const { + return "ukm"; +} + +std::string DebugPage::GetMimeType(const std::string& path) const { + return "text/html"; +} + +void DebugPage::StartDataRequest( + const std::string& path, + const content::ResourceRequestInfo::WebContentsGetter& wc_getter, + const content::URLDataSource::GotDataCallback& callback) { + std::string data; + data.append(R"""(<!DOCTYPE html> + <html> + <head> + <meta http-equiv="Content-Security-Policy" + content="object-src 'none'; script-src 'none'"> + <title>UKM Debug</title> + </head> + <body> + <h1>UKM Debug page</h1> + )"""); + UkmService* ukm_service = service_getter_.Run(); + if (ukm_service) { + data.append( + base::StringPrintf("<p>IsEnabled:%s</p>", + ukm_service->recording_enabled_ ? "True" : "False")); + data.append(base::StringPrintf("<p>ClientId:%" PRIu64 "</p>", + ukm_service->client_id_)); + data.append( + base::StringPrintf("<p>SessionId:%d</p>", ukm_service->session_id_)); + + data.append("<h2>Sources</h2>"); + for (const auto& kv : ukm_service->sources_) { + const auto* src = kv.second.get(); + data.append(base::StringPrintf("<p>Id:%" PRId64 " Url:%s</p>", src->id(), + src->url().spec().c_str())); + } + + data.append("<h2>Entries</h2>"); + for (const auto& v : ukm_service->entries_) { + const auto* entry = v.get(); + data.append(base::StringPrintf("<h3>Id:%" PRId64 " Hash:%" PRIu64 "</h3>", + entry->source_id, entry->event_hash)); + } + } + + data.append(R"""( + </body> + </html> + )"""); + + callback.Run(base::RefCountedString::TakeString(&data)); +} + +bool DebugPage::AllowCaching() const { + return false; +} + +} // namespace debug +} // namespace ukm diff --git a/chromium/components/ukm/debug_page/debug_page.h b/chromium/components/ukm/debug_page/debug_page.h new file mode 100644 index 00000000000..52ae7a167af --- /dev/null +++ b/chromium/components/ukm/debug_page/debug_page.h @@ -0,0 +1,47 @@ +// Copyright (c) 2017 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. + +#ifndef COMPONENTS_UKM_DEBUG_PAGE_REQUEST_JOB_H_ +#define COMPONENTS_UKM_DEBUG_PAGE_REQUEST_JOB_H_ + +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "content/public/browser/url_data_source.h" + +namespace ukm { + +class UkmService; + +namespace debug { + +// Implements the chrome://ukm page for debugging UKM state. +class DebugPage : public content::URLDataSource { + public: + typedef base::Callback<UkmService*()> ServiceGetter; + + explicit DebugPage(ServiceGetter service_getter); + + // content::URLDataSource: + std::string GetSource() const override; + std::string GetMimeType(const std::string& path) const override; + void StartDataRequest( + const std::string& path, + const content::ResourceRequestInfo::WebContentsGetter& wc_getter, + const content::URLDataSource::GotDataCallback& callback) override; + bool AllowCaching() const override; + + private: + ~DebugPage() override; + + ServiceGetter service_getter_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(DebugPage); +}; + +} // namespace debug +} // namespace ukm + +#endif // COMPONENTS_UKM_DEBUG_PAGE_REQUEST_JOB_H_ diff --git a/chromium/components/ukm/public/BUILD.gn b/chromium/components/ukm/public/BUILD.gn new file mode 100644 index 00000000000..1383752327d --- /dev/null +++ b/chromium/components/ukm/public/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright 2017 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. + +import("//mojo/public/tools/bindings/mojom.gni") + +component("public") { + sources = [ + "ukm_entry_builder.cc", + "ukm_entry_builder.h", + "ukm_export.h", + "ukm_recorder.cc", + "ukm_recorder.h", + ] + + defines = [ "UKM_IMPLEMENTATION" ] + + public_deps = [ + "//base", + "//components/ukm/public/interfaces", + "//url", + ] + + deps = [ + "//mojo/public/cpp/bindings", + ] +} diff --git a/chromium/components/ukm/public/interfaces/BUILD.gn b/chromium/components/ukm/public/interfaces/BUILD.gn new file mode 100644 index 00000000000..b4804bedb30 --- /dev/null +++ b/chromium/components/ukm/public/interfaces/BUILD.gn @@ -0,0 +1,15 @@ +# Copyright 2017 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. + +import("//mojo/public/tools/bindings/mojom.gni") + +mojom("interfaces") { + sources = [ + "ukm_interface.mojom", + ] + + public_deps = [ + "//url/mojo:url_mojom_gurl", + ] +} diff --git a/chromium/components/ukm/public/interfaces/OWNERS b/chromium/components/ukm/public/interfaces/OWNERS new file mode 100644 index 00000000000..08850f42120 --- /dev/null +++ b/chromium/components/ukm/public/interfaces/OWNERS @@ -0,0 +1,2 @@ +per-file *.mojom=set noparent +per-file *.mojom=file://ipc/SECURITY_OWNERS diff --git a/chromium/components/ukm/public/interfaces/ukm_interface.mojom b/chromium/components/ukm/public/interfaces/ukm_interface.mojom new file mode 100644 index 00000000000..0625916b88a --- /dev/null +++ b/chromium/components/ukm/public/interfaces/ukm_interface.mojom @@ -0,0 +1,22 @@ +// Copyright 2017 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. + +module ukm.mojom; + +import "url/mojo/url.mojom"; + +struct UkmMetric { + uint64 metric_hash; + int64 value; +}; + +struct UkmEntry { + int64 source_id; + uint64 event_hash; + array<UkmMetric> metrics; +}; + +interface UkmRecorderInterface { + AddEntry(UkmEntry entry); +}; diff --git a/chromium/components/ukm/public/ukm_entry_builder.cc b/chromium/components/ukm/public/ukm_entry_builder.cc new file mode 100644 index 00000000000..72a227acc08 --- /dev/null +++ b/chromium/components/ukm/public/ukm_entry_builder.cc @@ -0,0 +1,32 @@ +// Copyright 2017 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 "components/ukm/public/ukm_entry_builder.h" + +#include <memory> + +#include "base/metrics/metrics_hashes.h" +#include "components/ukm/public/interfaces/ukm_interface.mojom.h" + +namespace ukm { + +UkmEntryBuilder::UkmEntryBuilder( + const UkmEntryBuilder::AddEntryCallback& callback, + ukm::SourceId source_id, + const char* event_name) + : add_entry_callback_(callback), entry_(mojom::UkmEntry::New()) { + entry_->source_id = source_id; + entry_->event_hash = base::HashMetricName(event_name); +} + +UkmEntryBuilder::~UkmEntryBuilder() { + add_entry_callback_.Run(std::move(entry_)); +} + +void UkmEntryBuilder::AddMetric(const char* metric_name, int64_t value) { + entry_->metrics.emplace_back( + mojom::UkmMetric::New(base::HashMetricName(metric_name), value)); +} + +} // namespace ukm diff --git a/chromium/components/ukm/ukm_entry_builder.h b/chromium/components/ukm/public/ukm_entry_builder.h index e2400ee5cb5..1c9facfe039 100644 --- a/chromium/components/ukm/ukm_entry_builder.h +++ b/chromium/components/ukm/public/ukm_entry_builder.h @@ -8,19 +8,19 @@ #include <string> #include "base/macros.h" -#include "components/ukm/ukm_service.h" +#include "components/ukm/public/interfaces/ukm_interface.mojom.h" +#include "components/ukm/public/ukm_export.h" namespace ukm { -class UkmEntry; -class UkmService; +typedef int64_t SourceId; -// The builder that builds UkmEntry and adds it to UkmService. +// The builder that builds UkmEntry and adds it to UkmRecorder. // The example usage is: // // { // unique_ptr<UkmEntryBuilder> builder = -// ukm_service->GetEntryBuilder(source_id, "PageLoad"); +// ukm_recorder->GetEntryBuilder(source_id, "PageLoad"); // builder->AddMetric("NavigationStart", navigation_start_time); // builder->AddMetric("ResponseStart", response_start_time); // builder->AddMetric("FirstPaint", first_paint_time); @@ -29,22 +29,20 @@ class UkmService; // // When there exists an added metric, the builder will automatically add the // UkmEntry to UkmService upon destruction when going out of scope. -class UkmEntryBuilder { +class UKM_EXPORT UkmEntryBuilder { public: + using AddEntryCallback = base::Callback<void(mojom::UkmEntryPtr)>; + UkmEntryBuilder(const AddEntryCallback& callback, + ukm::SourceId source_id, + const char* event_name); + ~UkmEntryBuilder(); + // Add metric to the entry. A metric contains a metric name and value. void AddMetric(const char* metric_name, int64_t value); - ~UkmEntryBuilder(); - private: - friend class UkmService; - - UkmEntryBuilder(const UkmService::AddEntryCallback& callback, - int32_t source_id, - const char* event_name); - - UkmService::AddEntryCallback add_entry_callback_; - std::unique_ptr<UkmEntry> entry_; + AddEntryCallback add_entry_callback_; + mojom::UkmEntryPtr entry_; DISALLOW_COPY_AND_ASSIGN(UkmEntryBuilder); }; diff --git a/chromium/components/ukm/public/ukm_export.h b/chromium/components/ukm/public/ukm_export.h new file mode 100644 index 00000000000..6c460eb5834 --- /dev/null +++ b/chromium/components/ukm/public/ukm_export.h @@ -0,0 +1,29 @@ +// Copyright 2017 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. + +#ifndef COMPONENTS_UKM_PUBLIC_UKM_EXPORT_H_ +#define COMPONENTS_UKM_PUBLIC_UKM_EXPORT_H_ + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(UKM_IMPLEMENTATION) +#define UKM_EXPORT __declspec(dllexport) +#else +#define UKM_EXPORT __declspec(dllimport) +#endif // defined(UKM_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(UKM_IMPLEMENTATION) +#define UKM_EXPORT __attribute__((visibility("default"))) +#else +#define UKM_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define UKM_EXPORT +#endif + +#endif // COMPONENTS_UKM_PUBLIC_UKM_EXPORT_H_ diff --git a/chromium/components/ukm/public/ukm_recorder.cc b/chromium/components/ukm/public/ukm_recorder.cc new file mode 100644 index 00000000000..25fdcb822f1 --- /dev/null +++ b/chromium/components/ukm/public/ukm_recorder.cc @@ -0,0 +1,47 @@ +// Copyright 2017 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 "components/ukm/public/ukm_recorder.h" + +#include "base/atomic_sequence_num.h" +#include "base/bind.h" +#include "base/feature_list.h" +#include "base/memory/ptr_util.h" +#include "components/ukm/public/ukm_entry_builder.h" + +namespace ukm { + +UkmRecorder* g_ukm_recorder = nullptr; + +const base::Feature kUkmFeature = {"Ukm", base::FEATURE_DISABLED_BY_DEFAULT}; + +UkmRecorder::UkmRecorder() { + DCHECK(!g_ukm_recorder); + g_ukm_recorder = this; +} + +UkmRecorder::~UkmRecorder() { + g_ukm_recorder = nullptr; +} + +// static +UkmRecorder* UkmRecorder::Get() { + return g_ukm_recorder; +} + +// static +ukm::SourceId UkmRecorder::GetNewSourceID() { + static base::StaticAtomicSequenceNumber seq; + return static_cast<ukm::SourceId>(seq.GetNext()); +} + +std::unique_ptr<UkmEntryBuilder> UkmRecorder::GetEntryBuilder( + ukm::SourceId source_id, + const char* event_name) { + return base::MakeUnique<UkmEntryBuilder>( + base::Bind(&UkmRecorder::AddEntry, base::Unretained(this)), source_id, + event_name); +} + +} // namespace ukm diff --git a/chromium/components/ukm/public/ukm_recorder.h b/chromium/components/ukm/public/ukm_recorder.h new file mode 100644 index 00000000000..74cd232d509 --- /dev/null +++ b/chromium/components/ukm/public/ukm_recorder.h @@ -0,0 +1,107 @@ +// Copyright 2017 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. + +#ifndef COMPONENTS_UKM_PUBLIC_UKM_RECORDER_H_ +#define COMPONENTS_UKM_PUBLIC_UKM_RECORDER_H_ + +#include <stddef.h> + +#include "base/callback.h" +#include "base/feature_list.h" +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "components/ukm/public/interfaces/ukm_interface.mojom.h" +#include "components/ukm/public/ukm_entry_builder.h" +#include "components/ukm/public/ukm_export.h" +#include "url/gurl.h" + +class ContextualSearchRankerLoggerImpl; +class PluginInfoMessageFilter; +class UkmPageLoadMetricsObserver; + +namespace autofill { +class AutofillMetrics; +} + +namespace content { +class MediaInternals; +class RenderFrameImpl; +} + +namespace translate { +class TranslateRankerImpl; +} + +namespace payments { +class JourneyLogger; +} + +namespace ukm { + +class UkmEntryBuilder; +class UkmInterface; +class TestRecordingHelper; + +// This feature controls whether UkmService should be created. +UKM_EXPORT extern const base::Feature kUkmFeature; + +typedef int64_t SourceId; + +// Interface for recording UKM +class UKM_EXPORT UkmRecorder { + public: + UkmRecorder(); + virtual ~UkmRecorder(); + + // Provides access to a previously constructed UkmRecorder instance. Only one + // instance exists per process and must have been constructed prior to any + // calls to this method. + static UkmRecorder* Get(); + + // Get the new source ID, which is unique for the duration of a browser + // session. + static SourceId GetNewSourceID(); + + // Update the URL on the source keyed to the given source ID. If the source + // does not exist, it will create a new UkmSource object. + virtual void UpdateSourceURL(SourceId source_id, const GURL& url) = 0; + + private: + friend autofill::AutofillMetrics; + friend payments::JourneyLogger; + friend ContextualSearchRankerLoggerImpl; + friend PluginInfoMessageFilter; + friend UkmPageLoadMetricsObserver; + friend translate::TranslateRankerImpl; + friend TestRecordingHelper; + friend UkmInterface; + friend content::MediaInternals; + friend content::RenderFrameImpl; + FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, AddEntryWithEmptyMetrics); + FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, EntryBuilderAndSerialization); + FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, + LogsUploadedOnlyWhenHavingSourcesOrEntries); + FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, MetricsProviderTest); + FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, PersistAndPurge); + FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, WhitelistEntryTest); + + // Get a new UkmEntryBuilder object for the specified source ID and event, + // which can get metrics added to. + // + // This API being private is intentional. Any client using UKM needs to + // declare itself to be a friend of UkmService and go through code review + // process. + std::unique_ptr<UkmEntryBuilder> GetEntryBuilder(SourceId source_id, + const char* event_name); + + private: + // Add an entry to the UkmEntry list. + virtual void AddEntry(mojom::UkmEntryPtr entry) = 0; + + DISALLOW_COPY_AND_ASSIGN(UkmRecorder); +}; + +} // namespace ukm + +#endif // COMPONENTS_UKM_PUBLIC_UKM_RECORDER_H_ diff --git a/chromium/components/ukm/test_ukm_recorder.cc b/chromium/components/ukm/test_ukm_recorder.cc new file mode 100644 index 00000000000..26a1307fede --- /dev/null +++ b/chromium/components/ukm/test_ukm_recorder.cc @@ -0,0 +1,67 @@ +// Copyright 2017 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 "components/ukm/test_ukm_recorder.h" + +#include "base/logging.h" +#include "base/metrics/metrics_hashes.h" +#include "components/ukm/ukm_source.h" + +namespace ukm { + +TestUkmRecorder::TestUkmRecorder() { + EnableRecording(); +} + +TestUkmRecorder::~TestUkmRecorder() = default; + +const UkmSource* TestUkmRecorder::GetSourceForUrl(const char* url) const { + const UkmSource* source = nullptr; + for (const auto& kv : sources()) { + if (kv.second->url() == url) { + DCHECK_EQ(nullptr, source); + source = kv.second.get(); + } + } + return source; +} + +const UkmSource* TestUkmRecorder::GetSourceForSourceId( + ukm::SourceId source_id) const { + const UkmSource* source = nullptr; + for (const auto& kv : sources()) { + if (kv.second->id() == source_id) { + DCHECK_EQ(nullptr, source); + source = kv.second.get(); + } + } + return source; +} + +const mojom::UkmEntry* TestUkmRecorder::GetEntry(size_t entry_num) const { + DCHECK_LT(entry_num, entries().size()); + return entries()[entry_num].get(); +} + +const mojom::UkmEntry* TestUkmRecorder::GetEntryForEntryName( + const char* entry_name) const { + for (const auto& it : entries()) { + if (it->event_hash == base::HashMetricName(entry_name)) + return it.get(); + } + return nullptr; +} + +// static +const mojom::UkmMetric* TestUkmRecorder::FindMetric( + const mojom::UkmEntry* entry, + const char* metric_name) { + for (const auto& metric : entry->metrics) { + if (metric->metric_hash == base::HashMetricName(metric_name)) + return metric.get(); + } + return nullptr; +} + +} // namespace ukm diff --git a/chromium/components/ukm/test_ukm_recorder.h b/chromium/components/ukm/test_ukm_recorder.h new file mode 100644 index 00000000000..ef989b9dca6 --- /dev/null +++ b/chromium/components/ukm/test_ukm_recorder.h @@ -0,0 +1,43 @@ +// Copyright 2017 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. + +#ifndef COMPONENTS_UKM_TEST_UKM_RECORDER_H_ +#define COMPONENTS_UKM_TEST_UKM_RECORDER_H_ + +#include <stddef.h> +#include <memory> + +#include "base/macros.h" +#include "components/ukm/ukm_recorder_impl.h" + +namespace ukm { + +// Wraps an UkmRecorder with additional accessors used for testing. +class TestUkmRecorder : public UkmRecorderImpl { + public: + TestUkmRecorder(); + ~TestUkmRecorder() override; + + size_t sources_count() const { return sources().size(); } + const std::map<ukm::SourceId, std::unique_ptr<UkmSource>>& GetSources() + const { + return sources(); + } + const UkmSource* GetSourceForUrl(const char* url) const; + const UkmSource* GetSourceForSourceId(ukm::SourceId source_id) const; + + size_t entries_count() const { return entries().size(); } + const mojom::UkmEntry* GetEntry(size_t entry_num) const; + const mojom::UkmEntry* GetEntryForEntryName(const char* entry_name) const; + + static const mojom::UkmMetric* FindMetric(const mojom::UkmEntry* entry, + const char* metric_name); + + private: + DISALLOW_COPY_AND_ASSIGN(TestUkmRecorder); +}; + +} // namespace ukm + +#endif // COMPONENTS_UKM_TEST_UKM_RECORDER_H_ diff --git a/chromium/components/ukm/test_ukm_service.cc b/chromium/components/ukm/test_ukm_service.cc deleted file mode 100644 index 824fa25a7fe..00000000000 --- a/chromium/components/ukm/test_ukm_service.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2017 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 "components/ukm/test_ukm_service.h" - -#include "base/logging.h" -#include "base/metrics/metrics_hashes.h" -#include "components/ukm/ukm_entry.h" -#include "components/ukm/ukm_source.h" - -namespace ukm { - -UkmServiceTestingHarness::UkmServiceTestingHarness() { - UkmService::RegisterPrefs(test_prefs_.registry()); - test_prefs_.ClearPref(prefs::kUkmClientId); - test_prefs_.ClearPref(prefs::kUkmSessionId); - test_prefs_.ClearPref(prefs::kUkmPersistedLogs); - - test_ukm_service_ = base::MakeUnique<TestUkmService>(&test_prefs_); -} - -UkmServiceTestingHarness::~UkmServiceTestingHarness() = default; - -TestUkmService::TestUkmService(PrefService* prefs_service) - : UkmService(prefs_service, &test_metrics_service_client_) { - EnableRecording(); - DisableReporting(); -} - -TestUkmService::~TestUkmService() = default; - -const std::map<int32_t, std::unique_ptr<UkmSource>>& -TestUkmService::GetSources() const { - return sources_for_testing(); -} - -const UkmSource* TestUkmService::GetSourceForUrl(const char* url) const { - const UkmSource* source = nullptr; - for (const auto& kv : sources_for_testing()) { - if (kv.second->url() == url) { - DCHECK_EQ(nullptr, source); - source = kv.second.get(); - } - } - return source; -} - -const UkmSource* TestUkmService::GetSourceForSourceId(int32_t source_id) const { - const UkmSource* source = nullptr; - for (const auto& kv : sources_for_testing()) { - if (kv.second->id() == source_id) { - DCHECK_EQ(nullptr, source); - source = kv.second.get(); - } - } - return source; -} - -const UkmEntry* TestUkmService::GetEntry(size_t entry_num) const { - return entries_for_testing()[entry_num].get(); -} - -const UkmEntry* TestUkmService::GetEntryForEntryName( - const char* entry_name) const { - for (const auto& it : entries_for_testing()) { - if (it->event_hash() == base::HashMetricName(entry_name)) - return it.get(); - } - return nullptr; -} - -} // namespace ukm diff --git a/chromium/components/ukm/test_ukm_service.h b/chromium/components/ukm/test_ukm_service.h deleted file mode 100644 index 55d5920411d..00000000000 --- a/chromium/components/ukm/test_ukm_service.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017 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. - -#ifndef COMPONENTS_UKM_TEST_UKM_SERVICE_H_ -#define COMPONENTS_UKM_TEST_UKM_SERVICE_H_ - -#include <stddef.h> -#include <memory> - -#include "components/metrics/test_metrics_service_client.h" -#include "components/prefs/testing_pref_service.h" -#include "components/ukm/ukm_pref_names.h" -#include "components/ukm/ukm_service.h" - -namespace ukm { - -// Wraps an UkmService with additional accessors used for testing. -class TestUkmService : public UkmService { - public: - explicit TestUkmService(PrefService* pref_service); - ~TestUkmService() override; - - size_t sources_count() const { return sources_for_testing().size(); } - const std::map<int32_t, std::unique_ptr<UkmSource>>& GetSources() const; - const UkmSource* GetSourceForUrl(const char* url) const; - const UkmSource* GetSourceForSourceId(int32_t source_id) const; - - size_t entries_count() const { return entries_for_testing().size(); } - const UkmEntry* GetEntry(size_t entry_num) const; - const UkmEntry* GetEntryForEntryName(const char* entry_name) const; - - private: - metrics::TestMetricsServiceClient test_metrics_service_client_; - - DISALLOW_COPY_AND_ASSIGN(TestUkmService); -}; - -// Convenience harness used for testing; creates a TestUkmService and -// supplies it with a prefs service with a longer lifespan. -class UkmServiceTestingHarness { - public: - UkmServiceTestingHarness(); - virtual ~UkmServiceTestingHarness(); - - TestUkmService* test_ukm_service() { return test_ukm_service_.get(); } - - private: - TestingPrefServiceSimple test_prefs_; - std::unique_ptr<TestUkmService> test_ukm_service_; - - DISALLOW_COPY_AND_ASSIGN(UkmServiceTestingHarness); -}; - -} // namespace ukm - -#endif // COMPONENTS_UKM_TEST_UKM_SERVICE_H_ diff --git a/chromium/components/ukm/ukm_entry.cc b/chromium/components/ukm/ukm_entry.cc deleted file mode 100644 index 88b724c06f6..00000000000 --- a/chromium/components/ukm/ukm_entry.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2017 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 "components/ukm/ukm_entry.h" - -#include "base/metrics/metrics_hashes.h" -#include "components/metrics/proto/ukm/entry.pb.h" -#include "components/ukm/ukm_source.h" - -namespace ukm { - -UkmEntry::UkmEntry(int32_t source_id, const char* event_name) - : source_id_(source_id), event_hash_(base::HashMetricName(event_name)) {} - -UkmEntry::~UkmEntry() {} - -void UkmEntry::PopulateProto(Entry* proto_entry) const { - DCHECK(!proto_entry->has_source_id()); - DCHECK(!proto_entry->has_event_hash()); - - proto_entry->set_source_id(source_id_); - proto_entry->set_event_hash(event_hash_); - for (auto& metric : metrics_) { - Entry::Metric* proto_metric = proto_entry->add_metrics(); - proto_metric->set_metric_hash(std::get<0>(metric)); - proto_metric->set_value(std::get<1>(metric)); - } -} - -} // namespace ukm diff --git a/chromium/components/ukm/ukm_entry.h b/chromium/components/ukm/ukm_entry.h deleted file mode 100644 index 9adcedb3fa0..00000000000 --- a/chromium/components/ukm/ukm_entry.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2017 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. - -#ifndef COMPONENTS_UKM_UKM_ENTRY_H_ -#define COMPONENTS_UKM_UKM_ENTRY_H_ - -#include <string> -#include <vector> - -#include "base/macros.h" - -namespace ukm { - -class Entry; -class UkmEntryBuilder; - -// One UkmEntry contains metrics for a specific source and event. It is -// connected to a UkmSource by the source ID. The event can be user defined. -// One example is "PageLoad". Each UkmEntry can have a list of metrics, each of -// which consist of a metric name and value. When the entry is serialized to the -// proto message, the event and metric names will be hashed by -// base::HashMetricName. -// -// To build UkmEntry objects, please use UkmEntryBuilder. -class UkmEntry { - public: - // Serializes the members of the class into the supplied proto. - void PopulateProto(Entry* proto_entry) const; - - int32_t source_id() const { return source_id_; } - uint64_t event_hash() const { return event_hash_; } - - ~UkmEntry(); - - private: - friend UkmEntryBuilder; - - UkmEntry(int32_t source_id, const char* event_name); - - const int32_t source_id_; - const uint64_t event_hash_; - std::vector<std::pair<uint64_t, int64_t>> metrics_; - - DISALLOW_COPY_AND_ASSIGN(UkmEntry); -}; - -} // namespace ukm - -#endif // COMPONENTS_UKM_UKM_ENTRY_H_ diff --git a/chromium/components/ukm/ukm_entry_builder.cc b/chromium/components/ukm/ukm_entry_builder.cc deleted file mode 100644 index fdff949038c..00000000000 --- a/chromium/components/ukm/ukm_entry_builder.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 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 "components/ukm/ukm_entry_builder.h" - -#include "base/metrics/metrics_hashes.h" -#include "components/ukm/ukm_entry.h" -#include "components/ukm/ukm_service.h" - -namespace ukm { - -UkmEntryBuilder::UkmEntryBuilder(const UkmService::AddEntryCallback& callback, - int32_t source_id, - const char* event_name) - : add_entry_callback_(callback), - entry_(new UkmEntry(source_id, event_name)) {} - -UkmEntryBuilder::~UkmEntryBuilder() { - add_entry_callback_.Run(std::move(entry_)); -} - -void UkmEntryBuilder::AddMetric(const char* metric_name, int64_t value) { - entry_->metrics_.emplace_back( - std::make_pair(base::HashMetricName(metric_name), value)); -} - -} // namespace ukm diff --git a/chromium/components/ukm/ukm_recorder_impl.cc b/chromium/components/ukm/ukm_recorder_impl.cc new file mode 100644 index 00000000000..cb670812ebf --- /dev/null +++ b/chromium/components/ukm/ukm_recorder_impl.cc @@ -0,0 +1,177 @@ +// Copyright 2017 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 "components/ukm/ukm_recorder_impl.h" + +#include "base/metrics/field_trial.h" +#include "base/metrics/field_trial_params.h" +#include "base/metrics/histogram_macros.h" +#include "base/metrics/metrics_hashes.h" +#include "base/strings/string_split.h" +#include "components/metrics/proto/ukm/entry.pb.h" +#include "components/metrics/proto/ukm/report.pb.h" +#include "components/metrics/proto/ukm/source.pb.h" +#include "components/ukm/ukm_source.h" + +namespace ukm { + +namespace { + +// Gets the list of whitelisted Entries as string. Format is a comma seperated +// list of Entry names (as strings). +std::string GetWhitelistEntries() { + return base::GetFieldTrialParamValueByFeature(kUkmFeature, + "WhitelistEntries"); +} + +// Gets the maximum number of Sources we'll keep in memory before discarding any +// new ones being added. +size_t GetMaxSources() { + constexpr size_t kDefaultMaxSources = 500; + return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt( + kUkmFeature, "MaxSources", kDefaultMaxSources)); +} + +// Gets the maximum number of Entries we'll keep in memory before discarding any +// new ones being added. +size_t GetMaxEntries() { + constexpr size_t kDefaultMaxEntries = 5000; + return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt( + kUkmFeature, "MaxEntries", kDefaultMaxEntries)); +} + +// True if we should record the initial_url field of the UKM Source proto. +bool ShouldRecordInitialUrl() { + return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, + "RecordInitialUrl", false); +} + +enum class DroppedDataReason { + NOT_DROPPED = 0, + RECORDING_DISABLED = 1, + MAX_HIT = 2, + NOT_WHITELISTED = 3, + NUM_DROPPED_DATA_REASONS +}; + +void RecordDroppedSource(DroppedDataReason reason) { + UMA_HISTOGRAM_ENUMERATION( + "UKM.Sources.Dropped", static_cast<int>(reason), + static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); +} + +void RecordDroppedEntry(DroppedDataReason reason) { + UMA_HISTOGRAM_ENUMERATION( + "UKM.Entries.Dropped", static_cast<int>(reason), + static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); +} + +void StoreEntryProto(const mojom::UkmEntry& in, Entry* out) { + DCHECK(!out->has_source_id()); + DCHECK(!out->has_event_hash()); + + out->set_source_id(in.source_id); + out->set_event_hash(in.event_hash); + for (const auto& metric : in.metrics) { + Entry::Metric* proto_metric = out->add_metrics(); + proto_metric->set_metric_hash(metric->metric_hash); + proto_metric->set_value(metric->value); + } +} + +} // namespace + +UkmRecorderImpl::UkmRecorderImpl() : recording_enabled_(false) {} +UkmRecorderImpl::~UkmRecorderImpl() = default; + +void UkmRecorderImpl::EnableRecording() { + DVLOG(1) << "UkmRecorderImpl::EnableRecording"; + recording_enabled_ = true; +} + +void UkmRecorderImpl::DisableRecording() { + DVLOG(1) << "UkmRecorderImpl::DisableRecording"; + recording_enabled_ = false; +} + +void UkmRecorderImpl::Purge() { + sources_.clear(); + entries_.clear(); +} + +void UkmRecorderImpl::StoreRecordingsInReport(Report* report) { + for (const auto& kv : sources_) { + Source* proto_source = report->add_sources(); + kv.second->PopulateProto(proto_source); + if (!ShouldRecordInitialUrl()) + proto_source->clear_initial_url(); + } + for (const auto& entry : entries_) { + Entry* proto_entry = report->add_entries(); + StoreEntryProto(*entry, proto_entry); + } + + UMA_HISTOGRAM_COUNTS_1000("UKM.Sources.SerializedCount", sources_.size()); + UMA_HISTOGRAM_COUNTS_1000("UKM.Entries.SerializedCount", entries_.size()); + sources_.clear(); + entries_.clear(); +} + +void UkmRecorderImpl::UpdateSourceURL(ukm::SourceId source_id, + const GURL& url) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (!recording_enabled_) { + RecordDroppedSource(DroppedDataReason::RECORDING_DISABLED); + return; + } + + // Update the pre-existing source if there is any. This happens when the + // initial URL is different from the committed URL for the same source, e.g., + // when there is redirection. + if (base::ContainsKey(sources_, source_id)) { + sources_[source_id]->UpdateUrl(url); + return; + } + + if (sources_.size() >= GetMaxSources()) { + RecordDroppedSource(DroppedDataReason::MAX_HIT); + return; + } + std::unique_ptr<UkmSource> source = base::MakeUnique<UkmSource>(); + source->set_id(source_id); + source->set_url(url); + sources_.insert(std::make_pair(source_id, std::move(source))); +} + +void UkmRecorderImpl::AddEntry(mojom::UkmEntryPtr entry) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (!recording_enabled_) { + RecordDroppedEntry(DroppedDataReason::RECORDING_DISABLED); + return; + } + if (entries_.size() >= GetMaxEntries()) { + RecordDroppedEntry(DroppedDataReason::MAX_HIT); + return; + } + + if (!whitelisted_entry_hashes_.empty() && + !base::ContainsKey(whitelisted_entry_hashes_, entry->event_hash)) { + RecordDroppedEntry(DroppedDataReason::NOT_WHITELISTED); + return; + } + + entries_.push_back(std::move(entry)); +} + +void UkmRecorderImpl::StoreWhitelistedEntries() { + const auto entries = + base::SplitString(GetWhitelistEntries(), ",", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + for (const auto& entry_string : entries) + whitelisted_entry_hashes_.insert(base::HashMetricName(entry_string)); +} + +} // namespace ukm diff --git a/chromium/components/ukm/ukm_recorder_impl.h b/chromium/components/ukm/ukm_recorder_impl.h new file mode 100644 index 00000000000..50976e436d0 --- /dev/null +++ b/chromium/components/ukm/ukm_recorder_impl.h @@ -0,0 +1,78 @@ +// Copyright 2017 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. + +#ifndef COMPONENTS_UKM_UKM_RECORDER_IMPL_H_ +#define COMPONENTS_UKM_UKM_RECORDER_IMPL_H_ + +#include <map> +#include <set> +#include <vector> + +#include "base/threading/thread_checker.h" +#include "components/ukm/public/interfaces/ukm_interface.mojom.h" +#include "components/ukm/public/ukm_recorder.h" + +namespace metrics { +class UkmBrowserTest; +} + +namespace ukm { + +class UkmSource; +class Report; + +namespace debug { +class DebugPage; +} + +class UkmRecorderImpl : public UkmRecorder { + public: + UkmRecorderImpl(); + ~UkmRecorderImpl() override; + + // Enables/disables recording control if data is allowed to be collected. + void EnableRecording(); + void DisableRecording(); + + // Deletes stored recordings. + void Purge(); + + protected: + // Cache the list of whitelisted entries from the field trial parameter. + void StoreWhitelistedEntries(); + + // Writes recordings into a report proto, and clears recordings. + void StoreRecordingsInReport(Report* report); + + const std::map<ukm::SourceId, std::unique_ptr<UkmSource>>& sources() const { + return sources_; + } + + const std::vector<mojom::UkmEntryPtr>& entries() const { return entries_; } + + private: + friend ::metrics::UkmBrowserTest; + friend ::ukm::debug::DebugPage; + + // UkmRecorder: + void UpdateSourceURL(SourceId source_id, const GURL& url) override; + void AddEntry(mojom::UkmEntryPtr entry) override; + + // Whether recording new data is currently allowed. + bool recording_enabled_; + + // Contains newly added sources and entries of UKM metrics which periodically + // get serialized and cleared by BuildAndStoreLog(). + std::map<ukm::SourceId, std::unique_ptr<UkmSource>> sources_; + std::vector<mojom::UkmEntryPtr> entries_; + + // Whitelisted Entry hashes, only the ones in this set will be recorded. + std::set<uint64_t> whitelisted_entry_hashes_; + + THREAD_CHECKER(thread_checker_); +}; + +} // namespace ukm + +#endif // COMPONENTS_UKM_UKM_RECORDER_IMPL_H_ diff --git a/chromium/components/ukm/ukm_service.cc b/chromium/components/ukm/ukm_service.cc index 4c190c946ff..312ba041dd1 100644 --- a/chromium/components/ukm/ukm_service.cc +++ b/chromium/components/ukm/ukm_service.cc @@ -14,26 +14,17 @@ #include "base/metrics/field_trial.h" #include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/metrics_hashes.h" #include "base/rand_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "components/metrics/metrics_log.h" -#include "components/metrics/metrics_log_uploader.h" #include "components/metrics/metrics_service_client.h" -#include "components/metrics/proto/ukm/entry.pb.h" #include "components/metrics/proto/ukm/report.pb.h" -#include "components/metrics/proto/ukm/source.pb.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/ukm/persisted_logs_metrics_impl.h" -#include "components/ukm/ukm_entry.h" -#include "components/ukm/ukm_entry_builder.h" #include "components/ukm/ukm_pref_names.h" #include "components/ukm/ukm_rotation_scheduler.h" -#include "components/ukm/ukm_source.h" namespace ukm { @@ -43,35 +34,6 @@ namespace { // initialization work. constexpr int kInitializationDelaySeconds = 5; -// Gets the list of whitelisted Entries as string. Format is a comma seperated -// list of Entry names (as strings). -std::string GetWhitelistEntries() { - return base::GetFieldTrialParamValueByFeature(kUkmFeature, - "WhitelistEntries"); -} - -// Gets the maximum number of Sources we'll keep in memory before discarding any -// new ones being added. -size_t GetMaxSources() { - constexpr size_t kDefaultMaxSources = 500; - return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt( - kUkmFeature, "MaxSources", kDefaultMaxSources)); -} - -// Gets the maximum number of Entries we'll keep in memory before discarding any -// new ones being added. -size_t GetMaxEntries() { - constexpr size_t kDefaultMaxEntries = 5000; - return static_cast<size_t>(base::GetFieldTrialParamByFeatureAsInt( - kUkmFeature, "MaxEntries", kDefaultMaxEntries)); -} - -// True if we should record the initial_url field of the UKM Source proto. -bool ShouldRecordInitialUrl() { - return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, - "RecordInitialUrl", false); -} - // True if we should record session ids in the UKM Report proto. bool ShouldRecordSessionId() { return base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "RecordSessionId", @@ -104,34 +66,11 @@ int32_t LoadSessionId(PrefService* pref_service) { return session_id; } -enum class DroppedDataReason { - NOT_DROPPED = 0, - RECORDING_DISABLED = 1, - MAX_HIT = 2, - NOT_WHITELISTED = 3, - NUM_DROPPED_DATA_REASONS -}; - -void RecordDroppedSource(DroppedDataReason reason) { - UMA_HISTOGRAM_ENUMERATION( - "UKM.Sources.Dropped", static_cast<int>(reason), - static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); -} - -void RecordDroppedEntry(DroppedDataReason reason) { - UMA_HISTOGRAM_ENUMERATION( - "UKM.Entries.Dropped", static_cast<int>(reason), - static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS)); -} - } // namespace -const base::Feature kUkmFeature = {"Ukm", base::FEATURE_DISABLED_BY_DEFAULT}; - UkmService::UkmService(PrefService* pref_service, metrics::MetricsServiceClient* client) : pref_service_(pref_service), - recording_enabled_(false), client_id_(0), session_id_(0), client_(client), @@ -177,14 +116,6 @@ void UkmService::Initialize() { base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); } -void UkmService::EnableRecording() { - recording_enabled_ = true; -} - -void UkmService::DisableRecording() { - recording_enabled_ = false; -} - void UkmService::EnableReporting() { DCHECK(thread_checker_.CalledOnValidThread()); DVLOG(1) << "UkmService::EnableReporting"; @@ -254,8 +185,7 @@ void UkmService::Purge() { DCHECK(thread_checker_.CalledOnValidThread()); DVLOG(1) << "UkmService::Purge"; reporting_service_.ukm_log_store()->Purge(); - sources_.clear(); - entries_.clear(); + UkmRecorderImpl::Purge(); } // TODO(bmcquade): rename this to something more generic, like @@ -307,7 +237,7 @@ void UkmService::BuildAndStoreLog() { // Suppress generating a log if we have no new data to include. // TODO(zhenw): add a histogram here to debug if this case is hitting a lot. - if (sources_.empty() && entries_.empty()) + if (sources().empty() && entries().empty()) return; Report report; @@ -315,21 +245,7 @@ void UkmService::BuildAndStoreLog() { if (ShouldRecordSessionId()) report.set_session_id(session_id_); - for (const auto& kv : sources_) { - Source* proto_source = report.add_sources(); - kv.second->PopulateProto(proto_source); - if (!ShouldRecordInitialUrl()) - proto_source->clear_initial_url(); - } - for (const auto& entry : entries_) { - Entry* proto_entry = report.add_entries(); - entry->PopulateProto(proto_entry); - } - - UMA_HISTOGRAM_COUNTS_1000("UKM.Sources.SerializedCount", sources_.size()); - UMA_HISTOGRAM_COUNTS_1000("UKM.Entries.SerializedCount", entries_.size()); - sources_.clear(); - entries_.clear(); + StoreRecordingsInReport(&report); metrics::MetricsLog::RecordCoreSystemProfile(client_, report.mutable_system_profile()); @@ -343,74 +259,4 @@ void UkmService::BuildAndStoreLog() { reporting_service_.ukm_log_store()->StoreLog(serialized_log); } -// static -int32_t UkmService::GetNewSourceID() { - static int32_t next_source_id = 0; - return next_source_id++; -} - -std::unique_ptr<UkmEntryBuilder> UkmService::GetEntryBuilder( - int32_t source_id, - const char* event_name) { - return std::unique_ptr<UkmEntryBuilder>(new UkmEntryBuilder( - base::Bind(&UkmService::AddEntry, base::Unretained(this)), source_id, - event_name)); -} - -void UkmService::UpdateSourceURL(int32_t source_id, const GURL& url) { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (!recording_enabled_) { - RecordDroppedSource(DroppedDataReason::RECORDING_DISABLED); - return; - } - - // Update the pre-existing source if there is any. This happens when the - // initial URL is different from the committed URL for the same source, e.g., - // when there is redirection. - if (base::ContainsKey(sources_, source_id)) { - sources_[source_id]->UpdateUrl(url); - return; - } - - if (sources_.size() >= GetMaxSources()) { - RecordDroppedSource(DroppedDataReason::MAX_HIT); - return; - } - std::unique_ptr<UkmSource> source = base::MakeUnique<UkmSource>(); - source->set_id(source_id); - source->set_url(url); - sources_.insert(std::make_pair(source_id, std::move(source))); -} - -void UkmService::AddEntry(std::unique_ptr<UkmEntry> entry) { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (!recording_enabled_) { - RecordDroppedEntry(DroppedDataReason::RECORDING_DISABLED); - return; - } - if (entries_.size() >= GetMaxEntries()) { - RecordDroppedEntry(DroppedDataReason::MAX_HIT); - return; - } - - if (!whitelisted_entry_hashes_.empty() && - !base::ContainsKey(whitelisted_entry_hashes_, entry->event_hash())) { - RecordDroppedEntry(DroppedDataReason::NOT_WHITELISTED); - return; - } - - entries_.push_back(std::move(entry)); -} - -void UkmService::StoreWhitelistedEntries() { - const auto entries = - base::SplitString(GetWhitelistEntries(), ",", base::TRIM_WHITESPACE, - base::SPLIT_WANT_NONEMPTY); - for (const auto& entry_string : entries) { - whitelisted_entry_hashes_.insert(base::HashMetricName(entry_string)); - } -} - } // namespace ukm diff --git a/chromium/components/ukm/ukm_service.h b/chromium/components/ukm/ukm_service.h index 9b493a2a213..b6931198f3f 100644 --- a/chromium/components/ukm/ukm_service.h +++ b/chromium/components/ukm/ukm_service.h @@ -9,73 +9,43 @@ #include <memory> #include <vector> -#include "base/callback.h" -#include "base/feature_list.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "build/build_config.h" #include "components/metrics/metrics_provider.h" #include "components/metrics/metrics_rotation_scheduler.h" +#include "components/ukm/ukm_recorder_impl.h" #include "components/ukm/ukm_reporting_service.h" -#include "url/gurl.h" -class PluginInfoMessageFilter; class PrefRegistrySimple; class PrefService; -class UkmPageLoadMetricsObserver; - -namespace autofill { -class AutofillMetrics; -} // namespace autofill - -namespace translate { -class TranslateRankerImpl; -} - -namespace payments { -class JourneyLogger; -} // namespace payments namespace metrics { class MetricsServiceClient; +class UkmBrowserTest; } namespace ukm { -class UkmEntry; -class UkmEntryBuilder; -class UkmSource; - -// This feature controls whether UkmService should be created. -extern const base::Feature kUkmFeature; +namespace debug { +class DebugPage; +} // The URL-Keyed Metrics (UKM) service is responsible for gathering and // uploading reports that contain fine grained performance metrics including // URLs for top-level navigations. -class UkmService { +class UkmService : public UkmRecorderImpl { public: // Constructs a UkmService. // Calling code is responsible for ensuring that the lifetime of // |pref_service| is longer than the lifetime of UkmService. UkmService(PrefService* pref_service, metrics::MetricsServiceClient* client); - virtual ~UkmService(); - - // Get the new source ID, which is unique for the duration of a browser - // session. - static int32_t GetNewSourceID(); - - // Update the URL on the source keyed to the given source ID. If the source - // does not exist, it will create a new UkmSource object. - void UpdateSourceURL(int32_t source_id, const GURL& url); + ~UkmService() override; // Initializes the UKM service. void Initialize(); - // Enables/disables recording control if data is allowed to be collected. - void EnableRecording(); - void DisableRecording(); - // Enables/disables transmission of accumulated logs. Logs that have already // been created will remain persisted to disk. void EnableReporting(); @@ -104,24 +74,10 @@ class UkmService { // the provided PrefRegistry. static void RegisterPrefs(PrefRegistrySimple* registry); - using AddEntryCallback = base::Callback<void(std::unique_ptr<UkmEntry>)>; - - protected: - const std::map<int32_t, std::unique_ptr<UkmSource>>& sources_for_testing() - const { - return sources_; - } - - const std::vector<std::unique_ptr<UkmEntry>>& entries_for_testing() const { - return entries_; - } - private: - friend autofill::AutofillMetrics; - friend payments::JourneyLogger; - friend PluginInfoMessageFilter; - friend UkmPageLoadMetricsObserver; - friend translate::TranslateRankerImpl; + friend ::ukm::debug::DebugPage; + friend ::metrics::UkmBrowserTest; + FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, AddEntryWithEmptyMetrics); FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, EntryBuilderAndSerialization); FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, @@ -130,15 +86,6 @@ class UkmService { FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, PersistAndPurge); FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, WhitelistEntryTest); - // Get a new UkmEntryBuilder object for the specified source ID and event, - // which can get metrics added to. - // - // This API being private is intentional. Any client using UKM needs to - // declare itself to be a friend of UkmService and go through code review - // process. - std::unique_ptr<UkmEntryBuilder> GetEntryBuilder(int32_t source_id, - const char* event_name); - // Starts metrics client initialization. void StartInitTask(); @@ -159,18 +106,9 @@ class UkmService { // Called by log_uploader_ when the an upload is completed. void OnLogUploadComplete(int response_code); - // Add an entry to the UkmEntry list. - void AddEntry(std::unique_ptr<UkmEntry> entry); - - // Cache the list of whitelisted entries from the field trial parameter. - void StoreWhitelistedEntries(); - // A weak pointer to the PrefService used to read and write preferences. PrefService* pref_service_; - // Whether recording new data is currently allowed. - bool recording_enabled_; - // The UKM client id stored in prefs. uint64_t client_id_; @@ -195,14 +133,6 @@ class UkmService { bool initialize_started_; bool initialize_complete_; - // Contains newly added sources and entries of UKM metrics which periodically - // get serialized and cleared by BuildAndStoreLog(). - std::map<int32_t, std::unique_ptr<UkmSource>> sources_; - std::vector<std::unique_ptr<UkmEntry>> entries_; - - // Whitelisted Entry hashes, only the ones in this set will be recorded. - std::set<uint64_t> whitelisted_entry_hashes_; - // Weak pointers factory used to post task on different threads. All weak // pointers managed by this factory have the same lifetime as UkmService. base::WeakPtrFactory<UkmService> self_ptr_factory_; diff --git a/chromium/components/ukm/ukm_service_unittest.cc b/chromium/components/ukm/ukm_service_unittest.cc index 6177f7c345d..3f3e6432c8a 100644 --- a/chromium/components/ukm/ukm_service_unittest.cc +++ b/chromium/components/ukm/ukm_service_unittest.cc @@ -19,7 +19,7 @@ #include "components/metrics/test_metrics_service_client.h" #include "components/prefs/testing_pref_service.h" #include "components/ukm/persisted_logs_metrics_impl.h" -#include "components/ukm/ukm_entry_builder.h" +#include "components/ukm/public/ukm_entry_builder.h" #include "components/ukm/ukm_pref_names.h" #include "components/ukm/ukm_source.h" #include "components/variations/variations_associated_data.h" @@ -28,6 +28,24 @@ namespace ukm { +// A small shim exposing UkmRecorder methods to tests. +class TestRecordingHelper { + public: + TestRecordingHelper(UkmRecorder* recorder) : recorder_(recorder) {} + + void UpdateSourceURL(SourceId source_id, const GURL& url) { + recorder_->UpdateSourceURL(source_id, url); + }; + + std::unique_ptr<UkmEntryBuilder> GetEntryBuilder(SourceId source_id, + const char* event_name) { + return recorder_->GetEntryBuilder(source_id, event_name); + } + + private: + UkmRecorder* recorder_; +}; + namespace { // TODO(rkaplow): consider making this a generic testing class in @@ -147,21 +165,22 @@ TEST_F(UkmServiceTest, EnableDisableSchedule) { TEST_F(UkmServiceTest, PersistAndPurge) { UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(GetPersistedLogCount(), 0); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - int32_t id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + ukm::SourceId id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); // Should init, generate a log, and start an upload for source. task_runner_->RunPendingTasks(); EXPECT_TRUE(client_.uploader()->is_uploading()); // Flushes the generated log to disk and generates a new entry. { std::unique_ptr<UkmEntryBuilder> builder = - service.GetEntryBuilder(id, "PageLoad"); + recorder.GetEntryBuilder(id, "PageLoad"); builder->AddMetric("FirstContentfulPaint", 300); } service.Flush(); @@ -172,16 +191,17 @@ TEST_F(UkmServiceTest, PersistAndPurge) { TEST_F(UkmServiceTest, SourceSerialization) { UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(GetPersistedLogCount(), 0); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - int32_t id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/initial")); - service.UpdateSourceURL(id, GURL("https://google.com/intermediate")); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + ukm::SourceId id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/initial")); + recorder.UpdateSourceURL(id, GURL("https://google.com/intermediate")); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); service.Flush(); EXPECT_EQ(GetPersistedLogCount(), 1); @@ -198,14 +218,15 @@ TEST_F(UkmServiceTest, SourceSerialization) { TEST_F(UkmServiceTest, EntryBuilderAndSerialization) { UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(0, GetPersistedLogCount()); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - int32_t id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + ukm::SourceId id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); { std::unique_ptr<UkmEntryBuilder> foo_builder = service.GetEntryBuilder(id, "foo"); @@ -261,14 +282,15 @@ TEST_F(UkmServiceTest, EntryBuilderAndSerialization) { TEST_F(UkmServiceTest, AddEntryWithEmptyMetrics) { UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(0, GetPersistedLogCount()); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - int32_t id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + ukm::SourceId id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); { std::unique_ptr<UkmEntryBuilder> builder = @@ -282,6 +304,7 @@ TEST_F(UkmServiceTest, AddEntryWithEmptyMetrics) { TEST_F(UkmServiceTest, MetricsProviderTest) { UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); metrics::TestMetricsProvider* provider = new metrics::TestMetricsProvider(); service.RegisterMetricsProvider( @@ -296,8 +319,8 @@ TEST_F(UkmServiceTest, MetricsProviderTest) { service.EnableRecording(); service.EnableReporting(); - int32_t id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + ukm::SourceId id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); { std::unique_ptr<UkmEntryBuilder> builder = service.GetEntryBuilder(id, "PageLoad"); @@ -316,6 +339,7 @@ TEST_F(UkmServiceTest, MetricsProviderTest) { TEST_F(UkmServiceTest, LogsUploadedOnlyWhenHavingSourcesOrEntries) { UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(GetPersistedLogCount(), 0); service.Initialize(); task_runner_->RunUntilIdle(); @@ -328,8 +352,8 @@ TEST_F(UkmServiceTest, LogsUploadedOnlyWhenHavingSourcesOrEntries) { service.Flush(); EXPECT_EQ(GetPersistedLogCount(), 0); - int32_t id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + ukm::SourceId id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); // Includes a Source, so will persist. service.Flush(); EXPECT_EQ(GetPersistedLogCount(), 1); @@ -343,7 +367,7 @@ TEST_F(UkmServiceTest, LogsUploadedOnlyWhenHavingSourcesOrEntries) { service.Flush(); EXPECT_EQ(GetPersistedLogCount(), 2); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); { std::unique_ptr<UkmEntryBuilder> builder = service.GetEntryBuilder(id, "PageLoad"); @@ -359,9 +383,9 @@ TEST_F(UkmServiceTest, LogsUploadedOnlyWhenHavingSourcesOrEntries) { } TEST_F(UkmServiceTest, GetNewSourceID) { - int32_t id1 = UkmService::GetNewSourceID(); - int32_t id2 = UkmService::GetNewSourceID(); - int32_t id3 = UkmService::GetNewSourceID(); + ukm::SourceId id1 = UkmRecorder::GetNewSourceID(); + ukm::SourceId id2 = UkmRecorder::GetNewSourceID(); + ukm::SourceId id3 = UkmRecorder::GetNewSourceID(); EXPECT_NE(id1, id2); EXPECT_NE(id1, id3); EXPECT_NE(id2, id3); @@ -376,16 +400,17 @@ TEST_F(UkmServiceTest, RecordInitialUrl) { ClearPrefs(); UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(GetPersistedLogCount(), 0); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - int32_t id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/initial")); - service.UpdateSourceURL(id, GURL("https://google.com/intermediate")); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + ukm::SourceId id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/initial")); + recorder.UpdateSourceURL(id, GURL("https://google.com/intermediate")); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); service.Flush(); EXPECT_EQ(GetPersistedLogCount(), 1); @@ -413,14 +438,15 @@ TEST_F(UkmServiceTest, RecordSessionId) { ClearPrefs(); UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(0, GetPersistedLogCount()); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - auto id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar")); + auto id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar")); service.Flush(); EXPECT_EQ(1, GetPersistedLogCount()); @@ -438,18 +464,19 @@ TEST_F(UkmServiceTest, SourceSize) { ClearPrefs(); UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(0, GetPersistedLogCount()); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - auto id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar1")); - id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar2")); - id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar3")); + auto id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar1")); + id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar2")); + id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar3")); service.Flush(); EXPECT_EQ(1, GetPersistedLogCount()); @@ -462,13 +489,14 @@ TEST_F(UkmServiceTest, SourceSize) { TEST_F(UkmServiceTest, PurgeMidUpload) { UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(GetPersistedLogCount(), 0); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - auto id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar1")); + auto id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar1")); // Should init, generate a log, and start an upload. task_runner_->RunPendingTasks(); EXPECT_TRUE(client_.uploader()->is_uploading()); @@ -488,14 +516,15 @@ TEST_F(UkmServiceTest, WhitelistEntryTest) { ClearPrefs(); UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(0, GetPersistedLogCount()); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - auto id = UkmService::GetNewSourceID(); - service.UpdateSourceURL(id, GURL("https://google.com/foobar1")); + auto id = UkmRecorder::GetNewSourceID(); + recorder.UpdateSourceURL(id, GURL("https://google.com/foobar1")); { std::unique_ptr<UkmEntryBuilder> builder = @@ -533,17 +562,18 @@ TEST_F(UkmServiceTest, WhitelistEntryTest) { TEST_F(UkmServiceTest, SourceURLLength) { UkmService service(&prefs_, &client_); + TestRecordingHelper recorder(&service); EXPECT_EQ(0, GetPersistedLogCount()); service.Initialize(); task_runner_->RunUntilIdle(); service.EnableRecording(); service.EnableReporting(); - auto id = UkmService::GetNewSourceID(); + auto id = UkmRecorder::GetNewSourceID(); // This URL is too long to be recorded fully. const std::string long_string = "https://" + std::string(10000, 'a'); - service.UpdateSourceURL(id, GURL(long_string)); + recorder.UpdateSourceURL(id, GURL(long_string)); service.Flush(); EXPECT_EQ(1, GetPersistedLogCount()); diff --git a/chromium/components/ukm/ukm_source.h b/chromium/components/ukm/ukm_source.h index 68347468101..928144be056 100644 --- a/chromium/components/ukm/ukm_source.h +++ b/chromium/components/ukm/ukm_source.h @@ -16,14 +16,16 @@ namespace ukm { class Source; +typedef int64_t SourceId; + // Contains UKM data for a single navigation entry. class UkmSource { public: UkmSource(); ~UkmSource(); - int32_t id() const { return id_; } - void set_id(int32_t id) { id_ = id; } + ukm::SourceId id() const { return id_; } + void set_id(ukm::SourceId id) { id_ = id; } const GURL& initial_url() const { return initial_url_; } const GURL& url() const { return url_; } @@ -42,7 +44,7 @@ class UkmSource { void PopulateProto(Source* proto_source) const; private: - int32_t id_; + ukm::SourceId id_; // The final, canonical URL for this source. GURL url_; |