blob: ed7f2f4678091e70cdd73cd09bd741b3ab8d3d8a [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/metrics/chrome_metrics_service_client.h"
#include <stddef.h>
#include <memory>
#include <set>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/base64.h"
#include "base/check_op.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/metrics/statistics_recorder.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/google/google_brand.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/metrics/cached_metrics_profile.h"
#include "chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h"
#include "chrome/browser/metrics/chrome_metrics_extensions_helper.h"
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/metrics/chrome_metrics_services_manager_client.h"
#include "chrome/browser/metrics/desktop_platform_features_metrics_provider.h"
#include "chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service_factory.h"
#include "chrome/browser/metrics/desktop_session_duration/desktop_session_metrics_provider.h"
#include "chrome/browser/metrics/family_link_user_metrics_provider.h"
#include "chrome/browser/metrics/https_engagement_metrics_provider.h"
#include "chrome/browser/metrics/metrics_reporting_state.h"
#include "chrome/browser/metrics/network_quality_estimator_provider_impl.h"
#include "chrome/browser/metrics/usertype_by_devicetype_metrics_provider.h"
#include "chrome/browser/performance_manager/metrics/metrics_provider_common.h"
#include "chrome/browser/privacy_budget/identifiability_study_state.h"
#include "chrome/browser/privacy_budget/privacy_budget_metrics_provider.h"
#include "chrome/browser/privacy_budget/privacy_budget_prefs.h"
#include "chrome/browser/privacy_budget/privacy_budget_ukm_entry_filter.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/safe_browsing/metrics/safe_browsing_metrics_provider.h"
#include "chrome/browser/sync/device_info_sync_service_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/tracing/chrome_background_tracing_metrics_provider.h"
#include "chrome/browser/translate/translate_ranker_metrics_provider.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/component_updater/component_updater_service.h"
#include "components/crash/core/common/crash_keys.h"
#include "components/history/core/browser/history_service.h"
#include "components/metrics/call_stacks/call_stack_profile_metrics_provider.h"
#include "components/metrics/component_metrics_provider.h"
#include "components/metrics/content/content_stability_metrics_provider.h"
#include "components/metrics/content/gpu_metrics_provider.h"
#include "components/metrics/content/rendering_perf_metrics_provider.h"
#include "components/metrics/content/subprocess_metrics_provider.h"
#include "components/metrics/cpu_metrics_provider.h"
#include "components/metrics/demographics/demographic_metrics_provider.h"
#include "components/metrics/drive_metrics_provider.h"
#include "components/metrics/entropy_state_provider.h"
#include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_reporting_default_state.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/metrics_service_client.h"
#include "components/metrics/metrics_state_manager.h"
#include "components/metrics/metrics_switches.h"
#include "components/metrics/net/cellular_logic_helper.h"
#include "components/metrics/net/net_metrics_log_uploader.h"
#include "components/metrics/net/network_metrics_provider.h"
#include "components/metrics/persistent_histograms.h"
#include "components/metrics/persistent_synthetic_trial_observer.h"
#include "components/metrics/sampling_metrics_provider.h"
#include "components/metrics/stability_metrics_helper.h"
#include "components/metrics/structured/structured_metrics_features.h" // nogncheck
#include "components/metrics/structured/structured_metrics_service.h" // nogncheck
#include "components/metrics/ui/form_factor_metrics_provider.h"
#include "components/metrics/ui/screen_info_metrics_provider.h"
#include "components/metrics/url_constants.h"
#include "components/metrics/version_utils.h"
#include "components/network_time/network_time_tracker.h"
#include "components/omnibox/browser/omnibox_metrics_provider.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/buildflags.h"
#include "components/sync/service/passphrase_type_metrics_provider.h"
#include "components/sync/service/sync_service.h"
#include "components/sync_device_info/device_count_metrics_provider.h"
#include "components/ukm/field_trials_provider_helper.h"
#include "components/ukm/ukm_service.h"
#include "components/variations/synthetic_trial_registry.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/histogram_fetcher.h"
#include "content/public/browser/network_service_instance.h"
#include "google_apis/google_api_keys.h"
#include "ppapi/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/metrics/chrome_android_metrics_provider.h"
#include "chrome/browser/metrics/page_load_metrics_provider.h"
#include "components/metrics/android_metrics_provider.h"
#include "components/metrics/gms_metrics_provider.h"
#else
#include "chrome/browser/metrics/browser_activity_watcher.h"
#include "chrome/browser/performance_manager/metrics/metrics_provider_desktop.h"
#endif
#if BUILDFLAG(IS_POSIX)
#include <signal.h>
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/metrics/extensions_metrics_provider.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/buildflags/buildflags.h"
#include "extensions/common/extension.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/metrics/lacros_metrics_provider.h"
#include "chromeos/startup/browser_params_proxy.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
#include "base/feature_list.h"
#include "chrome/browser/ash/arc/vmm/vmm_metrics_provider.h"
#include "chrome/browser/ash/login/demo_mode/demo_session.h"
#include "chrome/browser/ash/printing/printer_metrics_provider.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/ash/settings/device_settings_service.h"
#include "chrome/browser/ash/system_web_apps/apps/personalization_app/keyboard_backlight_color_metrics_provider.h"
#include "chrome/browser/ash/system_web_apps/apps/personalization_app/personalization_app_theme_metrics_provider.h"
#include "chrome/browser/ash/system_web_apps/apps/personalization_app/wallpaper_metrics_provider.h"
#include "chrome/browser/metrics/ambient_mode_metrics_provider.h"
#include "chrome/browser/metrics/assistant_service_metrics_provider.h"
#include "chrome/browser/metrics/chromeos_family_link_user_metrics_provider.h"
#include "chrome/browser/metrics/chromeos_metrics_provider.h"
#include "chrome/browser/metrics/chromeos_system_profile_provider.h"
#include "chrome/browser/metrics/cros_healthd_metrics_provider.h"
#include "chrome/browser/metrics/family_user_metrics_provider.h"
#include "chrome/browser/metrics/per_user_state_manager_chromeos.h"
#include "chrome/browser/metrics/update_engine_metrics_provider.h"
#include "chrome/browser/ui/webui/ash/settings/services/metrics/os_settings_metrics_provider.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/metrics/structured/ash_structured_metrics_recorder.h" // nogncheck
#else
#include "chrome/browser/metrics/structured/chrome_structured_metrics_delegate.h" // nogncheck
#include "chrome/browser/metrics/structured/chrome_structured_metrics_recorder.h" // nogncheck
#endif
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "chrome/browser/metrics/antivirus_metrics_provider_win.h"
#include "chrome/browser/metrics/google_update_metrics_provider_win.h"
#include "chrome/install_static/install_util.h"
#include "chrome/installer/util/util_constants.h"
#include "chrome/notification_helper/notification_helper_constants.h"
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
#include "components/metrics/motherboard_metrics_provider.h"
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
#include "chrome/browser/metrics/chrome_metrics_service_crash_reporter.h"
#endif
#if !BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/signin/chrome_signin_and_sync_status_metrics_provider.h"
#include "components/metrics/content/accessibility_metrics_provider.h"
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_MAC)
#include "chrome/browser/metrics/power/power_metrics_provider_mac.h"
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/metrics/bluetooth_metrics_provider.h"
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
namespace {
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
const int kMaxHistogramStorageKiB = 100 << 10; // 100 MiB
#else
const int kMaxHistogramStorageKiB = 500 << 10; // 500 MiB
#endif
// This specifies the amount of time to wait for all renderers to send their
// data.
const int kMaxHistogramGatheringWaitDuration = 60000; // 60 seconds.
// Needs to be kept in sync with the writer in
// third_party/crashpad/crashpad/handler/handler_main.cc.
const char kCrashpadHistogramAllocatorName[] = "CrashpadMetrics";
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
base::LazyInstance<ChromeMetricsServiceCrashReporter>::Leaky g_crash_reporter =
LAZY_INSTANCE_INITIALIZER;
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_WIN)
// Needs to be kept in sync with the writer in PlatformExperienceHelper.
const char kPlatformExperienceHelperHistogramAllocatorName[] =
"PlatformExperienceHelperMetrics";
#endif // BUILDFLAG(IS_WIN)
void RegisterFileMetricsPreferences(PrefRegistrySimple* registry) {
metrics::FileMetricsProvider::RegisterSourcePrefs(registry,
kBrowserMetricsName);
metrics::FileMetricsProvider::RegisterSourcePrefs(
registry, kDeferredBrowserMetricsName);
metrics::FileMetricsProvider::RegisterSourcePrefs(
registry, kCrashpadHistogramAllocatorName);
#if BUILDFLAG(IS_WIN)
metrics::FileMetricsProvider::RegisterSourcePrefs(
registry, installer::kSetupHistogramAllocatorName);
metrics::FileMetricsProvider::RegisterSourcePrefs(
registry, notification_helper::kNotificationHelperHistogramAllocatorName);
metrics::FileMetricsProvider::RegisterSourcePrefs(
registry, kPlatformExperienceHelperHistogramAllocatorName);
#endif
}
// Constructs the name of a persistent metrics file from a directory and metrics
// name, and either registers that file as associated with a previous run if
// metrics reporting is enabled, or deletes it if not.
void RegisterOrRemovePreviousRunMetricsFile(
bool metrics_reporting_enabled,
const base::FilePath& dir,
std::string_view metrics_name,
metrics::FileMetricsProvider::SourceAssociation association,
metrics::FileMetricsProvider* file_metrics_provider) {
base::FilePath metrics_file =
base::GlobalHistogramAllocator::ConstructFilePath(dir, metrics_name);
if (metrics_reporting_enabled) {
// Enable reading any existing saved metrics.
file_metrics_provider->RegisterSource(metrics::FileMetricsProvider::Params(
metrics_file,
metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
association, metrics_name));
} else {
// When metrics reporting is not enabled, any existing file should be
// deleted in order to preserve user privacy.
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::GetDeleteFileCallback(metrics_file));
}
}
std::unique_ptr<metrics::FileMetricsProvider> CreateFileMetricsProvider(
bool metrics_reporting_enabled) {
// Create an object to monitor files of metrics and include them in reports.
std::unique_ptr<metrics::FileMetricsProvider> file_metrics_provider(
new metrics::FileMetricsProvider(g_browser_process->local_state()));
base::FilePath user_data_dir;
if (base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
// Register the Crashpad metrics files.
// Register the data from the previous run if crashpad_handler didn't exit
// cleanly.
RegisterOrRemovePreviousRunMetricsFile(
metrics_reporting_enabled, user_data_dir,
kCrashpadHistogramAllocatorName,
metrics::FileMetricsProvider::
ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
file_metrics_provider.get());
base::FilePath browser_metrics_upload_dir =
user_data_dir.AppendASCII(kBrowserMetricsName);
base::FilePath deferred_browser_metrics_upload_dir =
user_data_dir.AppendASCII(kDeferredBrowserMetricsName);
if (metrics_reporting_enabled) {
metrics::FileMetricsProvider::Params browser_metrics_params(
browser_metrics_upload_dir,
metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
metrics::FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE,
kBrowserMetricsName);
browser_metrics_params.max_dir_kib = kMaxHistogramStorageKiB;
browser_metrics_params.filter = base::BindRepeating(
&ChromeMetricsServiceClient::FilterBrowserMetricsFiles);
file_metrics_provider->RegisterSource(browser_metrics_params);
metrics::FileMetricsProvider::Params deferred_browser_metrics_params(
deferred_browser_metrics_upload_dir,
metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
metrics::FileMetricsProvider::ASSOCIATE_CURRENT_RUN,
kDeferredBrowserMetricsName);
deferred_browser_metrics_params.max_dir_kib = kMaxHistogramStorageKiB;
file_metrics_provider->RegisterSource(deferred_browser_metrics_params);
base::FilePath crashpad_active_path =
base::GlobalHistogramAllocator::ConstructFilePathForActiveFile(
user_data_dir, kCrashpadHistogramAllocatorName);
// Register data that will be populated for the current run. "Active"
// files need an empty "prefs_key" because they update the file itself.
file_metrics_provider->RegisterSource(
metrics::FileMetricsProvider::Params(
crashpad_active_path,
metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
metrics::FileMetricsProvider::ASSOCIATE_CURRENT_RUN));
} else {
// When metrics reporting is not enabled, any existing files should be
// deleted in order to preserve user privacy.
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::GetDeletePathRecursivelyCallback(
std::move(browser_metrics_upload_dir)));
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::GetDeletePathRecursivelyCallback(
std::move(deferred_browser_metrics_upload_dir)));
}
}
#if BUILDFLAG(IS_WIN)
// Read metrics file from setup.exe.
base::FilePath program_dir;
base::PathService::Get(base::DIR_EXE, &program_dir);
file_metrics_provider->RegisterSource(metrics::FileMetricsProvider::Params(
program_dir.AppendASCII(installer::kSetupHistogramAllocatorName),
metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
metrics::FileMetricsProvider::ASSOCIATE_CURRENT_RUN,
installer::kSetupHistogramAllocatorName));
// When metrics reporting is enabled, register the notification_helper
// and platform experience helper metrics files; otherwise delete any
// existing files in order to preserve user privacy.
if (!user_data_dir.empty()) {
base::FilePath notification_helper_metrics_upload_dir =
user_data_dir.AppendASCII(
notification_helper::kNotificationHelperHistogramAllocatorName);
base::FilePath platform_experience_helper_metrics_upload_dir =
user_data_dir.AppendASCII(
kPlatformExperienceHelperHistogramAllocatorName);
if (metrics_reporting_enabled) {
file_metrics_provider->RegisterSource(
metrics::FileMetricsProvider::Params(
notification_helper_metrics_upload_dir,
metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
metrics::FileMetricsProvider::ASSOCIATE_CURRENT_RUN,
notification_helper::kNotificationHelperHistogramAllocatorName));
file_metrics_provider->RegisterSource(
metrics::FileMetricsProvider::Params(
platform_experience_helper_metrics_upload_dir,
metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
metrics::FileMetricsProvider::ASSOCIATE_CURRENT_RUN,
kPlatformExperienceHelperHistogramAllocatorName));
} else {
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::GetDeletePathRecursivelyCallback(
std::move(notification_helper_metrics_upload_dir)));
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::GetDeletePathRecursivelyCallback(
std::move(platform_experience_helper_metrics_upload_dir)));
}
}
#endif
return file_metrics_provider;
}
ChromeMetricsServiceClient::IsProcessRunningFunction g_is_process_running =
nullptr;
bool IsProcessRunning(base::ProcessId pid) {
// Use any "override" method if one is set (for testing).
if (g_is_process_running) {
return g_is_process_running(pid);
}
#if BUILDFLAG(IS_WIN)
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (process) {
DWORD ret = WaitForSingleObject(process, 0);
CloseHandle(process);
if (ret == WAIT_TIMEOUT) {
return true;
}
}
#elif BUILDFLAG(IS_POSIX)
// Sending a signal value of 0 will cause error checking to be performed
// with no signal being sent.
if (kill(pid, 0) == 0 || errno != ESRCH) {
return true;
}
#elif BUILDFLAG(IS_FUCHSIA)
// TODO(crbug.com/40629149): Implement along with metrics support.
NOTIMPLEMENTED_LOG_ONCE();
#else
#error Unsupported OS. Might be okay to just return false.
#endif
return false;
}
// Client used by DemographicMetricsProvider to retrieve Profile information.
class ProfileClientImpl
: public metrics::DemographicMetricsProvider::ProfileClient {
public:
ProfileClientImpl() = default;
ProfileClientImpl(const ProfileClientImpl&) = delete;
ProfileClientImpl& operator=(const ProfileClientImpl&) = delete;
~ProfileClientImpl() override = default;
int GetNumberOfProfilesOnDisk() override {
return g_browser_process->profile_manager()->GetNumberOfProfiles();
}
PrefService* GetLocalState() override {
return g_browser_process->local_state();
}
PrefService* GetProfilePrefs() override {
Profile* profile = cached_metrics_profile_.GetMetricsProfile();
if (!profile) {
return nullptr;
}
return profile->GetPrefs();
}
syncer::SyncService* GetSyncService() override {
Profile* profile = cached_metrics_profile_.GetMetricsProfile();
if (!profile) {
return nullptr;
}
return SyncServiceFactory::GetForProfile(profile);
}
base::Time GetNetworkTime() const override {
base::Time time;
if (g_browser_process->network_time_tracker()->GetNetworkTime(&time,
nullptr) !=
network_time::NetworkTimeTracker::NETWORK_TIME_AVAILABLE) {
// Return null time to indicate that it could not get the network time. It
// is the responsibility of the client to have the strategy to deal with
// the absence of network time.
return base::Time();
}
return time;
}
private:
// Provides the same cached Profile each time.
metrics::CachedMetricsProfile cached_metrics_profile_;
};
std::unique_ptr<metrics::DemographicMetricsProvider>
MakeDemographicMetricsProvider(
metrics::MetricsLogUploader::MetricServiceType metrics_service_type) {
return std::make_unique<metrics::DemographicMetricsProvider>(
std::make_unique<ProfileClientImpl>(), metrics_service_type);
}
class ChromeComponentMetricsProviderDelegate
: public metrics::ComponentMetricsProviderDelegate {
public:
explicit ChromeComponentMetricsProviderDelegate(
component_updater::ComponentUpdateService* component_updater_service)
: component_updater_service_(component_updater_service) {}
~ChromeComponentMetricsProviderDelegate() override = default;
std::vector<component_updater::ComponentInfo> GetComponents() override {
return component_updater_service_->GetComponents();
}
private:
raw_ptr<component_updater::ComponentUpdateService> component_updater_service_;
};
#if BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(crbug.com/40214482): Remove this and use ChangeMetricsReportingState()
// once crash no longer depends on GoogleUpdateSettings and per-user is
// available outside of Ash.
void UpdateMetricsServicesForPerUser(bool enabled) {
// Set the local state pref because a lot of services read directly from this
// pref to obtain metrics consent.
//
// This is OK on Chrome OS because this pref is set on every startup with the
// device policy value. The previous user consent will get overwritten by
// the correct device policy value on startup.
//
// TODO(crbug.com/40822509): Once a proper API is established and services no
// longer read the pref value directly, this can be removed.
g_browser_process->local_state()->SetBoolean(
metrics::prefs::kMetricsReportingEnabled, enabled);
g_browser_process->GetMetricsServicesManager()->UpdateUploadPermissions(true);
}
#endif
} // namespace
ChromeMetricsServiceClient::ChromeMetricsServiceClient(
metrics::MetricsStateManager* state_manager,
variations::SyntheticTrialRegistry* synthetic_trial_registry)
: metrics_state_manager_(state_manager),
synthetic_trial_registry_(synthetic_trial_registry) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
incognito_observer_ = IncognitoObserver::Create(
base::BindRepeating(&ChromeMetricsServiceClient::UpdateRunningServices,
weak_ptr_factory_.GetWeakPtr()));
}
ChromeMetricsServiceClient::~ChromeMetricsServiceClient() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
// static
std::unique_ptr<ChromeMetricsServiceClient> ChromeMetricsServiceClient::Create(
metrics::MetricsStateManager* state_manager,
variations::SyntheticTrialRegistry* synthetic_trial_registry) {
// Perform two-phase initialization so that `client->metrics_service_` only
// receives pointers to fully constructed objects.
std::unique_ptr<ChromeMetricsServiceClient> client(
new ChromeMetricsServiceClient(state_manager, synthetic_trial_registry));
client->Initialize();
return client;
}
// static
void ChromeMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
ChromeBrowserMainExtraPartsMetrics::RegisterPrefs(registry);
metrics::MetricsService::RegisterPrefs(registry);
ukm::UkmService::RegisterPrefs(registry);
metrics::StabilityMetricsHelper::RegisterPrefs(registry);
prefs::RegisterPrivacyBudgetPrefs(registry);
RegisterFileMetricsPreferences(registry);
metrics::RegisterMetricsReportingStatePrefs(registry);
#if BUILDFLAG(IS_ANDROID)
ChromeAndroidMetricsProvider::RegisterPrefs(registry);
#endif // BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_CHROMEOS_ASH)
metrics::PerUserStateManagerChromeOS::RegisterPrefs(registry);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
BUILDFLAG(IS_MAC)
metrics::structured::StructuredMetricsService::RegisterPrefs(registry);
#if !BUILDFLAG(IS_CHROMEOS_ASH)
metrics::structured::ChromeStructuredMetricsRecorder::RegisterLocalState(
registry);
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH) || \
// BUILDFLAG(IS_MAC)
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
void ChromeMetricsServiceClient::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
metrics::PerUserStateManagerChromeOS::RegisterProfilePrefs(registry);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
variations::SyntheticTrialRegistry*
ChromeMetricsServiceClient::GetSyntheticTrialRegistry() {
return synthetic_trial_registry_.get();
}
metrics::MetricsService* ChromeMetricsServiceClient::GetMetricsService() {
return metrics_service_.get();
}
ukm::UkmService* ChromeMetricsServiceClient::GetUkmService() {
return ukm_service_.get();
}
IdentifiabilityStudyState*
ChromeMetricsServiceClient::GetIdentifiabilityStudyState() {
return identifiability_study_state_.get();
}
metrics::structured::StructuredMetricsService*
ChromeMetricsServiceClient::GetStructuredMetricsService() {
return structured_metrics_service_.get();
}
void ChromeMetricsServiceClient::SetMetricsClientId(
const std::string& client_id) {
crash_keys::SetMetricsClientIdFromGUID(client_id);
}
int32_t ChromeMetricsServiceClient::GetProduct() {
return metrics::ChromeUserMetricsExtension::CHROME;
}
std::string ChromeMetricsServiceClient::GetApplicationLocale() {
return g_browser_process->GetApplicationLocale();
}
const network_time::NetworkTimeTracker*
ChromeMetricsServiceClient::GetNetworkTimeTracker() {
return g_browser_process->network_time_tracker();
}
bool ChromeMetricsServiceClient::GetBrand(std::string* brand_code) {
return google_brand::GetBrand(brand_code);
}
metrics::SystemProfileProto::Channel ChromeMetricsServiceClient::GetChannel() {
return metrics::AsProtobufChannel(chrome::GetChannel());
}
bool ChromeMetricsServiceClient::IsExtendedStableChannel() {
return chrome::IsExtendedStableChannel();
}
std::string ChromeMetricsServiceClient::GetVersionString() {
return metrics::GetVersionString();
}
void ChromeMetricsServiceClient::OnEnvironmentUpdate(std::string* environment) {
// TODO(https://bugs.chromium.org/p/crashpad/issues/detail?id=135): call this
// on Mac when the Crashpad API supports it.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
// Register the environment with the crash reporter. Note that there is a
// window from startup to this point during which crash reports will not have
// an environment set.
g_crash_reporter.Get().OnEnvironmentUpdate(*environment);
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
}
void ChromeMetricsServiceClient::MergeSubprocessHistograms() {
// TODO(crbug.com/40213327): Move this to a shared place to not have to
// duplicate the code across different `MetricsServiceClient`s.
// Synchronously fetch subprocess histograms that live in shared memory.
base::StatisticsRecorder::ImportProvidedHistogramsSync();
// Asynchronously fetch subprocess histograms that do not live in shared
// memory (e.g., they were emitted before the shared memory was set up).
content::FetchHistogramsAsynchronously(
base::SingleThreadTaskRunner::GetCurrentDefault(),
/*callback=*/base::DoNothing(),
/*wait_time=*/base::Milliseconds(kMaxHistogramGatheringWaitDuration));
}
void ChromeMetricsServiceClient::CollectFinalMetricsForLog(
base::OnceClosure done_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
collect_final_metrics_done_callback_ = std::move(done_callback);
CollectFinalHistograms();
}
std::unique_ptr<metrics::MetricsLogUploader>
ChromeMetricsServiceClient::CreateUploader(
const GURL& server_url,
const GURL& insecure_server_url,
std::string_view mime_type,
metrics::MetricsLogUploader::MetricServiceType service_type,
const metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
return std::make_unique<metrics::NetMetricsLogUploader>(
g_browser_process->shared_url_loader_factory(), server_url,
insecure_server_url, mime_type, service_type, on_upload_complete);
}
base::TimeDelta ChromeMetricsServiceClient::GetStandardUploadInterval() {
return metrics::GetUploadInterval(metrics::ShouldUseCellularUploadInterval());
}
bool ChromeMetricsServiceClient::IsReportingPolicyManaged() {
return IsMetricsReportingPolicyManaged();
}
metrics::EnableMetricsDefault
ChromeMetricsServiceClient::GetMetricsReportingDefaultState() {
return metrics::GetMetricsReportingDefaultState(
g_browser_process->local_state());
}
void ChromeMetricsServiceClient::Initialize() {
PrefService* local_state = g_browser_process->local_state();
metrics_service_ = std::make_unique<metrics::MetricsService>(
metrics_state_manager_, this, local_state);
observers_active_ = RegisterObservers();
CreateStructuredMetricsService();
RegisterMetricsServiceProviders();
if (IsMetricsReportingForceEnabled() ||
base::FeatureList::IsEnabled(ukm::kUkmFeature)) {
identifiability_study_state_ =
std::make_unique<IdentifiabilityStudyState>(local_state);
uint64_t client_id = 0;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// Read metrics service client id from ash chrome if it's present.
client_id = chromeos::BrowserParamsProxy::Get()->UkmClientId();
#endif
ukm_service_ = std::make_unique<ukm::UkmService>(
local_state, this,
MakeDemographicMetricsProvider(
metrics::MetricsLogUploader::MetricServiceType::UKM),
client_id);
ukm_service_->SetIsWebstoreExtensionCallback(
base::BindRepeating(&IsWebstoreExtension));
ukm_service_->RegisterEventFilter(
std::make_unique<PrivacyBudgetUkmEntryFilter>(
identifiability_study_state_.get()));
RegisterUKMProviders();
}
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
BUILDFLAG(IS_CHROMEOS_ASH)
metrics::structured::Recorder::GetInstance()->SetUiTaskRunner(
base::SequencedTaskRunner::GetCurrentDefault());
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
AsyncInitSystemProfileProvider();
// TODO(tluk): Consider setting up the UserActivityDetector observation for
// all platforms once the detector is well supported on these other platforms.
user_activity_observation_.Observe(ui::UserActivityDetector::Get());
// Set is_demo_mode_ to true in ukm_consent_state_observer if the device is
// currently in Demo Mode.
SetIsDemoMode(ash::DemoSession::IsDeviceInDemoMode());
#endif
}
void ChromeMetricsServiceClient::RegisterMetricsServiceProviders() {
PrefService* local_state = g_browser_process->local_state();
// Gets access to persistent metrics shared by sub-processes.
CHECK(metrics::SubprocessMetricsProvider::GetInstance());
#if BUILDFLAG(ENABLE_EXTENSIONS)
metrics_service_->RegisterMetricsProvider(
std::make_unique<ExtensionsMetricsProvider>(metrics_state_manager_));
#endif
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::NetworkMetricsProvider>(
content::CreateNetworkConnectionTrackerAsyncGetter(),
std::make_unique<metrics::NetworkQualityEstimatorProviderImpl>()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<OmniboxMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::ContentStabilityMetricsProvider>(
local_state, std::make_unique<ChromeMetricsExtensionsHelper>()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::GPUMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::RenderingPerfMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::CPUMetricsProvider>());
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::MotherboardMetricsProvider>());
#endif
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::EntropyStateProvider>(local_state));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::ScreenInfoMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::FormFactorMetricsProvider>());
metrics_service_->RegisterMetricsProvider(CreateFileMetricsProvider(
metrics_state_manager_->IsMetricsReportingEnabled()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::DriveMetricsProvider>(
chrome::FILE_LOCAL_STATE));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::CallStackProfileMetricsProvider>());
int sample_rate;
// Only log the sample rate if it's defined.
if (ChromeMetricsServicesManagerClient::GetSamplingRatePerMille(
&sample_rate)) {
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::SamplingMetricsProvider>(sample_rate));
}
metrics_service_->RegisterMetricsProvider(
std::make_unique<translate::TranslateRankerMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::ComponentMetricsProvider>(
std::make_unique<ChromeComponentMetricsProviderDelegate>(
g_browser_process->component_updater())));
metrics_service_->RegisterMetricsProvider(
std::make_unique<tracing::ChromeBackgroundTracingMetricsProvider>(
reinterpret_cast<ChromeOSSystemProfileProvider*>(
cros_system_profile_provider_.get())));
metrics_service_->RegisterMetricsProvider(MakeDemographicMetricsProvider(
metrics::MetricsLogUploader::MetricServiceType::UMA));
// TODO(crbug.com/40765618): Add metrics registration for WebView, iOS and
// WebLayer.
metrics_service_->RegisterMetricsProvider(
std::make_unique<safe_browsing::SafeBrowsingMetricsProvider>());
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::BluetoothMetricsProvider>());
#endif
#if BUILDFLAG(IS_ANDROID)
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::AndroidMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<ChromeAndroidMetricsProvider>(local_state));
metrics_service_->RegisterMetricsProvider(
std::make_unique<PageLoadMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::GmsMetricsProvider>());
#else
metrics_service_->RegisterMetricsProvider(base::WrapUnique(
new performance_manager::MetricsProviderDesktop(local_state)));
#endif // BUILDFLAG(IS_ANDROID)
metrics_service_->RegisterMetricsProvider(
std::make_unique<performance_manager::MetricsProviderCommon>());
#if BUILDFLAG(IS_WIN)
metrics_service_->RegisterMetricsProvider(
std::make_unique<GoogleUpdateMetricsProviderWin>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<AntiVirusMetricsProvider>());
#endif // BUILDFLAG(IS_WIN)
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \
(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
metrics_service_->RegisterMetricsProvider(
std::make_unique<DesktopPlatformFeaturesMetricsProvider>());
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_LINUX) ||
// BUILDFLAG(IS_CHROMEOS_LACROS))
metrics_service_->RegisterMetricsProvider(
std::make_unique<FamilyLinkUserMetricsProvider>());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
metrics_service_->RegisterMetricsProvider(
std::make_unique<LacrosMetricsProvider>());
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
#if BUILDFLAG(IS_CHROMEOS_ASH)
metrics_service_->RegisterMetricsProvider(
std::make_unique<ChromeOSMetricsProvider>(
metrics::MetricsLogUploader::UMA,
reinterpret_cast<ChromeOSSystemProfileProvider*>(
cros_system_profile_provider_.get())));
metrics_service_->RegisterMetricsProvider(
std::make_unique<ChromeOSHistogramMetricsProvider>());
if (base::FeatureList::IsEnabled(::features::kUmaStorageDimensions)) {
metrics_service_->RegisterMetricsProvider(
std::make_unique<CrosHealthdMetricsProvider>());
}
// Record default UMA state as opt-out for all Chrome OS users, if not
// recorded yet.
if (metrics::GetMetricsReportingDefaultState(local_state) ==
metrics::EnableMetricsDefault::DEFAULT_UNKNOWN) {
metrics::RecordMetricsReportingDefaultState(
local_state, metrics::EnableMetricsDefault::OPT_OUT);
}
metrics_service_->RegisterMetricsProvider(
std::make_unique<ash::PrinterMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<AssistantServiceMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<AmbientModeMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<FamilyUserMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<ChromeOSFamilyLinkUserMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<UpdateEngineMetricsProvider>());
if (base::FeatureList::IsEnabled(
::features::kUserTypeByDeviceTypeMetricsProvider)) {
metrics_service_->RegisterMetricsProvider(
std::make_unique<UserTypeByDeviceTypeMetricsProvider>());
}
metrics_service_->RegisterMetricsProvider(
std::make_unique<KeyboardBacklightColorMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<PersonalizationAppThemeMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<ash::settings::OsSettingsMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<WallpaperMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<arc::VmmMetricsProvider>());
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if !BUILDFLAG(IS_CHROMEOS_ASH)
metrics_service_->RegisterMetricsProvider(
std::make_unique<ChromeSigninAndSyncStatusMetricsProvider>());
// ChromeOS uses ChromeOSMetricsProvider for accessibility metrics provider.
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::AccessibilityMetricsProvider>());
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
metrics_service_->RegisterMetricsProvider(
std::make_unique<syncer::DeviceCountMetricsProvider>(base::BindRepeating(
&DeviceInfoSyncServiceFactory::GetAllDeviceInfoTrackers)));
metrics_service_->RegisterMetricsProvider(
std::make_unique<syncer::PassphraseTypeMetricsProvider>(
base::BindRepeating(&SyncServiceFactory::GetAllSyncServices)));
metrics_service_->RegisterMetricsProvider(
std::make_unique<HttpsEngagementMetricsProvider>());
#if BUILDFLAG(IS_MAC)
metrics_service_->RegisterMetricsProvider(
std::make_unique<PowerMetricsProvider>());
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
metrics_service_->RegisterMetricsProvider(
metrics::CreateDesktopSessionMetricsProvider());
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_LINUX)
}
void ChromeMetricsServiceClient::RegisterUKMProviders() {
// Note: if you make changes here please also consider whether they should go
// in AndroidMetricsServiceClient::CreateUkmService().
ukm_service_->RegisterMetricsProvider(
std::make_unique<metrics::NetworkMetricsProvider>(
content::CreateNetworkConnectionTrackerAsyncGetter(),
std::make_unique<metrics::NetworkQualityEstimatorProviderImpl>()));
#if BUILDFLAG(IS_CHROMEOS_ASH)
ukm_service_->RegisterMetricsProvider(
std::make_unique<ChromeOSMetricsProvider>(
metrics::MetricsLogUploader::UKM,
reinterpret_cast<ChromeOSSystemProfileProvider*>(
cros_system_profile_provider_.get())));
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
ukm_service_->RegisterMetricsProvider(
std::make_unique<LacrosMetricsProvider>());
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
ukm_service_->RegisterMetricsProvider(
std::make_unique<metrics::GPUMetricsProvider>());
ukm_service_->RegisterMetricsProvider(
std::make_unique<metrics::CPUMetricsProvider>());
ukm_service_->RegisterMetricsProvider(
std::make_unique<metrics::ScreenInfoMetricsProvider>());
ukm_service_->RegisterMetricsProvider(
std::make_unique<metrics::FormFactorMetricsProvider>());
ukm_service_->RegisterMetricsProvider(
ukm::CreateFieldTrialsProviderForUkm(synthetic_trial_registry_.get()));
ukm_service_->RegisterMetricsProvider(
std::make_unique<PrivacyBudgetMetricsProvider>(
identifiability_study_state_.get()));
ukm_service_->RegisterMetricsProvider(
std::make_unique<metrics::ComponentMetricsProvider>(
std::make_unique<ChromeComponentMetricsProviderDelegate>(
g_browser_process->component_updater())));
}
void ChromeMetricsServiceClient::NotifyApplicationNotIdle() {
metrics_service_->OnApplicationNotIdle();
}
void ChromeMetricsServiceClient::CollectFinalHistograms() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Begin the multi-step process of collecting memory usage histograms:
// First spawn a task to collect the memory details; when that task is
// finished, it will call OnMemoryDetailCollectionDone. That will in turn
// call HistogramSynchronization to collect histograms from all renderers and
// then call OnHistogramSynchronizationDone to continue processing.
DCHECK(!waiting_for_collect_final_metrics_step_);
waiting_for_collect_final_metrics_step_ = true;
base::OnceClosure callback =
base::BindOnce(&ChromeMetricsServiceClient::OnMemoryDetailCollectionDone,
weak_ptr_factory_.GetWeakPtr());
auto details =
base::MakeRefCounted<MetricsMemoryDetails>(std::move(callback));
details->StartFetch();
}
void ChromeMetricsServiceClient::OnMemoryDetailCollectionDone() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This function should only be called as the callback from an ansynchronous
// step.
DCHECK(waiting_for_collect_final_metrics_step_);
// Create a callback_task for OnHistogramSynchronizationDone.
base::RepeatingClosure callback = base::BindRepeating(
&ChromeMetricsServiceClient::OnHistogramSynchronizationDone,
weak_ptr_factory_.GetWeakPtr());
base::TimeDelta timeout =
base::Milliseconds(kMaxHistogramGatheringWaitDuration);
DCHECK_EQ(num_async_histogram_fetches_in_progress_, 0);
// `callback` is used 2 times below.
num_async_histogram_fetches_in_progress_ = 2;
// Merge histograms from metrics providers into StatisticsRecorder.
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&base::StatisticsRecorder::ImportProvidedHistograms,
/*async=*/true, callback));
// Set up the callback task to call after we receive histograms from all
// child processes. `timeout` specifies how long to wait before absolutely
// calling us back on the task.
content::FetchHistogramsAsynchronously(
base::SingleThreadTaskRunner::GetCurrentDefault(), std::move(callback),
timeout);
}
void ChromeMetricsServiceClient::OnHistogramSynchronizationDone() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This function should only be called as the callback from an ansynchronous
// step.
DCHECK(waiting_for_collect_final_metrics_step_);
DCHECK_GT(num_async_histogram_fetches_in_progress_, 0);
// Check if all expected requests finished.
if (--num_async_histogram_fetches_in_progress_ > 0) {
return;
}
waiting_for_collect_final_metrics_step_ = false;
std::move(collect_final_metrics_done_callback_).Run();
}
bool ChromeMetricsServiceClient::RegisterObservers() {
omnibox_url_opened_subscription_ =
OmniboxEventGlobalTracker::GetInstance()->RegisterCallback(
base::BindRepeating(
&ChromeMetricsServiceClient::OnURLOpenedFromOmnibox,
base::Unretained(this)));
#if !BUILDFLAG(IS_ANDROID)
browser_activity_watcher_ = std::make_unique<BrowserActivityWatcher>(
base::BindRepeating(&metrics::MetricsService::OnApplicationNotIdle,
base::Unretained(metrics_service_.get())));
#endif
bool all_profiles_succeeded = true;
for (Profile* profile :
g_browser_process->profile_manager()->GetLoadedProfiles()) {
if (!RegisterForProfileEvents(profile)) {
all_profiles_succeeded = false;
}
}
profile_manager_observer_.Observe(g_browser_process->profile_manager());
synthetic_trial_observation_.Observe(synthetic_trial_registry_.get());
return all_profiles_succeeded;
}
bool ChromeMetricsServiceClient::RegisterForProfileEvents(Profile* profile) {
// Only Original Profiles are checked in this call, meaning Incognito and
// Guest Off the record status are not checked in this method for UKM consent.
// The equivalent check is done in this method
// `MetricsServicesManager::UpdateUkmService()`
DCHECK(!profile->IsOffTheRecord());
// Non-Regular Profiles consent information are not expected to be
// observed or checked, therefore they are whitelisted for the UKM
// validation that checks consent on all profiles.
// E.g System Profile consent should be always true.
if (!profiles::IsRegularUserProfile(profile)) {
return true;
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
// If the device is in Demo Mode, observe the sync service to enable UKM to
// collect app data and return true.
if (IsDeviceInDemoMode()) {
syncer::SyncService* sync = SyncServiceFactory::GetForProfile(profile);
if (!sync) {
return false;
}
StartObserving(sync, profile->GetPrefs());
return true;
}
#endif
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \
(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
// This creates the DesktopProfileSessionDurationsServices if it didn't exist
// already.
metrics::DesktopProfileSessionDurationsServiceFactory::GetForBrowserContext(
profile);
#endif
history::HistoryService* history_service =
HistoryServiceFactory::GetForProfile(profile,
ServiceAccessType::IMPLICIT_ACCESS);
if (!history_service) {
return false;
}
ObserveServiceForDeletions(history_service);
syncer::SyncService* sync = SyncServiceFactory::GetForProfile(profile);
if (!sync) {
return false;
}
StartObserving(sync, profile->GetPrefs());
return true;
}
void ChromeMetricsServiceClient::OnProfileAdded(Profile* profile) {
bool success = RegisterForProfileEvents(profile);
// On failure, set `observers_active_` to false which will
// disable UKM reporting via UpdateRunningServices().
if (!success && observers_active_) {
observers_active_ = false;
UpdateRunningServices();
}
}
void ChromeMetricsServiceClient::OnProfileManagerDestroying() {
profile_manager_observer_.Reset();
}
void ChromeMetricsServiceClient::OnUserActivity(const ui::Event* event) {
NotifyApplicationNotIdle();
}
void ChromeMetricsServiceClient::LoadingStateChanged(bool /*is_loading*/) {
NotifyApplicationNotIdle();
}
void ChromeMetricsServiceClient::OnURLOpenedFromOmnibox(OmniboxLog* log) {
NotifyApplicationNotIdle();
}
bool ChromeMetricsServiceClient::IsOnCellularConnection() {
return metrics::ShouldUseCellularUploadInterval();
}
void ChromeMetricsServiceClient::OnHistoryDeleted() {
if (ukm_service_) {
ukm_service_->Purge();
}
}
void ChromeMetricsServiceClient::OnUkmAllowedStateChanged(
bool total_purge,
ukm::UkmConsentState previous_consent_state) {
if (!ukm_service_) {
return;
}
const ukm::UkmConsentState consent_state = GetUkmConsentState();
// Manages purging of events and sources.
if (total_purge) {
ukm_service_->Purge();
ukm_service_->ResetClientState(ukm::ResetReason::kOnUkmAllowedStateChanged);
} else {
// Purge recording if required consent has been revoked.
if (!consent_state.Has(ukm::MSBB)) {
ukm_service_->PurgeMsbbData();
}
if (!consent_state.Has(ukm::EXTENSIONS)) {
ukm_service_->PurgeExtensionsData();
}
if (!consent_state.Has(ukm::APPS)) {
ukm_service_->PurgeAppsData();
}
// If MSBB or App-sync consent changed from on to off then, the client id,
// or client state, must be reset. When not ChromeOS Ash, function
// will be a no-op.
//
// On non-ChromeOS platforms, client reset is handled above because
// |total_purge| will be true. MSBB is used to determine if UKM is enabled
// or disabled. When the consent is revoked UkmService will be disabled,
// triggering |total_purge| to be true. At which point the client state will
// be reset.
//
// On ChromeOS, disabling MSBB or App-Sync will not trigger a total purge.
// Resetting the client state has to be handled specifically for this case.
ResetClientStateWhenMsbbOrAppConsentIsRevoked(previous_consent_state);
}
// Notify the recording service of changed metrics consent.
ukm_service_->UpdateRecording(consent_state);
// Broadcast UKM consent state change.
ukm_service_->OnUkmAllowedStateChanged(consent_state);
// Signal service manager to enable/disable UKM based on new states.
UpdateRunningServices();
}
void ChromeMetricsServiceClient::OnRenderProcessHostCreated(
content::RenderProcessHost* host) {
if (!scoped_observations_.IsObservingSource(host)) {
scoped_observations_.AddObservation(host);
}
}
void ChromeMetricsServiceClient::RenderProcessExited(
content::RenderProcessHost* host,
const content::ChildProcessTerminationInfo& info) {
NotifyApplicationNotIdle();
}
void ChromeMetricsServiceClient::RenderProcessHostDestroyed(
content::RenderProcessHost* host) {
scoped_observations_.RemoveObservation(host);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
void ChromeMetricsServiceClient::AsyncInitSystemProfileProvider() {
DCHECK(cros_system_profile_provider_);
cros_system_profile_provider_->AsyncInit(base::BindOnce([]() {
// Structured metrics needs to know when the SystemProfile is
// available since events should have SystemProfile populated.
// Notify structured metrics recorder that SystemProfile is available to
// start sending events.
metrics::structured::Recorder::GetInstance()->OnSystemProfileInitialized();
}));
}
#endif
// static
bool ChromeMetricsServiceClient::IsWebstoreExtension(std::string_view id) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
// Only acceptable if at least one profile knows the extension and all
// profiles that know the extension say it was from the web-store.
bool matched = false;
ProfileManager* profile_manager = g_browser_process->profile_manager();
DCHECK(profile_manager);
auto profiles = profile_manager->GetLoadedProfiles();
for (Profile* profile : profiles) {
DCHECK(profile);
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile);
if (!registry) {
continue;
}
const extensions::Extension* extension =
registry->enabled_extensions().GetByID(std::string(id));
if (!extension) {
continue;
}
if (!extension->from_webstore()) {
return false;
}
matched = true;
}
return matched;
#else
return false;
#endif
}
// static
metrics::FileMetricsProvider::FilterAction
ChromeMetricsServiceClient::FilterBrowserMetricsFiles(
const base::FilePath& path) {
base::ProcessId pid;
if (!base::GlobalHistogramAllocator::ParseFilePath(path, nullptr, nullptr,
&pid)) {
return metrics::FileMetricsProvider::FILTER_PROCESS_FILE;
}
if (pid == base::GetCurrentProcId()) {
return metrics::FileMetricsProvider::FILTER_ACTIVE_THIS_PID;
}
if (IsProcessRunning(pid)) {
return metrics::FileMetricsProvider::FILTER_TRY_LATER;
}
return metrics::FileMetricsProvider::FILTER_PROCESS_FILE;
}
// static
void ChromeMetricsServiceClient::SetIsProcessRunningForTesting(
ChromeMetricsServiceClient::IsProcessRunningFunction func) {
g_is_process_running = func;
}
bool ChromeMetricsServiceClient::IsUkmAllowedForAllProfiles() {
return UkmConsentStateObserver::IsUkmAllowedForAllProfiles();
}
bool g_observer_registration_failed = false;
void ChromeMetricsServiceClient::SetNotificationListenerSetupFailedForTesting(
bool simulate_failure) {
g_observer_registration_failed = simulate_failure;
}
bool ChromeMetricsServiceClient::
AreNotificationListenersEnabledOnAllProfiles() {
// For testing
if (g_observer_registration_failed) {
return false;
}
return observers_active_;
}
std::string ChromeMetricsServiceClient::GetAppPackageNameIfLoggable() {
return metrics::GetAppPackageName();
}
std::string ChromeMetricsServiceClient::GetUploadSigningKey() {
std::string decoded_key;
base::Base64Decode(google_apis::GetMetricsKey(), &decoded_key);
return decoded_key;
}
bool ChromeMetricsServiceClient::ShouldResetClientIdsOnClonedInstall() {
return metrics_service_->ShouldResetClientIdsOnClonedInstall();
}
base::CallbackListSubscription
ChromeMetricsServiceClient::AddOnClonedInstallDetectedCallback(
base::OnceClosure callback) {
return metrics_state_manager_->AddOnClonedInstallDetectedCallback(
std::move(callback));
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
bool ChromeMetricsServiceClient::ShouldUploadMetricsForUserId(
const uint64_t user_id) {
// Metrics logs with user ids should be stored in a user cryptohome so this
// function should only be called after a user logins.
// |per_user_state_manager_| is initialized before a user can login.
DCHECK(per_user_state_manager_);
// This function should only be called if reporting is enabled.
DCHECK(ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled());
auto current_user_id = per_user_state_manager_->GetCurrentUserId();
// Do not upload logs that are missing |user_id| during this session.
if (!current_user_id.has_value()) {
return false;
}
// If |user_id| is different from the currently logged in user, log
// associated with different |user_id| should not be uploaded. This can
// happen if a user goes from enable->disable->enable state as user ID is
// reset going from enable->disable state.
//
// The log will be dropped since it may contain data collected during a
// point in which metrics reporting consent was disabled.
return user_id == metrics::MetricsLog::Hash(current_user_id.value());
}
void ChromeMetricsServiceClient::UpdateCurrentUserMetricsConsent(
bool user_metrics_consent) {
DCHECK(per_user_state_manager_);
per_user_state_manager_->SetCurrentUserMetricsConsent(user_metrics_consent);
}
void ChromeMetricsServiceClient::InitPerUserMetrics() {
per_user_state_manager_ =
std::make_unique<metrics::PerUserStateManagerChromeOS>(
this, g_browser_process->local_state());
per_user_consent_change_subscription_ = per_user_state_manager_->AddObserver(
base::BindRepeating(&UpdateMetricsServicesForPerUser));
}
std::optional<bool> ChromeMetricsServiceClient::GetCurrentUserMetricsConsent()
const {
if (per_user_state_manager_) {
return per_user_state_manager_
->GetCurrentUserReportingConsentIfApplicable();
}
return std::nullopt;
}
std::optional<std::string> ChromeMetricsServiceClient::GetCurrentUserId()
const {
if (per_user_state_manager_) {
return per_user_state_manager_->GetCurrentUserId();
}
return std::nullopt;
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
void ChromeMetricsServiceClient::ResetClientStateWhenMsbbOrAppConsentIsRevoked(
ukm::UkmConsentState previous_consent_state) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
const auto ukm_consent_state = GetUkmConsentState();
// True if MSBB consent change from on to off, False otherwise.
const bool msbb_revoked = previous_consent_state.Has(ukm::MSBB) &&
!ukm_consent_state.Has(ukm::MSBB);
// True if APPS consent change from on to off, False otherwise.
const bool apps_revoked = previous_consent_state.Has(ukm::APPS) &&
!ukm_consent_state.Has(ukm::APPS);
// If either condition is true, then reset client state.
if (msbb_revoked || apps_revoked) {
ukm_service_->ResetClientState(ukm::ResetReason::kOnUkmAllowedStateChanged);
}
#endif
}
void ChromeMetricsServiceClient::CreateStructuredMetricsService() {
PrefService* local_state = g_browser_process->local_state();
std::unique_ptr<metrics::structured::StructuredMetricsRecorder> recorder;
#if BUILDFLAG(IS_CHROMEOS_ASH)
cros_system_profile_provider_ =
std::make_unique<ChromeOSSystemProfileProvider>();
recorder =
std::make_unique<metrics::structured::AshStructuredMetricsRecorder>(
cros_system_profile_provider_.get());
#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC)
// Make sure that Structured Metrics recording delegates have been created
// before the service is created. This is handled in other places for ChromeOS
// and Lacros but isn't needed for the other platforms. So here is fine.
metrics::structured::ChromeStructuredMetricsDelegate::Get()->Initialize();
if (base::FeatureList::IsEnabled(::features::kChromeStructuredMetrics)) {
recorder =
std::make_unique<metrics::structured::ChromeStructuredMetricsRecorder>(
local_state);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Only create the Structured Metrics Service if there is a recorder. It will
// not be created on Windows, Mac, and Linux if the kChromeStructuredMetrics
// feature is disabled. It will always be created on ChromeOS and Lacros.
if (recorder) {
structured_metrics_service_ =
std::make_unique<metrics::structured::StructuredMetricsService>(
this, local_state, std::move(recorder));
}
}