Commit 282196be authored by Tim Volodine's avatar Tim Volodine Committed by Commit Bot

Reland "Move AwMetricsServiceClient logic into components for reuse by WebLayer"

This reverts commit 5d840711.

Reason for revert:
the previous breakage and revert was due to an internal patch not having rolled into chromium. It has now, so relanding this CL.
(crbug.com/1046775)

Original change's description:
> Revert "Move AwMetricsServiceClient logic into components for reuse by WebLayer"
> 
> This reverts commit 43e5153c.
> 
> Reason for revert:
> broke some build bots, see https://bugs.chromium.org/p/chromium/issues/detail?id=1046775
> 
> https://ci.chromium.org/p/chrome/builders/ci/arm64-builder-rel/20782
> 
> 
> Original change's description:
> > Move AwMetricsServiceClient logic into components for reuse by WebLayer
> > 
> > The corresponding WebLayer changes are in a follow on CL. The TBR is for
> > the new DEP file which needs content/public/browser.
> > 
> > TBR=jam@chromium.org
> > 
> > Bug: 1025781
> > Change-Id: Ie895ba7246761416d52c98ae3d4b241fed62fa45
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1926505
> > Commit-Queue: Alex Clarke <alexclarke@chromium.org>
> > Reviewed-by: Bo <boliu@chromium.org>
> > Reviewed-by: Nate Fischer <ntfschr@chromium.org>
> > Reviewed-by: Alexei Svitkine <asvitkine@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#736313}
> 
> TBR=jam@chromium.org,boliu@chromium.org,asvitkine@chromium.org,blundell@chromium.org,alexclarke@chromium.org,tobiasjs@chromium.org,ntfschr@chromium.org
> 
> Change-Id: I2e52f5da2c62f769cedbcaa4671f1a0ebe193be5
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: 1025781
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2028047
> Reviewed-by: Tim Volodine <timvolodine@chromium.org>
> Commit-Queue: Tim Volodine <timvolodine@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#736366}

TBR=jam@chromium.org,boliu@chromium.org,asvitkine@chromium.org,blundell@chromium.org,timvolodine@chromium.org,alexclarke@chromium.org,tobiasjs@chromium.org,ntfschr@chromium.org

Change-Id: I24cbdc73208dcc78040ca1e5a2904cf0d06c6e52
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1025781
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2028127Reviewed-by: default avatarTim Volodine <timvolodine@chromium.org>
Commit-Queue: Tim Volodine <timvolodine@chromium.org>
Cr-Commit-Position: refs/heads/master@{#736373}
parent 47fc1dff
...@@ -336,7 +336,6 @@ generate_jni("browser_jni_headers") { ...@@ -336,7 +336,6 @@ generate_jni("browser_jni_headers") {
"java/src/org/chromium/android_webview/gfx/AwPicture.java", "java/src/org/chromium/android_webview/gfx/AwPicture.java",
"java/src/org/chromium/android_webview/gfx/JavaBrowserViewRendererHelper.java", "java/src/org/chromium/android_webview/gfx/JavaBrowserViewRendererHelper.java",
"java/src/org/chromium/android_webview/gfx/RootBeginFrameSourceWebView.java", "java/src/org/chromium/android_webview/gfx/RootBeginFrameSourceWebView.java",
"java/src/org/chromium/android_webview/metrics/AwMetricsLogUploader.java",
"java/src/org/chromium/android_webview/metrics/AwMetricsServiceClient.java", "java/src/org/chromium/android_webview/metrics/AwMetricsServiceClient.java",
"java/src/org/chromium/android_webview/permission/AwPermissionRequest.java", "java/src/org/chromium/android_webview/permission/AwPermissionRequest.java",
"java/src/org/chromium/android_webview/safe_browsing/AwSafeBrowsingConfigHelper.java", "java/src/org/chromium/android_webview/safe_browsing/AwSafeBrowsingConfigHelper.java",
...@@ -430,7 +429,6 @@ android_library("browser_java") { ...@@ -430,7 +429,6 @@ android_library("browser_java") {
"java/src/org/chromium/android_webview/gfx/AwPicture.java", "java/src/org/chromium/android_webview/gfx/AwPicture.java",
"java/src/org/chromium/android_webview/gfx/JavaBrowserViewRendererHelper.java", "java/src/org/chromium/android_webview/gfx/JavaBrowserViewRendererHelper.java",
"java/src/org/chromium/android_webview/gfx/RootBeginFrameSourceWebView.java", "java/src/org/chromium/android_webview/gfx/RootBeginFrameSourceWebView.java",
"java/src/org/chromium/android_webview/metrics/AwMetricsLogUploader.java",
"java/src/org/chromium/android_webview/metrics/AwMetricsServiceClient.java", "java/src/org/chromium/android_webview/metrics/AwMetricsServiceClient.java",
"java/src/org/chromium/android_webview/permission/AwGeolocationCallback.java", "java/src/org/chromium/android_webview/permission/AwGeolocationCallback.java",
"java/src/org/chromium/android_webview/permission/AwPermissionRequest.java", "java/src/org/chromium/android_webview/permission/AwPermissionRequest.java",
...@@ -510,6 +508,7 @@ android_library("common_platform_services_java") { ...@@ -510,6 +508,7 @@ android_library("common_platform_services_java") {
deps = [ deps = [
"//base:base_java", "//base:base_java",
"//components/embedder_support/android/metrics:java",
"//third_party/android_deps:androidx_annotation_annotation_java", "//third_party/android_deps:androidx_annotation_annotation_java",
] ]
......
...@@ -206,6 +206,7 @@ source_set("browser") { ...@@ -206,6 +206,7 @@ source_set("browser") {
"//components/crash/content/app", "//components/crash/content/app",
"//components/crash/content/browser", "//components/crash/content/browser",
"//components/embedder_support/android:web_contents_delegate", "//components/embedder_support/android:web_contents_delegate",
"//components/embedder_support/android/metrics",
"//components/google/core/common", "//components/google/core/common",
"//components/heap_profiling", "//components/heap_profiling",
"//components/metrics", "//components/metrics",
......
...@@ -16,6 +16,7 @@ include_rules = [ ...@@ -16,6 +16,7 @@ include_rules = [
"+components/crash/content/browser", "+components/crash/content/browser",
"+components/crash/core", "+components/crash/core",
"+components/download/public/common", "+components/download/public/common",
"+components/embedder_support/android/metrics",
"+components/heap_profiling", "+components/heap_profiling",
"+components/keyed_service/core", "+components/keyed_service/core",
"+components/minidump_uploader", "+components/minidump_uploader",
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "android_webview/browser/aw_content_browser_client.h" #include "android_webview/browser/aw_content_browser_client.h"
#include "android_webview/browser/aw_web_ui_controller_factory.h" #include "android_webview/browser/aw_web_ui_controller_factory.h"
#include "android_webview/browser/metrics/aw_metrics_service_client.h" #include "android_webview/browser/metrics/aw_metrics_service_client.h"
#include "android_webview/browser/metrics/memory_metrics_logger.h"
#include "android_webview/browser/network_service/aw_network_change_notifier_factory.h" #include "android_webview/browser/network_service/aw_network_change_notifier_factory.h"
#include "android_webview/common/aw_descriptors.h" #include "android_webview/common/aw_descriptors.h"
#include "android_webview/common/aw_paths.h" #include "android_webview/common/aw_paths.h"
...@@ -33,6 +32,7 @@ ...@@ -33,6 +32,7 @@
#include "base/message_loop/message_pump_type.h" #include "base/message_loop/message_pump_type.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "components/crash/content/browser/child_exit_observer_android.h" #include "components/crash/content/browser/child_exit_observer_android.h"
#include "components/embedder_support/android/metrics/memory_metrics_logger.h"
#include "components/heap_profiling/supervisor.h" #include "components/heap_profiling/supervisor.h"
#include "components/services/heap_profiling/public/cpp/settings.h" #include "components/services/heap_profiling/public/cpp/settings.h"
#include "components/user_prefs/user_prefs.h" #include "components/user_prefs/user_prefs.h"
...@@ -124,7 +124,7 @@ void AwBrowserMainParts::PreMainMessageLoopRun() { ...@@ -124,7 +124,7 @@ void AwBrowserMainParts::PreMainMessageLoopRun() {
content::WebUIControllerFactory::RegisterFactory( content::WebUIControllerFactory::RegisterFactory(
AwWebUIControllerFactory::GetInstance()); AwWebUIControllerFactory::GetInstance());
content::RenderFrameHost::AllowInjectingJavaScript(); content::RenderFrameHost::AllowInjectingJavaScript();
metrics_logger_ = std::make_unique<MemoryMetricsLogger>(); metrics_logger_ = std::make_unique<metrics::MemoryMetricsLogger>();
} }
bool AwBrowserMainParts::MainMessageLoopRun(int* result_code) { bool AwBrowserMainParts::MainMessageLoopRun(int* result_code) {
......
...@@ -13,11 +13,14 @@ ...@@ -13,11 +13,14 @@
#include "base/task/single_thread_task_executor.h" #include "base/task/single_thread_task_executor.h"
#include "content/public/browser/browser_main_parts.h" #include "content/public/browser/browser_main_parts.h"
namespace metrics {
class MemoryMetricsLogger;
}
namespace android_webview { namespace android_webview {
class AwBrowserProcess; class AwBrowserProcess;
class AwContentBrowserClient; class AwContentBrowserClient;
class MemoryMetricsLogger;
class AwBrowserMainParts : public content::BrowserMainParts { class AwBrowserMainParts : public content::BrowserMainParts {
public: public:
...@@ -37,7 +40,7 @@ class AwBrowserMainParts : public content::BrowserMainParts { ...@@ -37,7 +40,7 @@ class AwBrowserMainParts : public content::BrowserMainParts {
AwContentBrowserClient* browser_client_; AwContentBrowserClient* browser_client_;
std::unique_ptr<MemoryMetricsLogger> metrics_logger_; std::unique_ptr<metrics::MemoryMetricsLogger> metrics_logger_;
std::unique_ptr<AwBrowserProcess> browser_process_; std::unique_ptr<AwBrowserProcess> browser_process_;
......
...@@ -76,7 +76,6 @@ const char* const kPersistentPrefsWhitelist[] = { ...@@ -76,7 +76,6 @@ const char* const kPersistentPrefsWhitelist[] = {
prefs::kRestartsWithStaleSeed, prefs::kRestartsWithStaleSeed,
}; };
// Shows notifications which correspond to PersistentPrefStore's reading errors.
void HandleReadError(PersistentPrefStore::PrefReadError error) {} void HandleReadError(PersistentPrefStore::PrefReadError error) {}
base::FilePath GetPrefStorePath() { base::FilePath GetPrefStorePath() {
......
...@@ -4,19 +4,16 @@ ...@@ -4,19 +4,16 @@
source_set("metrics") { source_set("metrics") {
sources = [ sources = [
"aw_metrics_log_uploader.cc",
"aw_metrics_log_uploader.h",
"aw_metrics_service_client.cc", "aw_metrics_service_client.cc",
"aw_metrics_service_client.h", "aw_metrics_service_client.h",
"aw_stability_metrics_provider.cc", "aw_stability_metrics_provider.cc",
"aw_stability_metrics_provider.h", "aw_stability_metrics_provider.h",
"memory_metrics_logger.cc",
"memory_metrics_logger.h",
] ]
deps = [ deps = [
"//android_webview:browser_jni_headers", "//android_webview:browser_jni_headers",
"//android_webview/common", "//android_webview/common",
"//base", "//base",
"//components/embedder_support/android/metrics",
"//components/metrics", "//components/metrics",
"//components/metrics:gpu", "//components/metrics:gpu",
"//components/metrics:net", "//components/metrics:net",
...@@ -25,6 +22,5 @@ source_set("metrics") { ...@@ -25,6 +22,5 @@ source_set("metrics") {
"//components/version_info", "//components/version_info",
"//components/version_info/android:channel_getter", "//components/version_info/android:channel_getter",
"//content/public/browser", "//content/public/browser",
"//services/resource_coordinator/public/cpp/memory_instrumentation:browser",
] ]
} }
// 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 ANDROID_WEBVIEW_BROWSER_METRICS_AW_METRICS_LOG_UPLOADER_H_
#define ANDROID_WEBVIEW_BROWSER_METRICS_AW_METRICS_LOG_UPLOADER_H_
#include <jni.h>
#include <string>
#include "components/metrics/metrics_log_uploader.h"
namespace android_webview {
// Uploads UMA logs for WebView using the platform logging mechanism.
class AwMetricsLogUploader : public ::metrics::MetricsLogUploader {
public:
explicit AwMetricsLogUploader(
const ::metrics::MetricsLogUploader::UploadCallback& on_upload_complete);
~AwMetricsLogUploader() override;
// ::metrics::MetricsLogUploader:
// Note: |log_hash| and |log_signature| are only used by the normal UMA
// server. WebView uses the platform logging mechanism instead of the normal
// UMA server, so |log_hash| and |log_signature| aren't used.
void UploadLog(const std::string& compressed_log_data,
const std::string& log_hash,
const std::string& log_signature,
const metrics::ReportingInfo& reporting_info) override;
private:
const metrics::MetricsLogUploader::UploadCallback on_upload_complete_;
DISALLOW_COPY_AND_ASSIGN(AwMetricsLogUploader);
};
} // namespace android_webview
#endif // ANDROID_WEBVIEW_BROWSER_METRICS_AW_METRICS_LOG_UPLOADER_H_
...@@ -6,45 +6,27 @@ ...@@ -6,45 +6,27 @@
#include <jni.h> #include <jni.h>
#include <cstdint> #include <cstdint>
#include <memory>
#include "android_webview/browser/metrics/aw_metrics_log_uploader.h"
#include "android_webview/browser/metrics/aw_stability_metrics_provider.h" #include "android_webview/browser/metrics/aw_stability_metrics_provider.h"
#include "android_webview/browser_jni_headers/AwMetricsServiceClient_jni.h" #include "android_webview/browser_jni_headers/AwMetricsServiceClient_jni.h"
#include "android_webview/common/aw_features.h" #include "android_webview/common/aw_features.h"
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/base_paths_android.h" #include "base/base_paths_android.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/hash/hash.h"
#include "base/i18n/rtl.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "components/metrics/android_metrics_provider.h" #include "components/metrics/android_metrics_provider.h"
#include "components/metrics/call_stack_profile_metrics_provider.h" #include "components/metrics/call_stack_profile_metrics_provider.h"
#include "components/metrics/cpu_metrics_provider.h"
#include "components/metrics/drive_metrics_provider.h" #include "components/metrics/drive_metrics_provider.h"
#include "components/metrics/enabled_state_provider.h"
#include "components/metrics/entropy_state_provider.h" #include "components/metrics/entropy_state_provider.h"
#include "components/metrics/gpu/gpu_metrics_provider.h" #include "components/metrics/gpu/gpu_metrics_provider.h"
#include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_service.h" #include "components/metrics/metrics_service.h"
#include "components/metrics/metrics_state_manager.h"
#include "components/metrics/net/cellular_logic_helper.h"
#include "components/metrics/net/network_metrics_provider.h"
#include "components/metrics/ui/screen_info_metrics_provider.h"
#include "components/metrics/version_utils.h" #include "components/metrics/version_utils.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/version_info/android/channel_getter.h" #include "components/version_info/android/channel_getter.h"
#include "components/version_info/version_info.h" #include "components/version_info/version_info.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
namespace android_webview { namespace android_webview {
...@@ -71,30 +53,6 @@ const double kBetaDevCanarySampledInRate = 0.99; ...@@ -71,30 +53,6 @@ const double kBetaDevCanarySampledInRate = 0.99;
// consulting with the privacy team. // consulting with the privacy team.
const double kPackageNameLimitRate = 0.10; const double kPackageNameLimitRate = 0.10;
// Callbacks for metrics::MetricsStateManager::Create. Store/LoadClientInfo
// allow Windows Chrome to back up ClientInfo. They're no-ops for WebView.
void StoreClientInfo(const metrics::ClientInfo& client_info) {}
std::unique_ptr<metrics::ClientInfo> LoadClientInfo() {
std::unique_ptr<metrics::ClientInfo> client_info;
return client_info;
}
bool UintFallsInBottomPercentOfValues(uint32_t value, double percent) {
DCHECK_GT(percent, 0);
DCHECK_LT(percent, 1.00);
// Since hashing is ~uniform, the chance that the value falls in the bottom
// X% of possible values is X%. UINT32_MAX fits within the range of integers
// that can be expressed precisely by a 64-bit double. Casting back to a
// uint32_t means we can determine if the value falls within the bottom X%,
// within a 1/UINT32_MAX error margin.
uint32_t value_threshold =
static_cast<uint32_t>(static_cast<double>(UINT32_MAX) * percent);
return value < value_threshold;
}
// Normally kMetricsReportingEnabledTimestamp would be set by the // Normally kMetricsReportingEnabledTimestamp would be set by the
// MetricsStateManager. However, it assumes kMetricsClientID and // MetricsStateManager. However, it assumes kMetricsClientID and
// kMetricsReportingEnabledTimestamp are always set together. Because WebView // kMetricsReportingEnabledTimestamp are always set together. Because WebView
...@@ -116,36 +74,6 @@ void SetReportingEnabledDateIfNotSet(PrefService* prefs) { ...@@ -116,36 +74,6 @@ void SetReportingEnabledDateIfNotSet(PrefService* prefs) {
backfill_date.ToTimeT()); backfill_date.ToTimeT());
} }
std::unique_ptr<metrics::MetricsService> CreateMetricsService(
metrics::MetricsStateManager* state_manager,
metrics::MetricsServiceClient* client,
PrefService* prefs) {
auto service =
std::make_unique<metrics::MetricsService>(state_manager, client, prefs);
service->RegisterMetricsProvider(
std::make_unique<metrics::NetworkMetricsProvider>(
content::CreateNetworkConnectionTrackerAsyncGetter()));
service->RegisterMetricsProvider(
std::make_unique<android_webview::AwStabilityMetricsProvider>(prefs));
service->RegisterMetricsProvider(
std::make_unique<metrics::AndroidMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<metrics::CPUMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<metrics::EntropyStateProvider>(prefs));
service->RegisterMetricsProvider(
std::make_unique<metrics::GPUMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<metrics::DriveMetricsProvider>(
base::DIR_ANDROID_APP_DATA));
service->RegisterMetricsProvider(
std::make_unique<metrics::ScreenInfoMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<metrics::CallStackProfileMetricsProvider>());
service->InitializeMetricsRecordingState();
return service;
}
// Queries the system for the app's first install time and uses this in the // Queries the system for the app's first install time and uses this in the
// kInstallDate pref. Must be called before created a MetricsStateManager. // kInstallDate pref. Must be called before created a MetricsStateManager.
// TODO(https://crbug.com/1012025): remove this when the kInstallDate pref has // TODO(https://crbug.com/1012025): remove this when the kInstallDate pref has
...@@ -184,143 +112,17 @@ void PopulateSystemInstallDateIfNecessary(PrefService* prefs) { ...@@ -184,143 +112,17 @@ void PopulateSystemInstallDateIfNecessary(PrefService* prefs) {
// static // static
AwMetricsServiceClient* AwMetricsServiceClient::GetInstance() { AwMetricsServiceClient* AwMetricsServiceClient::GetInstance() {
static base::NoDestructor<AwMetricsServiceClient> client; static base::NoDestructor<AwMetricsServiceClient> client;
DCHECK_CALLED_ON_VALID_SEQUENCE(client.get()->sequence_checker_); client->EnsureOnValidSequence();
return client.get(); return client.get();
} }
AwMetricsServiceClient::AwMetricsServiceClient() = default; AwMetricsServiceClient::AwMetricsServiceClient() = default;
AwMetricsServiceClient::~AwMetricsServiceClient() = default; AwMetricsServiceClient::~AwMetricsServiceClient() = default;
// static
void AwMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
metrics::MetricsService::RegisterPrefs(registry);
metrics::StabilityMetricsHelper::RegisterPrefs(registry);
}
void AwMetricsServiceClient::Initialize(PrefService* pref_service) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!init_finished_);
pref_service_ = pref_service;
PopulateSystemInstallDateIfNecessary(pref_service_);
metrics_state_manager_ = metrics::MetricsStateManager::Create(
pref_service_, this, base::string16(),
base::BindRepeating(&StoreClientInfo),
base::BindRepeating(&LoadClientInfo));
init_finished_ = true;
MaybeStartMetrics();
}
void AwMetricsServiceClient::MaybeStartMetrics() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Treat the debugging flag the same as user consent because the user set it,
// but keep app_consent_ separate so we never persist data from an opted-out
// app.
bool user_consent_or_flag = user_consent_ || IsMetricsReportingForceEnabled();
if (init_finished_ && set_consent_finished_) {
if (app_consent_ && user_consent_or_flag) {
metrics_service_ = CreateMetricsService(metrics_state_manager_.get(),
this, pref_service_);
// Register for notifications so we can detect when the user or app are
// interacting with WebView. We use these as signals to wake up the
// MetricsService.
RegisterForNotifications();
metrics_state_manager_->ForceClientIdCreation();
SetReportingEnabledDateIfNotSet(pref_service_);
is_in_sample_ = IsInSample();
is_in_package_name_sample_ = IsInPackageNameSample();
if (IsReportingEnabled()) {
// WebView has no shutdown sequence, so there's no need for a matching
// Stop() call.
metrics_service_->Start();
}
} else {
pref_service_->ClearPref(metrics::prefs::kMetricsClientID);
pref_service_->ClearPref(
metrics::prefs::kMetricsReportingEnabledTimestamp);
}
}
}
void AwMetricsServiceClient::RegisterForNotifications() {
registrar_.Add(this, content::NOTIFICATION_LOAD_START,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
content::NotificationService::AllSources());
}
void AwMetricsServiceClient::SetHaveMetricsConsent(bool user_consent,
bool app_consent) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
set_consent_finished_ = true;
user_consent_ = user_consent;
app_consent_ = app_consent;
MaybeStartMetrics();
}
void AwMetricsServiceClient::SetFastStartupForTesting(
bool fast_startup_for_testing) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
fast_startup_for_testing_ = fast_startup_for_testing;
}
void AwMetricsServiceClient::SetUploadIntervalForTesting(
const base::TimeDelta& upload_interval) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
overridden_upload_interval_ = upload_interval;
}
std::unique_ptr<const base::FieldTrial::EntropyProvider>
AwMetricsServiceClient::CreateLowEntropyProvider() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return metrics_state_manager_->CreateLowEntropyProvider();
}
bool AwMetricsServiceClient::IsConsentGiven() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return user_consent_ && app_consent_;
}
bool AwMetricsServiceClient::IsReportingEnabled() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!app_consent_)
return false;
return IsMetricsReportingForceEnabled() ||
(EnabledStateProvider::IsReportingEnabled() && is_in_sample_);
}
metrics::MetricsService* AwMetricsServiceClient::GetMetricsService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This will be null if initialization hasn't finished, or if metrics
// collection is disabled.
return metrics_service_.get();
}
// In Chrome, UMA and Breakpad are enabled/disabled together by the same
// checkbox and they share the same client ID (a.k.a. GUID). SetMetricsClientId
// is intended to provide the ID to Breakpad. In WebView, UMA and Breakpad are
// independent, so this is a no-op.
void AwMetricsServiceClient::SetMetricsClientId(const std::string& client_id) {}
int32_t AwMetricsServiceClient::GetProduct() { int32_t AwMetricsServiceClient::GetProduct() {
return metrics::ChromeUserMetricsExtension::ANDROID_WEBVIEW; return metrics::ChromeUserMetricsExtension::ANDROID_WEBVIEW;
} }
std::string AwMetricsServiceClient::GetApplicationLocale() {
return base::i18n::GetConfiguredLocale();
}
bool AwMetricsServiceClient::GetBrand(std::string* brand_code) {
// WebView doesn't use brand codes.
return false;
}
metrics::SystemProfileProto::Channel AwMetricsServiceClient::GetChannel() { metrics::SystemProfileProto::Channel AwMetricsServiceClient::GetChannel() {
return metrics::AsProtobufChannel(version_info::android::GetChannel()); return metrics::AsProtobufChannel(version_info::android::GetChannel());
} }
...@@ -329,103 +131,54 @@ std::string AwMetricsServiceClient::GetVersionString() { ...@@ -329,103 +131,54 @@ std::string AwMetricsServiceClient::GetVersionString() {
return version_info::GetVersionNumber(); return version_info::GetVersionNumber();
} }
void AwMetricsServiceClient::CollectFinalMetricsForLog( double AwMetricsServiceClient::GetSampleRate() {
base::OnceClosure done_callback) { // Down-sample unknown channel as a precaution in case it ends up being
std::move(done_callback).Run(); // shipped to Stable users.
} version_info::Channel channel = version_info::android::GetChannel();
if (channel == version_info::Channel::STABLE ||
std::unique_ptr<metrics::MetricsLogUploader> channel == version_info::Channel::UNKNOWN) {
AwMetricsServiceClient::CreateUploader( return kStableSampledInRate;
const GURL& server_url,
const GURL& insecure_server_url,
base::StringPiece mime_type,
metrics::MetricsLogUploader::MetricServiceType service_type,
const metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
// |server_url|, |insecure_server_url|, and |mime_type| are unused because
// WebView sends metrics to the platform logging mechanism rather than to
// Chrome's metrics server.
return std::make_unique<AwMetricsLogUploader>(on_upload_complete);
}
base::TimeDelta AwMetricsServiceClient::GetStandardUploadInterval() {
// In WebView, metrics collection (when we batch up all logged histograms into
// a ChromeUserMetricsExtension proto) and metrics uploading (when the proto
// goes to the server) happen separately.
//
// This interval controls the metrics collection rate, so we choose the
// standard upload interval to make sure we're collecting metrics consistently
// with Chrome for Android. The metrics uploading rate for WebView is
// controlled by the platform logging mechanism. Since this mechanism has its
// own logic for rate-limiting on cellular connections, we disable the
// component-layer logic.
if (!overridden_upload_interval_.is_zero()) {
return overridden_upload_interval_;
} }
return metrics::GetUploadInterval(false /* use_cellular_upload_interval */); return kBetaDevCanarySampledInRate;
} }
bool AwMetricsServiceClient::ShouldStartUpFastForTesting() const { void AwMetricsServiceClient::InitInternal() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); PopulateSystemInstallDateIfNecessary(pref_service());
return fast_startup_for_testing_;
} }
std::string AwMetricsServiceClient::GetAppPackageName() { void AwMetricsServiceClient::OnMetricsStart() {
if (is_in_package_name_sample_ && CanRecordPackageNameForAppType()) { SetReportingEnabledDateIfNotSet(pref_service());
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jstring> j_app_name =
Java_AwMetricsServiceClient_getAppPackageName(env);
if (j_app_name)
return ConvertJavaStringToUTF8(env, j_app_name);
}
return std::string();
} }
void AwMetricsServiceClient::Observe( double AwMetricsServiceClient::GetPackageNameLimitRate() {
int type, return kPackageNameLimitRate;
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (type) {
case content::NOTIFICATION_LOAD_STOP:
case content::NOTIFICATION_LOAD_START:
case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
if (base::FeatureList::IsEnabled(features::kWebViewWakeMetricsService))
metrics_service_->OnApplicationNotIdle();
break;
default:
NOTREACHED();
}
} }
// WebView metrics are sampled at (possibly) different rates depending on bool AwMetricsServiceClient::ShouldWakeMetricsService() {
// channel, based on the client ID. Sampling is hard-coded (rather than return base::FeatureList::IsEnabled(features::kWebViewWakeMetricsService);
// controlled via variations, as in Chrome) because:
// - WebView is slow to download the variations seed and propagate it to each
// app, so we'd miss metrics from the first few runs of each app.
// - WebView uses the low-entropy source for all studies, so there would be
// crosstalk between the metrics sampling study and all other studies.
double AwMetricsServiceClient::GetSampleRate() {
double sampled_in_rate = kBetaDevCanarySampledInRate;
// Down-sample unknown channel as a precaution in case it ends up being
// shipped to Stable users.
version_info::Channel channel = version_info::android::GetChannel();
if (channel == version_info::Channel::STABLE ||
channel == version_info::Channel::UNKNOWN) {
sampled_in_rate = kStableSampledInRate;
}
return sampled_in_rate;
} }
bool AwMetricsServiceClient::IsInSample() { void AwMetricsServiceClient::RegisterAdditionalMetricsProviders(
// Called in MaybeStartMetrics(), after metrics_service_ is created. metrics::MetricsService* service) {
return IsInSample(base::PersistentHash(metrics_service_->GetClientId())); service->RegisterMetricsProvider(
std::make_unique<android_webview::AwStabilityMetricsProvider>(
pref_service()));
service->RegisterMetricsProvider(
std::make_unique<metrics::AndroidMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<metrics::DriveMetricsProvider>(
base::DIR_ANDROID_APP_DATA));
service->RegisterMetricsProvider(
std::make_unique<metrics::GPUMetricsProvider>());
} }
bool AwMetricsServiceClient::IsInSample(uint32_t value) { std::string AwMetricsServiceClient::GetAppPackageNameInternal() {
return UintFallsInBottomPercentOfValues(value, GetSampleRate()); JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jstring> j_app_name =
Java_AwMetricsServiceClient_getAppPackageName(env);
if (j_app_name)
return ConvertJavaStringToUTF8(env, j_app_name);
return std::string();
} }
bool AwMetricsServiceClient::CanRecordPackageNameForAppType() { bool AwMetricsServiceClient::CanRecordPackageNameForAppType() {
...@@ -435,21 +188,6 @@ bool AwMetricsServiceClient::CanRecordPackageNameForAppType() { ...@@ -435,21 +188,6 @@ bool AwMetricsServiceClient::CanRecordPackageNameForAppType() {
return Java_AwMetricsServiceClient_canRecordPackageNameForAppType(env); return Java_AwMetricsServiceClient_canRecordPackageNameForAppType(env);
} }
bool AwMetricsServiceClient::IsInPackageNameSample() {
// Check if this client falls within the group for which it's acceptable to
// log package name. This guarantees we enforce the privacy requirement
// because we never log package names for more than kPackageNameLimitRate
// percent of clients. We'll actually log package name for less than this,
// because we also filter out packages for certain types of apps (see
// CanRecordPackageNameForAppType()).
return IsInPackageNameSample(
base::PersistentHash(metrics_service_->GetClientId()));
}
bool AwMetricsServiceClient::IsInPackageNameSample(uint32_t value) {
return UintFallsInBottomPercentOfValues(value, kPackageNameLimitRate);
}
// static // static
void JNI_AwMetricsServiceClient_SetHaveMetricsConsent(JNIEnv* env, void JNI_AwMetricsServiceClient_SetHaveMetricsConsent(JNIEnv* env,
jboolean user_consent, jboolean user_consent,
......
...@@ -13,19 +13,13 @@ ...@@ -13,19 +13,13 @@
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/embedder_support/android/metrics/android_metrics_service_client.h"
#include "components/metrics/enabled_state_provider.h" #include "components/metrics/enabled_state_provider.h"
#include "components/metrics/metrics_log_uploader.h" #include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_service_client.h" #include "components/metrics/metrics_service_client.h"
#include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_registrar.h"
class PrefRegistrySimple;
class PrefService;
namespace metrics {
class MetricsStateManager;
}
namespace android_webview { namespace android_webview {
// These values are persisted to logs. Entries should not be renumbered and // These values are persisted to logs. Entries should not be renumbered and
...@@ -93,9 +87,8 @@ enum class BackfillInstallDate { ...@@ -93,9 +87,8 @@ enum class BackfillInstallDate {
// the client ID (generating a new ID if there was none). If this client is in // the client ID (generating a new ID if there was none). If this client is in
// the sample, it then calls MetricsService::Start(). If consent was not // the sample, it then calls MetricsService::Start(). If consent was not
// granted, MaybeStartMetrics() instead clears the client ID, if any. // granted, MaybeStartMetrics() instead clears the client ID, if any.
class AwMetricsServiceClient : public metrics::MetricsServiceClient,
public metrics::EnabledStateProvider, class AwMetricsServiceClient : public ::metrics::AndroidMetricsServiceClient {
public content::NotificationObserver {
friend class base::NoDestructor<AwMetricsServiceClient>; friend class base::NoDestructor<AwMetricsServiceClient>;
public: public:
...@@ -104,103 +97,23 @@ class AwMetricsServiceClient : public metrics::MetricsServiceClient, ...@@ -104,103 +97,23 @@ class AwMetricsServiceClient : public metrics::MetricsServiceClient,
AwMetricsServiceClient(); AwMetricsServiceClient();
~AwMetricsServiceClient() override; ~AwMetricsServiceClient() override;
// Registers local state prefs used by this class.
static void RegisterPrefs(PrefRegistrySimple* registry);
void Initialize(PrefService* pref_service);
void SetHaveMetricsConsent(bool user_consent, bool app_consent);
void SetFastStartupForTesting(bool fast_startup_for_testing);
void SetUploadIntervalForTesting(const base::TimeDelta& upload_interval);
std::unique_ptr<const base::FieldTrial::EntropyProvider>
CreateLowEntropyProvider();
// metrics::EnabledStateProvider
bool IsConsentGiven() const override;
bool IsReportingEnabled() const override;
// metrics::MetricsServiceClient // metrics::MetricsServiceClient
metrics::MetricsService* GetMetricsService() override;
void SetMetricsClientId(const std::string& client_id) override;
int32_t GetProduct() override; int32_t GetProduct() override;
std::string GetApplicationLocale() override;
bool GetBrand(std::string* brand_code) override;
metrics::SystemProfileProto::Channel GetChannel() override; metrics::SystemProfileProto::Channel GetChannel() override;
std::string GetVersionString() override; std::string GetVersionString() override;
void CollectFinalMetricsForLog(base::OnceClosure done_callback) override;
std::unique_ptr<metrics::MetricsLogUploader> CreateUploader(
const GURL& server_url,
const GURL& insecure_server_url,
base::StringPiece mime_type,
metrics::MetricsLogUploader::MetricServiceType service_type,
const metrics::MetricsLogUploader::UploadCallback& on_upload_complete)
override;
base::TimeDelta GetStandardUploadInterval() override;
bool ShouldStartUpFastForTesting() const override;
// Gets the embedding app's package name if it's OK to log. Otherwise, this
// returns the empty string.
std::string GetAppPackageName() override;
// content::NotificationObserver
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
protected:
// Returns the metrics sampling rate, to be used by IsInSample(). This is a
// double in the non-inclusive range (0.00, 1.00). Virtual for testing.
virtual double GetSampleRate();
// Determines if the client is within the random sample of clients for which // metrics::AndroidMetricsServiceClient:
// we log metrics. If this returns false, AwMetricsServiceClient should void InitInternal() override;
// indicate reporting is disabled. Sampling is due to storage/bandwidth void OnMetricsStart() override;
// considerations. Virtual for testing. double GetSampleRate() override;
virtual bool IsInSample(); double GetPackageNameLimitRate() override;
bool ShouldWakeMetricsService() override;
// Prefer calling the IsInSample() which takes no arguments. Virtual for void RegisterAdditionalMetricsProviders(
// testing. metrics::MetricsService* service) override;
virtual bool IsInSample(uint32_t value); bool CanRecordPackageNameForAppType() override;
std::string GetAppPackageNameInternal() override;
// Determines if the embedder app is the type of app for which we may log the
// package name. If this returns false, GetAppPackageName() must return empty
// string. Virtual for testing.
virtual bool CanRecordPackageNameForAppType();
// Determines if this client falls within the group for which it's acceptable
// to include the embedding app's package name. If this returns false,
// GetAppPackageName() must return the empty string (for
// privacy/fingerprintability reasons). Virtual for testing.
virtual bool IsInPackageNameSample();
// Prefer calling the IsInPackageNameSample() which takes no arguments.
// Virtual for testing.
virtual bool IsInPackageNameSample(uint32_t value);
private: private:
void MaybeStartMetrics();
void RegisterForNotifications();
std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager_;
std::unique_ptr<metrics::MetricsService> metrics_service_;
content::NotificationRegistrar registrar_;
PrefService* pref_service_ = nullptr;
bool init_finished_ = false;
bool set_consent_finished_ = false;
bool user_consent_ = false;
bool app_consent_ = false;
bool is_in_sample_ = false;
bool is_in_package_name_sample_ = false;
bool fast_startup_for_testing_ = false;
// When non-zero, this overrides the default value in
// GetStandardUploadInterval().
base::TimeDelta overridden_upload_interval_;
// AwMetricsServiceClient may be created before the UI thread is promoted to
// BrowserThread::UI. Use |sequence_checker_| to enforce that the
// AwMetricsServiceClient is used on a single thread.
base::SequenceChecker sequence_checker_;
DISALLOW_COPY_AND_ASSIGN(AwMetricsServiceClient); DISALLOW_COPY_AND_ASSIGN(AwMetricsServiceClient);
}; };
......
...@@ -23,16 +23,6 @@ ...@@ -23,16 +23,6 @@
namespace android_webview { namespace android_webview {
namespace { namespace {
// Scales up a uint32_t in the inverse of how UintFallsInBottomPercentOfValues()
// makes its judgment. This is useful so tests can use integers, which itself
// helps to avoid rounding issues.
uint32_t ScaleValue(uint32_t value) {
DCHECK_GE(value, 0u);
DCHECK_LE(value, 100u);
double rate = static_cast<double>(value) / 100;
return UINT32_MAX * rate;
}
// For client ID format, see: // For client ID format, see:
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) // https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
const char kTestClientId[] = "01234567-89ab-40cd-80ef-0123456789ab"; const char kTestClientId[] = "01234567-89ab-40cd-80ef-0123456789ab";
...@@ -60,12 +50,9 @@ class TestClient : public AwMetricsServiceClient { ...@@ -60,12 +50,9 @@ class TestClient : public AwMetricsServiceClient {
void SetInPackageNameSample(bool value) { in_package_name_sample_ = value; } void SetInPackageNameSample(bool value) { in_package_name_sample_ = value; }
// Expose the super class implementation for testing. // Expose the super class implementation for testing.
bool IsInSample(uint32_t value) override { using AwMetricsServiceClient::GetAppPackageNameInternal;
return AwMetricsServiceClient::IsInSample(value); using AwMetricsServiceClient::IsInPackageNameSample;
} using AwMetricsServiceClient::IsInSample;
bool IsInPackageNameSample(uint32_t value) override {
return AwMetricsServiceClient::IsInPackageNameSample(value);
}
protected: protected:
double GetSampleRate() override { return sampled_in_rate_; } double GetSampleRate() override { return sampled_in_rate_; }
...@@ -121,65 +108,6 @@ class AwMetricsServiceClientTest : public testing::Test { ...@@ -121,65 +108,6 @@ class AwMetricsServiceClientTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(AwMetricsServiceClientTest); DISALLOW_COPY_AND_ASSIGN(AwMetricsServiceClientTest);
}; };
TEST_F(AwMetricsServiceClientTest, TestSetConsentTrueBeforeInit) {
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
client->SetHaveMetricsConsent(true, true);
client->Initialize(prefs.get());
EXPECT_TRUE(client->IsRecordingActive());
EXPECT_TRUE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_TRUE(
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
TEST_F(AwMetricsServiceClientTest, TestSetConsentFalseBeforeInit) {
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
client->SetHaveMetricsConsent(false, false);
client->Initialize(prefs.get());
EXPECT_FALSE(client->IsRecordingActive());
EXPECT_FALSE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_FALSE(
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
TEST_F(AwMetricsServiceClientTest, TestSetConsentTrueAfterInit) {
auto prefs = CreateTestPrefs();
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(true, true);
EXPECT_TRUE(client->IsRecordingActive());
EXPECT_TRUE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_TRUE(
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
TEST_F(AwMetricsServiceClientTest, TestSetConsentFalseAfterInit) {
auto prefs = CreateTestPrefs();
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(false, false);
EXPECT_FALSE(client->IsRecordingActive());
EXPECT_FALSE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_FALSE(
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
// If there is already a valid client ID and enabled date, they should be
// reused.
TEST_F(AwMetricsServiceClientTest, TestKeepExistingClientIdAndEnabledDate) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
int64_t enabled_date = 12345;
prefs->SetInt64(metrics::prefs::kMetricsReportingEnabledTimestamp,
enabled_date);
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(true, true);
EXPECT_TRUE(client->IsRecordingActive());
EXPECT_TRUE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_EQ(kTestClientId, prefs->GetString(metrics::prefs::kMetricsClientID));
EXPECT_EQ(enabled_date,
prefs->GetInt64(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
// TODO(https://crbug.com/995544): remove this when the // TODO(https://crbug.com/995544): remove this when the
// kMetricsReportingEnabledTimestamp pref has been persisted for one or two // kMetricsReportingEnabledTimestamp pref has been persisted for one or two
// milestones. // milestones.
...@@ -194,154 +122,12 @@ TEST_F(AwMetricsServiceClientTest, TestBackfillEnabledDateIfMissing) { ...@@ -194,154 +122,12 @@ TEST_F(AwMetricsServiceClientTest, TestBackfillEnabledDateIfMissing) {
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp)); prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
} }
TEST_F(AwMetricsServiceClientTest, TestSetConsentFalseClearsIdAndEnabledDate) { TEST_F(AwMetricsServiceClientTest, TestGetPackageNameInternal) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(false, false);
EXPECT_FALSE(client->IsRecordingActive());
EXPECT_FALSE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_FALSE(
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
TEST_F(AwMetricsServiceClientTest, TestShouldNotUploadPackageName_AppType) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
client->SetRecordPackageNameForAppType(false);
client->SetInPackageNameSample(true);
client->SetHaveMetricsConsent(true, true);
std::string package_name = client->GetAppPackageName();
EXPECT_TRUE(package_name.empty());
}
TEST_F(AwMetricsServiceClientTest, TestShouldNotUploadPackageName_SampledOut) {
auto prefs = CreateTestPrefs(); auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId); prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get()); auto client = CreateAndInitTestClient(prefs.get());
client->SetRecordPackageNameForAppType(true); // Make sure GetPackageNameInternal returns a non-empty string.
client->SetInPackageNameSample(false); EXPECT_FALSE(client->GetAppPackageNameInternal().empty());
client->SetHaveMetricsConsent(true, true);
std::string package_name = client->GetAppPackageName();
EXPECT_TRUE(package_name.empty());
}
TEST_F(AwMetricsServiceClientTest, TestCanUploadPackageName) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
client->SetRecordPackageNameForAppType(true);
client->SetInPackageNameSample(true);
client->SetHaveMetricsConsent(true, true);
std::string package_name = client->GetAppPackageName();
EXPECT_FALSE(package_name.empty());
}
TEST_F(AwMetricsServiceClientTest, TestPackageNameLogic_SampleRateBelowTen) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
double sample_rate = 0.08;
client->SetSampleRate(sample_rate);
// When GetSampleRate() <= 0.10, everything in-sample should also be in the
// package name sample.
for (uint32_t value = 0; value < 8; ++value) {
EXPECT_TRUE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be in-sample";
EXPECT_TRUE(client->IsInPackageNameSample(ScaleValue(value)))
<< "Value " << value << " should be in the package name sample";
}
// After this, the only thing we care about is that we're out of sample (the
// package name logic shouldn't matter at this point, because we won't upload
// any records).
for (uint32_t value = 8; value < 100; ++value) {
EXPECT_FALSE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be out of sample";
}
}
TEST_F(AwMetricsServiceClientTest, TestPackageNameLogic_SampleRateAboveTen) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
double sample_rate = 0.90;
client->SetSampleRate(sample_rate);
// When GetSampleRate() > 0.10, only values up to 0.10 should be in the
// package name sample.
for (uint32_t value = 0; value < 10; ++value) {
EXPECT_TRUE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be in-sample";
EXPECT_TRUE(client->IsInPackageNameSample(ScaleValue(value)))
<< "Value " << value << " should be in the package name sample";
}
// After this (but until we hit the sample rate), clients should be in sample
// but not upload the package name.
for (uint32_t value = 10; value < 90; ++value) {
EXPECT_TRUE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be in-sample";
EXPECT_FALSE(client->IsInPackageNameSample(ScaleValue(value)))
<< "Value " << value << " should be out of the package name sample";
}
// After this, the only thing we care about is that we're out of sample (the
// package name logic shouldn't matter at this point, because we won't upload
// any records).
for (uint32_t value = 90; value < 100; ++value) {
EXPECT_FALSE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be out of sample";
}
}
TEST_F(AwMetricsServiceClientTest, TestCanForceEnableMetrics) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
metrics::switches::kForceEnableMetricsReporting);
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
// Flag should have higher precedence than sampling or user consent (but not
// app consent, so we set that to 'true' for this case).
client->SetHaveMetricsConsent(false, /* app_consent */ true);
client->SetInSample(false);
client->Initialize(prefs.get());
EXPECT_TRUE(client->IsReportingEnabled());
EXPECT_TRUE(client->IsRecordingActive());
}
TEST_F(AwMetricsServiceClientTest, TestCanForceEnableMetricsIfAlreadyEnabled) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
metrics::switches::kForceEnableMetricsReporting);
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
// This is a sanity check: flip consent and sampling to true, just to make
// sure the flag continues to work.
client->SetHaveMetricsConsent(true, true);
client->SetInSample(true);
client->Initialize(prefs.get());
EXPECT_TRUE(client->IsReportingEnabled());
EXPECT_TRUE(client->IsRecordingActive());
}
TEST_F(AwMetricsServiceClientTest, TestCannotForceEnableMetricsIfAppOptsOut) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
metrics::switches::kForceEnableMetricsReporting);
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
// Even with the flag, app consent should be respected.
client->SetHaveMetricsConsent(true, /* app_consent */ false);
client->SetInSample(true);
client->Initialize(prefs.get());
EXPECT_FALSE(client->IsReportingEnabled());
EXPECT_FALSE(client->IsRecordingActive());
} }
// TODO(https://crbug.com/1012025): remove this when the kInstallDate pref has // TODO(https://crbug.com/1012025): remove this when the kInstallDate pref has
......
include_rules = [ include_rules = [
"+components/background_task_scheduler/android/java", "+components/background_task_scheduler/android/java",
"+components/embedder_support/android/metrics/java",
"+components/minidump_uploader/android/java", "+components/minidump_uploader/android/java",
"-android_webview/glue", "-android_webview/glue",
......
...@@ -11,7 +11,9 @@ import android.os.HandlerThread; ...@@ -11,7 +11,9 @@ import android.os.HandlerThread;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.base.Consumer;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.components.metrics.AndroidMetricsLogUploader;
/** /**
* This class manages platform-specific services. (i.e. Google Services) The platform * This class manages platform-specific services. (i.e. Google Services) The platform
...@@ -27,7 +29,14 @@ public abstract class PlatformServiceBridge { ...@@ -27,7 +29,14 @@ public abstract class PlatformServiceBridge {
private static Handler sHandler; private static Handler sHandler;
private static final Object sHandlerLock = new Object(); private static final Object sHandlerLock = new Object();
protected PlatformServiceBridge() {} protected PlatformServiceBridge() {
AndroidMetricsLogUploader.setUploader(new Consumer<byte[]>() {
@Override
public void accept(byte[] data) {
logMetrics(data);
}
});
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
public static PlatformServiceBridge getInstance() { public static PlatformServiceBridge getInstance() {
......
// 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.
package org.chromium.android_webview.metrics;
import org.chromium.android_webview.common.PlatformServiceBridge;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
/**
* Passes UMA logs from native to PlatformServiceBridge.
*/
@JNINamespace("android_webview")
public class AwMetricsLogUploader {
@CalledByNative
public static void uploadLog(byte[] data) {
// This relies on WebViewChromiumFactoryProvider having already created the
// PlatformServiceBridge. This is guaranteed because metrics won't start until the
// PlatformServiceBridge.queryMetricsSetting() callback fires.
PlatformServiceBridge.getInstance().logMetrics(data);
}
}
...@@ -350,10 +350,9 @@ source_set("webview_instrumentation_test_native_jni_impl") { ...@@ -350,10 +350,9 @@ source_set("webview_instrumentation_test_native_jni_impl") {
deps = [ deps = [
":webview_instrumentation_test_native_jni", ":webview_instrumentation_test_native_jni",
"//android_webview/browser",
"//android_webview/browser/metrics",
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//components/embedder_support/android/metrics",
] ]
} }
......
include_rules = [ include_rules = [
"+components/embedder_support/android/metrics",
"+components/policy/android/javatests", "+components/policy/android/javatests",
"-content/public/android/java", "-content/public/android/java",
"+content/public/android/java/src/org/chromium/content_public", "+content/public/android/java/src/org/chromium/content_public",
......
...@@ -4,17 +4,18 @@ ...@@ -4,17 +4,18 @@
#include "android_webview/test/webview_instrumentation_test_native_jni/MemoryMetricsLoggerUtils_jni.h" #include "android_webview/test/webview_instrumentation_test_native_jni/MemoryMetricsLoggerUtils_jni.h"
#include "android_webview/browser/metrics/memory_metrics_logger.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/test/test_timeouts.h" #include "base/test/test_timeouts.h"
#include "components/embedder_support/android/metrics/memory_metrics_logger.h"
namespace android_webview { namespace android_webview {
// static // static
jboolean JNI_MemoryMetricsLoggerUtils_ForceRecordHistograms(JNIEnv* env) { jboolean JNI_MemoryMetricsLoggerUtils_ForceRecordHistograms(JNIEnv* env) {
auto* memory_metrics_logger = MemoryMetricsLogger::GetInstanceForTesting(); auto* memory_metrics_logger =
::metrics::MemoryMetricsLogger::GetInstanceForTesting();
if (!memory_metrics_logger) if (!memory_metrics_logger)
return false; return false;
......
...@@ -311,6 +311,7 @@ test("components_unittests") { ...@@ -311,6 +311,7 @@ test("components_unittests") {
"//components/crash/android:java", "//components/crash/android:java",
"//components/crash/android:unit_tests", "//components/crash/android:unit_tests",
"//components/download/internal/common:internal_java", "//components/download/internal/common:internal_java",
"//components/embedder_support/android/metrics:unit_tests",
"//components/gcm_driver/instance_id:test_support", "//components/gcm_driver/instance_id:test_support",
"//components/gcm_driver/instance_id/android:instance_id_driver_java", "//components/gcm_driver/instance_id/android:instance_id_driver_java",
"//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java", "//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java",
......
Collection of Android libraries that provides embedders with Collection of Android libraries that provides embedders with
typical implementations of interfaces of content layer. typical implementations of content and component layer interfaces.
# Copyright 2020 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("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
assert(is_android, "This component can only be depended on for android builds")
# Intended for content embedders such as WebView & WebLayer.
static_library("metrics") {
sources = [
"android_metrics_log_uploader.cc",
"android_metrics_log_uploader.h",
"android_metrics_service_client.cc",
"android_metrics_service_client.h",
"memory_metrics_logger.cc",
"memory_metrics_logger.h",
]
deps = [
":jni",
"//components/metrics",
"//components/metrics:net",
"//components/metrics:ui",
"//components/prefs",
"//content/public/browser",
"//services/resource_coordinator/public/cpp/memory_instrumentation:browser",
]
}
android_library("java") {
sources = [
"java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java",
]
deps = [
"//base:base_java",
"//base:jni_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
generate_jni("jni") {
sources = [
"java/src/org/chromium/components/metrics/AndroidMetricsLogUploader.java",
]
}
source_set("unit_tests") {
testonly = true
sources = [ "android_metrics_service_client_unittest.cc" ]
deps = [
":metrics",
"//base/test:test_support",
"//components/metrics",
"//components/prefs:test_support",
"//testing/gtest",
]
}
include_rules = [
"+components/metrics",
"+components/prefs",
"+content/public/browser",
"+services/resource_coordinator/public/cpp/memory_instrumentation",
]
file://base/metrics/OWNERS
ntfschr@chromium.org
# COMPONENT: Internals>Metrics
# TEAM: chromium-dev@chromium.org
// Copyright 2017 The Chromium Authors. All rights reserved. // Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "android_webview/browser/metrics/aw_metrics_log_uploader.h" #include "components/embedder_support/android/metrics/android_metrics_log_uploader.h"
#include "android_webview/browser_jni_headers/AwMetricsLogUploader_jni.h"
#include "base/android/jni_array.h" #include "base/android/jni_array.h"
#include "components/embedder_support/android/metrics/jni/AndroidMetricsLogUploader_jni.h"
#include "components/metrics/log_decoder.h" #include "components/metrics/log_decoder.h"
using base::android::ScopedJavaLocalRef; using base::android::ScopedJavaLocalRef;
using base::android::ToJavaByteArray; using base::android::ToJavaByteArray;
namespace android_webview { namespace metrics {
AwMetricsLogUploader::AwMetricsLogUploader( AndroidMetricsLogUploader::AndroidMetricsLogUploader(
const metrics::MetricsLogUploader::UploadCallback& on_upload_complete) const MetricsLogUploader::UploadCallback& on_upload_complete)
: on_upload_complete_(on_upload_complete) {} : on_upload_complete_(on_upload_complete) {}
AwMetricsLogUploader::~AwMetricsLogUploader() {} AndroidMetricsLogUploader::~AndroidMetricsLogUploader() = default;
void AwMetricsLogUploader::UploadLog( void AndroidMetricsLogUploader::UploadLog(
const std::string& compressed_log_data, const std::string& compressed_log_data,
const std::string& /*log_hash*/, const std::string& /*log_hash*/,
const std::string& /*log_signature*/, const std::string& /*log_signature*/,
const metrics::ReportingInfo& reporting_info) { const ReportingInfo& reporting_info) {
// WebView uses the platform logging mechanism instead of the normal UMA // This uploader uses the platform logging mechanism instead of the normal UMA
// server. The platform mechanism does its own compression, so undo the // server. The platform mechanism does its own compression, so undo the
// previous compression. // previous compression.
std::string log_data; std::string log_data;
if (!metrics::DecodeLogData(compressed_log_data, &log_data)) { if (!DecodeLogData(compressed_log_data, &log_data)) {
// If the log is corrupt, pretend the server rejected it (HTTP Bad Request). // If the log is corrupt, pretend the server rejected it (HTTP Bad Request).
on_upload_complete_.Run(400, 0, true); on_upload_complete_.Run(400, 0, true);
return; return;
...@@ -37,7 +37,7 @@ void AwMetricsLogUploader::UploadLog( ...@@ -37,7 +37,7 @@ void AwMetricsLogUploader::UploadLog(
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> java_data = ToJavaByteArray( ScopedJavaLocalRef<jbyteArray> java_data = ToJavaByteArray(
env, reinterpret_cast<const uint8_t*>(log_data.data()), log_data.size()); env, reinterpret_cast<const uint8_t*>(log_data.data()), log_data.size());
Java_AwMetricsLogUploader_uploadLog(env, java_data); Java_AndroidMetricsLogUploader_uploadLog(env, java_data);
// The platform mechanism doesn't provide a response code or any way to handle // The platform mechanism doesn't provide a response code or any way to handle
// failures, so we have nothing to pass to on_upload_complete. Just pass 200 // failures, so we have nothing to pass to on_upload_complete. Just pass 200
...@@ -45,4 +45,4 @@ void AwMetricsLogUploader::UploadLog( ...@@ -45,4 +45,4 @@ void AwMetricsLogUploader::UploadLog(
on_upload_complete_.Run(200, 0, true); on_upload_complete_.Run(200, 0, true);
} }
} // namespace android_webview } // namespace metrics
// Copyright 2020 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_EMBEDDER_SUPPORT_ANDROID_METRICS_ANDROID_METRICS_LOG_UPLOADER_H_
#define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_METRICS_ANDROID_METRICS_LOG_UPLOADER_H_
#include <string>
#include "components/metrics/metrics_log_uploader.h"
namespace metrics {
// Uploads UMA logs using the platform logging mechanism.
class AndroidMetricsLogUploader : public MetricsLogUploader {
public:
explicit AndroidMetricsLogUploader(
const MetricsLogUploader::UploadCallback& on_upload_complete);
~AndroidMetricsLogUploader() override;
AndroidMetricsLogUploader(const AndroidMetricsLogUploader&) = delete;
AndroidMetricsLogUploader& operator=(const AndroidMetricsLogUploader&) =
delete;
// MetricsLogUploader:
// Note: |log_hash| and |log_signature| are only used by the normal UMA
// server. This uploader uses a Java logging mechanism that ignores these
// fields.
void UploadLog(const std::string& compressed_log_data,
const std::string& log_hash,
const std::string& log_signature,
const ReportingInfo& reporting_info) override;
private:
const MetricsLogUploader::UploadCallback on_upload_complete_;
};
} // namespace metrics
#endif // COMPONENTS_EMBEDDER_SUPPORT_ANDROID_METRICS_ANDROID_METRICS_LOG_UPLOADER_H_
// Copyright 2020 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/embedder_support/android/metrics/android_metrics_service_client.h"
#include <cstdint>
#include "base/i18n/rtl.h"
#include "build/build_config.h"
#include "components/embedder_support/android/metrics/android_metrics_log_uploader.h"
#include "components/metrics/call_stack_profile_metrics_provider.h"
#include "components/metrics/cpu_metrics_provider.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/metrics_state_manager.h"
#include "components/metrics/net/cellular_logic_helper.h"
#include "components/metrics/net/network_metrics_provider.h"
#include "components/metrics/stability_metrics_helper.h"
#include "components/metrics/ui/screen_info_metrics_provider.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
namespace metrics {
namespace {
// Callbacks for MetricsStateManager::Create. Store/LoadClientInfo
// allow Windows Chrome to back up ClientInfo. They're no-ops for
// AndroidMetricsServiceClient.
void StoreClientInfo(const ClientInfo& client_info) {}
std::unique_ptr<ClientInfo> LoadClientInfo() {
std::unique_ptr<ClientInfo> client_info;
return client_info;
}
bool UintFallsInBottomPercentOfValues(uint32_t value, double fraction) {
DCHECK_GT(fraction, 0);
DCHECK_LT(fraction, 1.00);
// Since hashing is ~uniform, the chance that the value falls in the bottom
// X% of possible values is X%. UINT32_MAX fits within the range of integers
// that can be expressed precisely by a 64-bit double. Casting back to a
// uint32_t means we can determine if the value falls within the bottom X%,
// within a 1/UINT32_MAX error margin.
uint32_t value_threshold =
static_cast<uint32_t>(static_cast<double>(UINT32_MAX) * fraction);
return value < value_threshold;
}
} // namespace
AndroidMetricsServiceClient::AndroidMetricsServiceClient() = default;
AndroidMetricsServiceClient::~AndroidMetricsServiceClient() = default;
// static
void AndroidMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
MetricsService::RegisterPrefs(registry);
StabilityMetricsHelper::RegisterPrefs(registry);
}
void AndroidMetricsServiceClient::Initialize(PrefService* pref_service) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!init_finished_);
pref_service_ = pref_service;
InitInternal();
metrics_state_manager_ =
MetricsStateManager::Create(pref_service_, this, base::string16(),
base::BindRepeating(&StoreClientInfo),
base::BindRepeating(&LoadClientInfo));
init_finished_ = true;
MaybeStartMetrics();
}
void AndroidMetricsServiceClient::MaybeStartMetrics() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Treat the debugging flag the same as user consent because the user set it,
// but keep app_consent_ separate so we never persist data from an opted-out
// app.
bool user_consent_or_flag = user_consent_ || IsMetricsReportingForceEnabled();
if (init_finished_ && set_consent_finished_) {
if (app_consent_ && user_consent_or_flag) {
metrics_service_ = CreateMetricsService(metrics_state_manager_.get(),
this, pref_service_);
// Register for notifications so we can detect when the user or app are
// interacting with the embedder. We use these as signals to wake up the
// MetricsService.
RegisterForNotifications();
metrics_state_manager_->ForceClientIdCreation();
OnMetricsStart();
is_in_sample_ = IsInSample();
if (IsReportingEnabled()) {
// We assume the embedder has no shutdown sequence, so there's no need
// for a matching Stop() call.
metrics_service_->Start();
}
} else {
pref_service_->ClearPref(prefs::kMetricsClientID);
}
}
}
std::unique_ptr<MetricsService>
AndroidMetricsServiceClient::CreateMetricsService(
MetricsStateManager* state_manager,
AndroidMetricsServiceClient* client,
PrefService* prefs) {
auto service = std::make_unique<MetricsService>(state_manager, client, prefs);
// Although targeted at mobile, the unit tests runs on all platforms and the
// chrome os version CHECK fails if we include NetworkMetricsProvider.
#if !defined(OS_CHROMEOS)
service->RegisterMetricsProvider(std::make_unique<NetworkMetricsProvider>(
content::CreateNetworkConnectionTrackerAsyncGetter()));
#endif // defined(OS_CHROMEOS)
service->RegisterMetricsProvider(std::make_unique<CPUMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<ScreenInfoMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<CallStackProfileMetricsProvider>());
RegisterAdditionalMetricsProviders(service.get());
service->InitializeMetricsRecordingState();
return service;
}
void AndroidMetricsServiceClient::RegisterForNotifications() {
registrar_.Add(this, content::NOTIFICATION_LOAD_START,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
content::NotificationService::AllSources());
registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
content::NotificationService::AllSources());
}
void AndroidMetricsServiceClient::SetHaveMetricsConsent(bool user_consent,
bool app_consent) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
set_consent_finished_ = true;
user_consent_ = user_consent;
app_consent_ = app_consent;
MaybeStartMetrics();
}
void AndroidMetricsServiceClient::SetFastStartupForTesting(
bool fast_startup_for_testing) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
fast_startup_for_testing_ = fast_startup_for_testing;
}
void AndroidMetricsServiceClient::SetUploadIntervalForTesting(
const base::TimeDelta& upload_interval) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
overridden_upload_interval_ = upload_interval;
}
std::unique_ptr<const base::FieldTrial::EntropyProvider>
AndroidMetricsServiceClient::CreateLowEntropyProvider() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return metrics_state_manager_->CreateLowEntropyProvider();
}
bool AndroidMetricsServiceClient::IsConsentGiven() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return user_consent_ && app_consent_;
}
bool AndroidMetricsServiceClient::IsReportingEnabled() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!app_consent_)
return false;
return IsMetricsReportingForceEnabled() ||
(EnabledStateProvider::IsReportingEnabled() && is_in_sample_);
}
MetricsService* AndroidMetricsServiceClient::GetMetricsService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This will be null if initialization hasn't finished, or if metrics
// collection is disabled.
return metrics_service_.get();
}
// In Chrome, UMA and Crashpad are enabled/disabled together by the same
// checkbox and they share the same client ID (a.k.a. GUID). SetMetricsClientId
// is intended to provide the ID to Breakpad. In AndroidMetricsServiceClients
// UMA and Crashpad are independent, so this is a no-op.
void AndroidMetricsServiceClient::SetMetricsClientId(
const std::string& client_id) {}
std::string AndroidMetricsServiceClient::GetApplicationLocale() {
return base::i18n::GetConfiguredLocale();
}
bool AndroidMetricsServiceClient::GetBrand(std::string* brand_code) {
// AndroidMetricsServiceClients don't use brand codes.
return false;
}
void AndroidMetricsServiceClient::CollectFinalMetricsForLog(
base::OnceClosure done_callback) {
std::move(done_callback).Run();
}
std::unique_ptr<MetricsLogUploader> AndroidMetricsServiceClient::CreateUploader(
const GURL& server_url,
const GURL& insecure_server_url,
base::StringPiece mime_type,
MetricsLogUploader::MetricServiceType service_type,
const MetricsLogUploader::UploadCallback& on_upload_complete) {
// |server_url|, |insecure_server_url|, and |mime_type| are unused because
// AndroidMetricsServiceClients send metrics to the platform logging mechanism
// rather than to Chrome's metrics server.
return std::make_unique<AndroidMetricsLogUploader>(on_upload_complete);
}
base::TimeDelta AndroidMetricsServiceClient::GetStandardUploadInterval() {
// In AndroidMetricsServiceClients, metrics collection (when we batch up all
// logged histograms into a ChromeUserMetricsExtension proto) and metrics
// uploading (when the proto goes to the server) happen separately.
//
// This interval controls the metrics collection rate, so we choose the
// standard upload interval to make sure we're collecting metrics consistently
// with Chrome for Android. The metrics uploading rate for
// AndroidMetricsServiceClients is controlled by the platform logging
// mechanism. Since this mechanism has its own logic for rate-limiting on
// cellular connections, we disable the component-layer logic.
if (!overridden_upload_interval_.is_zero()) {
return overridden_upload_interval_;
}
return metrics::GetUploadInterval(false /* use_cellular_upload_interval */);
}
bool AndroidMetricsServiceClient::ShouldStartUpFastForTesting() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return fast_startup_for_testing_;
}
void AndroidMetricsServiceClient::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (type) {
case content::NOTIFICATION_LOAD_STOP:
case content::NOTIFICATION_LOAD_START:
case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
if (ShouldWakeMetricsService())
metrics_service_->OnApplicationNotIdle();
break;
default:
NOTREACHED();
}
}
bool AndroidMetricsServiceClient::IsInSample() {
// Called in MaybeStartMetrics(), after |metrics_service_| is created.
// NOTE IsInSample and IsInPackageNameSample deliberately use the same hash to
// guarantee we never exceed 10% of total, opted-in clients for PackageNames.
return IsInSample(base::PersistentHash(metrics_service_->GetClientId()));
}
bool AndroidMetricsServiceClient::IsInSample(uint32_t value) {
return UintFallsInBottomPercentOfValues(value, GetSampleRate());
}
bool AndroidMetricsServiceClient::IsInPackageNameSample() {
// Check if this client falls within the group for which it's acceptable to
// log package name. This guarantees we enforce the privacy requirement
// because we never log package names for more than kPackageNameLimitRate
// percent of clients. We'll actually log package name for less than this,
// because we also filter out packages for certain types of apps (see
// CanRecordPackageNameForAppType()).
return IsInPackageNameSample(
base::PersistentHash(metrics_service_->GetClientId()));
}
bool AndroidMetricsServiceClient::IsInPackageNameSample(uint32_t value) {
return UintFallsInBottomPercentOfValues(value, GetPackageNameLimitRate());
}
std::string AndroidMetricsServiceClient::GetAppPackageName() {
if (IsInPackageNameSample() && CanRecordPackageNameForAppType())
return GetAppPackageNameInternal();
return std::string();
}
} // namespace metrics
// Copyright 2020 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_EMBEDDER_SUPPORT_ANDROID_METRICS_ANDROID_METRICS_SERVICE_CLIENT_H_
#define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_METRICS_ANDROID_METRICS_SERVICE_CLIENT_H_
#include <memory>
#include <string>
#include "base/metrics/field_trial.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "components/metrics/enabled_state_provider.h"
#include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_service_client.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class PrefRegistrySimple;
class PrefService;
namespace metrics {
class MetricsStateManager;
// AndroidMetricsServiceClient is a singleton which manages metrics collection
// intended for use by WebView & WebLayer.
//
// Metrics should be enabled iff all these conditions are met:
// - The user has not opted out.
// - The app has not opted out.
// - This client is in the 10% sample (controlled by client ID hash).
// The first two are recorded in |user_consent_| and |app_consent_|, which are
// set by SetHaveMetricsConsent(). The last is recorded in |is_in_sample_|.
//
// Metrics are pseudonymously identified by a randomly-generated "client ID".
// AndroidMetricsServiceClient stores this in prefs, written to the app's data
// directory. There's a different such directory for each user, for each app,
// on each device. So the ID should be unique per (device, app, user) tuple.
//
// In order to be transparent about not associating an ID with an opted out user
// or app, the client ID should only be created and retained when neither the
// user nor the app have opted out. Otherwise, the presence of the ID could give
// the impression that metrics were being collected.
//
// AndroidMetricsServiceClient metrics set up happens like so:
//
// startup
// │
// ├────────────┐
// │ ▼
// │ query for consent
// ▼ │
// Initialize() │
// │ ▼
// │ SetHaveMetricsConsent()
// │ │
// │ ┌──────────┘
// ▼ ▼
// MaybeStartMetrics()
// │
// ▼
// MetricsService::Start()
//
// All the named functions in this diagram happen on the UI thread. Querying GMS
// happens in the background, and the result is posted back to the UI thread, to
// SetHaveMetricsConsent(). Querying GMS is slow, so SetHaveMetricsConsent()
// typically happens after Initialize(), but it may happen before.
//
// Each path sets a flag, |init_finished_| or |set_consent_finished_|, to show
// that path has finished, and then calls MaybeStartMetrics(). When
// MaybeStartMetrics() is called the first time, it sees only one flag is true,
// and does nothing. When MaybeStartMetrics() is called the second time, it
// decides whether to start metrics.
//
// If consent was granted, MaybeStartMetrics() determines sampling by hashing
// the client ID (generating a new ID if there was none). If this client is in
// the sample, it then calls MetricsService::Start(). If consent was not
// granted, MaybeStartMetrics() instead clears the client ID, if any.
class AndroidMetricsServiceClient : public MetricsServiceClient,
public EnabledStateProvider,
public content::NotificationObserver {
public:
AndroidMetricsServiceClient();
~AndroidMetricsServiceClient() override;
AndroidMetricsServiceClient(const AndroidMetricsServiceClient&) = delete;
AndroidMetricsServiceClient& operator=(const AndroidMetricsServiceClient&) =
delete;
static void RegisterPrefs(PrefRegistrySimple* registry);
void Initialize(PrefService* pref_service);
void SetHaveMetricsConsent(bool user_consent, bool app_consent);
void SetFastStartupForTesting(bool fast_startup_for_testing);
void SetUploadIntervalForTesting(const base::TimeDelta& upload_interval);
std::unique_ptr<const base::FieldTrial::EntropyProvider>
CreateLowEntropyProvider();
// EnabledStateProvider
bool IsConsentGiven() const override;
bool IsReportingEnabled() const override;
// MetricsServiceClient
MetricsService* GetMetricsService() override;
void SetMetricsClientId(const std::string& client_id) override;
std::string GetApplicationLocale() override;
bool GetBrand(std::string* brand_code) override;
void CollectFinalMetricsForLog(
const base::OnceClosure done_callback) override;
std::unique_ptr<MetricsLogUploader> CreateUploader(
const GURL& server_url,
const GURL& insecure_server_url,
base::StringPiece mime_type,
MetricsLogUploader::MetricServiceType service_type,
const MetricsLogUploader::UploadCallback& on_upload_complete) override;
base::TimeDelta GetStandardUploadInterval() override;
bool ShouldStartUpFastForTesting() const override;
// Gets the embedding app's package name if it's OK to log. Otherwise, this
// returns the empty string.
std::string GetAppPackageName() override;
// content::NotificationObserver
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
protected:
// Called by Initialize() to allow embedder specific initialization.
virtual void InitInternal() = 0;
// Called by MaybeStartMetrics() to allow embedder specific initialization.
virtual void OnMetricsStart() = 0;
// Returns the metrics sampling rate, to be used by IsInSample(). This is a
// double in the non-inclusive range (0.00, 1.00). Virtual for testing.
virtual double GetSampleRate() = 0;
// Determines if the client is within the random sample of clients for which
// we log metrics. If this returns false, MetricsServiceClient should
// indicate reporting is disabled. Sampling is due to storage/bandwidth
// considerations. Virtual for testing.
virtual bool IsInSample();
// Prefer calling the IsInSample() which takes no arguments. Virtual for
// testing.
virtual bool IsInSample(uint32_t value);
// Determines if the embedder app is the type of app for which we may log the
// package name. If this returns false, GetAppPackageName() must return empty
// string. Virtual for testing.
virtual bool CanRecordPackageNameForAppType() = 0;
// Determines if this client falls within the group for which it's acceptable
// to include the embedding app's package name. If this returns false,
// GetAppPackageName() must return the empty string (for
// privacy/fingerprintability reasons). Virtual for testing.
virtual bool IsInPackageNameSample();
// Prefer calling the IsInPackageNameSample() which takes no arguments.
// Virtual for testing.
virtual bool IsInPackageNameSample(uint32_t value);
// Caps the rate at which we upload package names. This is privacy sensitive.
virtual double GetPackageNameLimitRate() = 0;
// Whether or not MetricsService::OnApplicationNotIdle should be called for
// notifications.
virtual bool ShouldWakeMetricsService() = 0;
// Called by CreateMetricsService, allows the embedder to register additional
// MetricsProviders.
virtual void RegisterAdditionalMetricsProviders(MetricsService* service) = 0;
// Returns the embedding application's package name.
virtual std::string GetAppPackageNameInternal() = 0;
void EnsureOnValidSequence() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
PrefService* pref_service() const { return pref_service_; }
private:
void MaybeStartMetrics();
void RegisterForNotifications();
std::unique_ptr<MetricsService> CreateMetricsService(
MetricsStateManager* state_manager,
AndroidMetricsServiceClient* client,
PrefService* prefs);
std::unique_ptr<MetricsStateManager> metrics_state_manager_;
std::unique_ptr<MetricsService> metrics_service_;
content::NotificationRegistrar registrar_;
PrefService* pref_service_ = nullptr;
bool init_finished_ = false;
bool set_consent_finished_ = false;
bool user_consent_ = false;
bool app_consent_ = false;
bool is_in_sample_ = false;
bool fast_startup_for_testing_ = false;
// When non-zero, this overrides the default value in
// GetStandardUploadInterval().
base::TimeDelta overridden_upload_interval_;
// MetricsServiceClient may be created before the UI thread is promoted to
// BrowserThread::UI. Use |sequence_checker_| to enforce that the
// MetricsServiceClient is used on a single thread.
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace metrics
#endif // COMPONENTS_EMBEDDER_SUPPORT_ANDROID_METRICS_ANDROID_METRICS_SERVICE_CLIENT_H_
// Copyright 2020 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/embedder_support/android/metrics/android_metrics_service_client.h"
#include <memory>
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/metrics_switches.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace metrics {
namespace {
// Scales up a uint32_t in the inverse of how UintFallsInBottomPercentOfValues()
// makes its judgment. This is useful so tests can use integers, which itself
// helps to avoid rounding issues.
uint32_t ScaleValue(uint32_t value) {
DCHECK_GE(value, 0u);
DCHECK_LE(value, 100u);
double rate = static_cast<double>(value) / 100.0;
return static_cast<uint32_t>(static_cast<double>(UINT32_MAX) * rate);
}
// For client ID format, see:
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
const char kTestClientId[] = "01234567-89ab-40cd-80ef-0123456789ab";
class TestClient : public AndroidMetricsServiceClient {
public:
TestClient()
: sampled_in_rate_(1.00),
in_sample_(true),
record_package_name_for_app_type_(true),
in_package_name_sample_(true) {}
~TestClient() override = default;
bool IsRecordingActive() {
auto* service = GetMetricsService();
if (service)
return service->recording_active();
return false;
}
void SetSampleRate(double value) { sampled_in_rate_ = value; }
void SetInSample(bool value) { in_sample_ = value; }
void SetRecordPackageNameForAppType(bool value) {
record_package_name_for_app_type_ = value;
}
void SetInPackageNameSample(bool value) { in_package_name_sample_ = value; }
// Expose the super class implementation for testing.
using AndroidMetricsServiceClient::IsInPackageNameSample;
using AndroidMetricsServiceClient::IsInSample;
protected:
void InitInternal() override {}
void OnMetricsStart() override {}
double GetSampleRate() override { return sampled_in_rate_; }
bool IsInSample() override { return in_sample_; }
bool CanRecordPackageNameForAppType() override {
return record_package_name_for_app_type_;
}
bool IsInPackageNameSample() override { return in_package_name_sample_; }
// AndroidMetricsServiceClient:
SystemProfileProto::Channel GetChannel() override {
return SystemProfileProto::CHANNEL_BETA;
}
std::string GetVersionString() override { return "1.1.1.1"; }
int32_t GetProduct() override {
return metrics::ChromeUserMetricsExtension::CHROME;
}
double GetPackageNameLimitRate() override {
// This is slightly under 0.1 to ensure
// TestPackageNameLogic_SampleRateAboveTen passes. There's something odd
// with the rounding which causes that test to fail if this is 0.1
return 0.0999;
}
bool ShouldWakeMetricsService() override {
NOTREACHED();
return true;
}
void RegisterAdditionalMetricsProviders(MetricsService* service) override {}
std::string GetAppPackageNameInternal() override { return "TestPackage"; }
private:
double sampled_in_rate_;
bool in_sample_;
bool record_package_name_for_app_type_;
bool in_package_name_sample_;
DISALLOW_COPY_AND_ASSIGN(TestClient);
};
std::unique_ptr<TestingPrefServiceSimple> CreateTestPrefs() {
auto prefs = std::make_unique<TestingPrefServiceSimple>();
metrics::MetricsService::RegisterPrefs(prefs->registry());
return prefs;
}
std::unique_ptr<TestClient> CreateAndInitTestClient(PrefService* prefs) {
auto client = std::make_unique<TestClient>();
client->Initialize(prefs);
return client;
}
} // namespace
class AndroidMetricsServiceClientTest : public testing::Test {
public:
AndroidMetricsServiceClientTest()
: test_begin_time_(base::Time::Now().ToTimeT()),
task_runner_(new base::TestSimpleTaskRunner) {
// Required by MetricsService.
base::SetRecordActionTaskRunner(task_runner_);
}
const int64_t test_begin_time_;
protected:
~AndroidMetricsServiceClientTest() override = default;
private:
base::test::TaskEnvironment task_environment_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(AndroidMetricsServiceClientTest);
};
TEST_F(AndroidMetricsServiceClientTest, TestSetConsentTrueBeforeInit) {
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
client->SetHaveMetricsConsent(true, true);
client->Initialize(prefs.get());
EXPECT_TRUE(client->IsRecordingActive());
EXPECT_TRUE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_TRUE(
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
TEST_F(AndroidMetricsServiceClientTest, TestSetConsentFalseBeforeInit) {
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
client->SetHaveMetricsConsent(false, false);
client->Initialize(prefs.get());
EXPECT_FALSE(client->IsRecordingActive());
EXPECT_FALSE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_FALSE(
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
TEST_F(AndroidMetricsServiceClientTest, TestSetConsentTrueAfterInit) {
auto prefs = CreateTestPrefs();
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(true, true);
EXPECT_TRUE(client->IsRecordingActive());
EXPECT_TRUE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_GE(prefs->GetInt64(prefs::kMetricsReportingEnabledTimestamp),
test_begin_time_);
}
TEST_F(AndroidMetricsServiceClientTest, TestSetConsentFalseAfterInit) {
auto prefs = CreateTestPrefs();
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(false, false);
EXPECT_FALSE(client->IsRecordingActive());
EXPECT_FALSE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_FALSE(prefs->HasPrefPath(prefs::kMetricsReportingEnabledTimestamp));
}
// If there is already a valid client ID and enabled date, they should be
// reused.
TEST_F(AndroidMetricsServiceClientTest,
TestKeepExistingClientIdAndEnabledDate) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
int64_t enabled_date = 12345;
prefs->SetInt64(metrics::prefs::kMetricsReportingEnabledTimestamp,
enabled_date);
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(true, true);
EXPECT_TRUE(client->IsRecordingActive());
EXPECT_TRUE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_EQ(kTestClientId, prefs->GetString(metrics::prefs::kMetricsClientID));
EXPECT_EQ(enabled_date,
prefs->GetInt64(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
TEST_F(AndroidMetricsServiceClientTest,
TestSetConsentFalseClearsIdAndEnabledDate) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(false, false);
EXPECT_FALSE(client->IsRecordingActive());
EXPECT_FALSE(prefs->HasPrefPath(metrics::prefs::kMetricsClientID));
EXPECT_FALSE(
prefs->HasPrefPath(metrics::prefs::kMetricsReportingEnabledTimestamp));
}
TEST_F(AndroidMetricsServiceClientTest,
TestShouldNotUploadPackageName_AppType) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(true, true);
client->SetRecordPackageNameForAppType(false);
client->SetInPackageNameSample(true);
std::string package_name = client->GetAppPackageName();
EXPECT_TRUE(package_name.empty());
}
TEST_F(AndroidMetricsServiceClientTest,
TestShouldNotUploadPackageName_SampledOut) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(true, true);
client->SetRecordPackageNameForAppType(true);
client->SetInPackageNameSample(false);
std::string package_name = client->GetAppPackageName();
EXPECT_TRUE(package_name.empty());
}
TEST_F(AndroidMetricsServiceClientTest, TestCanUploadPackageName) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
client->SetHaveMetricsConsent(true, true);
client->SetRecordPackageNameForAppType(true);
client->SetInPackageNameSample(true);
std::string package_name = client->GetAppPackageName();
EXPECT_FALSE(package_name.empty());
}
TEST_F(AndroidMetricsServiceClientTest,
TestPackageNameLogic_SampleRateBelowTen) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
double sample_rate = 0.08;
client->SetSampleRate(sample_rate);
// When GetSampleRate() <= 0.10, everything in-sample should also be in the
// package name sample.
for (uint32_t value = 0; value < 8; ++value) {
EXPECT_TRUE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be in-sample";
EXPECT_TRUE(client->IsInPackageNameSample(ScaleValue(value)))
<< "Value " << value << " should be in the package name sample";
}
// After this, the only thing we care about is that we're out of sample (the
// package name logic shouldn't matter at this point, because we won't upload
// any records).
for (uint32_t value = 8; value < 100; ++value) {
EXPECT_FALSE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be out of sample";
}
}
TEST_F(AndroidMetricsServiceClientTest,
TestPackageNameLogic_SampleRateAboveTen) {
auto prefs = CreateTestPrefs();
prefs->SetString(metrics::prefs::kMetricsClientID, kTestClientId);
auto client = CreateAndInitTestClient(prefs.get());
double sample_rate = 0.90;
client->SetSampleRate(sample_rate);
// When GetSampleRate() > 0.10, only values up to 0.10 should be in the
// package name sample.
for (uint32_t value = 0; value < 10; ++value) {
EXPECT_TRUE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be in-sample";
EXPECT_TRUE(client->IsInPackageNameSample(ScaleValue(value)))
<< "Value " << value << " should be in the package name sample";
}
// After this (but until we hit the sample rate), clients should be in sample
// but not upload the package name.
for (uint32_t value = 10; value < 90; ++value) {
EXPECT_TRUE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be in-sample";
EXPECT_FALSE(client->IsInPackageNameSample(ScaleValue(value)))
<< "Value " << value << " should be out of the package name sample";
}
// After this, the only thing we care about is that we're out of sample (the
// package name logic shouldn't matter at this point, because we won't upload
// any records).
for (uint32_t value = 90; value < 100; ++value) {
EXPECT_FALSE(client->IsInSample(ScaleValue(value)))
<< "Value " << value << " should be out of sample";
}
}
TEST_F(AndroidMetricsServiceClientTest, TestCanForceEnableMetrics) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
metrics::switches::kForceEnableMetricsReporting);
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
// Flag should have higher precedence than sampling or user consent (but not
// app consent, so we set that to 'true' for this case).
client->SetHaveMetricsConsent(false, /* app_consent */ true);
client->SetInSample(false);
client->Initialize(prefs.get());
EXPECT_TRUE(client->IsReportingEnabled());
EXPECT_TRUE(client->IsRecordingActive());
}
TEST_F(AndroidMetricsServiceClientTest,
TestCanForceEnableMetricsIfAlreadyEnabled) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
metrics::switches::kForceEnableMetricsReporting);
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
// This is a sanity check: flip consent and sampling to true, just to make
// sure the flag continues to work.
client->SetHaveMetricsConsent(true, true);
client->SetInSample(true);
client->Initialize(prefs.get());
EXPECT_TRUE(client->IsReportingEnabled());
EXPECT_TRUE(client->IsRecordingActive());
}
TEST_F(AndroidMetricsServiceClientTest,
TestCannotForceEnableMetricsIfAppOptsOut) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
metrics::switches::kForceEnableMetricsReporting);
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
// Even with the flag, app consent should be respected.
client->SetHaveMetricsConsent(true, /* app_consent */ false);
client->SetInSample(true);
client->Initialize(prefs.get());
EXPECT_FALSE(client->IsReportingEnabled());
EXPECT_FALSE(client->IsRecordingActive());
}
} // namespace metrics
// Copyright 2020 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.
package org.chromium.components.metrics;
import org.chromium.base.Consumer;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
/**
* Passes UMA logs from native to a java uploader.
*/
@JNINamespace("metrics")
public class AndroidMetricsLogUploader {
private static volatile Consumer<byte[]> sUploader;
/**
* Configures the consumer of logs data submitted via uploadLog, should be called once during
* start up.
*
* @param uploader The consumer of logs data submitted via uploadLog.
*/
public static void setUploader(Consumer<byte[]> uploader) {
sUploader = uploader;
}
@CalledByNative
public static void uploadLog(byte[] data) {
final Consumer<byte[]> uploader = sUploader;
if (uploader != null) {
uploader.accept(data);
}
}
}
// Copyright 2019 The Chromium Authors. All rights reserved. // Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "android_webview/browser/metrics/memory_metrics_logger.h" #include "components/embedder_support/android/metrics/memory_metrics_logger.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
using memory_instrumentation::GetPrivateFootprintHistogramName; using memory_instrumentation::GetPrivateFootprintHistogramName;
using memory_instrumentation::HistogramProcessType; using memory_instrumentation::HistogramProcessType;
namespace android_webview { namespace metrics {
namespace { namespace {
MemoryMetricsLogger* g_instance = nullptr; MemoryMetricsLogger* g_instance = nullptr;
...@@ -56,6 +56,8 @@ void RecordMemoryMetricsImpl( ...@@ -56,6 +56,8 @@ void RecordMemoryMetricsImpl(
} }
// WebView only supports the browser and possibly renderer process. // WebView only supports the browser and possibly renderer process.
// TODO(weblayer-team): refactor to allow the embedder to record GPU
// metrics.
case memory_instrumentation::mojom::ProcessType::GPU: case memory_instrumentation::mojom::ProcessType::GPU:
FALLTHROUGH; FALLTHROUGH;
case memory_instrumentation::mojom::ProcessType::ARC: case memory_instrumentation::mojom::ProcessType::ARC:
...@@ -146,4 +148,4 @@ void MemoryMetricsLogger::RecordMemoryMetrics(scoped_refptr<State> state, ...@@ -146,4 +148,4 @@ void MemoryMetricsLogger::RecordMemoryMetrics(scoped_refptr<State> state,
RecordMemoryMetricsAfterDelay(state); RecordMemoryMetricsAfterDelay(state);
} }
} // namespace android_webview } // namespace metrics
// Copyright 2019 The Chromium Authors. All rights reserved. // Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef ANDROID_WEBVIEW_BROWSER_METRICS_MEMORY_METRICS_LOGGER_H_ #ifndef COMPONENTS_EMBEDDER_SUPPORT_ANDROID_METRICS_MEMORY_METRICS_LOGGER_H_
#define ANDROID_WEBVIEW_BROWSER_METRICS_MEMORY_METRICS_LOGGER_H_ #define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_METRICS_MEMORY_METRICS_LOGGER_H_
#include <jni.h>
#include <memory>
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
namespace android_webview { namespace metrics {
// MemoryMetricsLogger is responsible for logging the memory related heartbeat // MemoryMetricsLogger is responsible for logging the memory related heartbeat
// metrics. MemoryMetricsLogger logs metrics at certain intervals for as long // metrics. MemoryMetricsLogger logs metrics at certain intervals for as long
...@@ -26,11 +22,8 @@ class MemoryMetricsLogger { ...@@ -26,11 +22,8 @@ class MemoryMetricsLogger {
MemoryMetricsLogger(); MemoryMetricsLogger();
~MemoryMetricsLogger(); ~MemoryMetricsLogger();
private: MemoryMetricsLogger(const MemoryMetricsLogger&) = delete;
struct State; MemoryMetricsLogger& operator=(const MemoryMetricsLogger&) = delete;
friend jboolean JNI_MemoryMetricsLoggerUtils_ForceRecordHistograms(
JNIEnv* env);
// Returns the single instance, if one was created. // Returns the single instance, if one was created.
static MemoryMetricsLogger* GetInstanceForTesting(); static MemoryMetricsLogger* GetInstanceForTesting();
...@@ -40,6 +33,9 @@ class MemoryMetricsLogger { ...@@ -40,6 +33,9 @@ class MemoryMetricsLogger {
// TaskRunner. // TaskRunner.
void ScheduleRecordForTesting(RecordCallback done_callback); void ScheduleRecordForTesting(RecordCallback done_callback);
private:
struct State;
// Called on the task runner to record metrics after a delay. // Called on the task runner to record metrics after a delay.
static void RecordMemoryMetricsAfterDelay(scoped_refptr<State> state); static void RecordMemoryMetricsAfterDelay(scoped_refptr<State> state);
...@@ -50,10 +46,8 @@ class MemoryMetricsLogger { ...@@ -50,10 +46,8 @@ class MemoryMetricsLogger {
RecordCallback done_callback); RecordCallback done_callback);
scoped_refptr<State> state_; scoped_refptr<State> state_;
DISALLOW_COPY_AND_ASSIGN(MemoryMetricsLogger);
}; };
} // namespace android_webview } // namespace metrics
#endif // ANDROID_WEBVIEW_BROWSER_METRICS_MEMORY_METRICS_LOGGER_H_ #endif // COMPONENTS_EMBEDDER_SUPPORT_ANDROID_METRICS_MEMORY_METRICS_LOGGER_H_
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