// Copyright 2020 The Chromium Authors
// 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 <jni.h>
#include <cstdint>
#include <string>
#include <string_view>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/barrier_closure.h"
#include "base/base_paths_android.h"
#include "base/files/file_path.h"
#include "base/hash/hash.h"
#include "base/i18n/rtl.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/statistics_recorder.h"
#include "base/path_service.h"
#include "base/process/process_handle.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "components/embedder_support/android/metrics/android_metrics_log_uploader.h"
#include "components/metrics/android_metrics_provider.h"
#include "components/metrics/call_stacks/call_stack_profile_metrics_provider.h"
#include "components/metrics/content/accessibility_metrics_provider.h"
#include "components/metrics/content/content_stability_metrics_provider.h"
#include "components/metrics/content/extensions_helper.h"
#include "components/metrics/content/gpu_metrics_provider.h"
#include "components/metrics/content/metrics_services_web_contents_observer.h"
#include "components/metrics/content/subprocess_metrics_provider.h"
#include "components/metrics/cpu_metrics_provider.h"
#include "components/metrics/drive_metrics_provider.h"
#include "components/metrics/entropy_state_provider.h"
#include "components/metrics/file_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/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/ui/form_factor_metrics_provider.h"
#include "components/metrics/ui/screen_info_metrics_provider.h"
#include "components/metrics/version_utils.h"
#include "components/prefs/pref_service.h"
#include "components/ukm/field_trials_provider_helper.h"
#include "components/ukm/ukm_service.h"
#include "content/public/browser/histogram_fetcher.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/web_contents.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/embedder_support/android/metrics/jni/AndroidMetricsServiceClient_jni.h"
namespace metrics {
using InstallerPackageType = AndroidMetricsServiceClient::InstallerPackageType;
namespace {
// This specifies the amount of time to wait for all renderers to send their
// data.
const int kMaxHistogramGatheringWaitDuration = 60000; // 60 seconds.
const int kMaxHistogramStorageKiB = 100 << 10; // 100 MiB
// Divides the spectrum of uint32_t values into 1000 ~equal-sized buckets (range
// [0, 999] inclusive), and returns which bucket |value| falls into. Ex. given
// 2^30, this would return 250, because 25% of uint32_t values fall below the
// given value.
int UintToPerMille(uint32_t value) {
// We need to divide by UINT32_MAX+1 (2^32), otherwise the fraction could
// evaluate to 1000.
uint64_t divisor = 1llu << 32;
uint64_t value_per_mille = static_cast<uint64_t>(value) * 1000llu / divisor;
DCHECK_GE(value_per_mille, 0llu);
DCHECK_LE(value_per_mille, 999llu);
return static_cast<int>(value_per_mille);
}
bool IsProcessRunning(base::ProcessId pid) {
// Sending a signal value of 0 will cause error checking to be performed
// with no signal being sent.
return (kill(pid, 0) == 0 || errno != ESRCH);
}
metrics::FileMetricsProvider::FilterAction 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;
}
bool IsSamplesCounterEnabled() {
return base::GetFieldTrialParamByFeatureAsBool(
kPersistentHistogramsFeature, "prev_run_metrics_count_only", false);
}
// TODO(crbug.com/40158523): Unify this implementation with the one in
// ChromeMetricsServiceClient.
std::unique_ptr<metrics::FileMetricsProvider> CreateFileMetricsProvider(
PrefService* pref_service,
bool metrics_reporting_enabled) {
using metrics::FileMetricsProvider;
// Create an object to monitor files of metrics and include them in reports.
std::unique_ptr<FileMetricsProvider> file_metrics_provider =
std::make_unique<FileMetricsProvider>(pref_service);
base::FilePath user_data_dir;
base::PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir);
FileMetricsProvider::Params browser_metrics_params(
user_data_dir.AppendASCII(kBrowserMetricsName),
FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
IsSamplesCounterEnabled()
? FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_SAMPLES_COUNTER
: FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE,
kBrowserMetricsName);
browser_metrics_params.max_dir_kib = kMaxHistogramStorageKiB;
browser_metrics_params.filter =
base::BindRepeating(FilterBrowserMetricsFiles);
file_metrics_provider->RegisterSource(browser_metrics_params,
metrics_reporting_enabled);
// Register the Crashpad metrics files:
// 1. Data from the previous run if crashpad_handler didn't exit cleanly.
base::FilePath crashpad_metrics_file =
base::GlobalHistogramAllocator::ConstructFilePath(
user_data_dir, kCrashpadHistogramAllocatorName);
file_metrics_provider->RegisterSource(
FileMetricsProvider::Params(
crashpad_metrics_file,
FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
kCrashpadHistogramAllocatorName),
metrics_reporting_enabled);
// 2. Data from the current run. Note: "Active" files don't set "prefs_key"
// because they update the file itself.
base::FilePath crashpad_active_path =
base::GlobalHistogramAllocator::ConstructFilePathForActiveFile(
user_data_dir, kCrashpadHistogramAllocatorName);
file_metrics_provider->RegisterSource(
FileMetricsProvider::Params(
crashpad_active_path,
FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
FileMetricsProvider::ASSOCIATE_CURRENT_RUN),
metrics_reporting_enabled);
return file_metrics_provider;
}
base::OnceClosure CreateChainedClosure(base::OnceClosure cb1,
base::OnceClosure cb2) {
return base::BindOnce(
[](base::OnceClosure cb1, base::OnceClosure cb2) {
if (cb1) {
std::move(cb1).Run();
}
if (cb2) {
std::move(cb2).Run();
}
},
std::move(cb1), std::move(cb2));
}
} // namespace
// Needs to be kept in sync with the writer in
// third_party/crashpad/crashpad/handler/handler_main.cc.
const char kCrashpadHistogramAllocatorName[] = "CrashpadMetrics";
AndroidMetricsServiceClient::AndroidMetricsServiceClient() = default;
AndroidMetricsServiceClient::~AndroidMetricsServiceClient() = default;
// static
void AndroidMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
metrics::MetricsService::RegisterPrefs(registry);
metrics::FileMetricsProvider::RegisterSourcePrefs(registry,
kBrowserMetricsName);
metrics::FileMetricsProvider::RegisterSourcePrefs(
registry, kCrashpadHistogramAllocatorName);
metrics::FileMetricsProvider::RegisterPrefs(registry);
metrics::StabilityMetricsHelper::RegisterPrefs(registry);
ukm::UkmService::RegisterPrefs(registry);
}
void AndroidMetricsServiceClient::Initialize(PrefService* pref_service) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!init_finished_);
pref_service_ = pref_service;
metrics_state_manager_ = MetricsStateManager::Create(
pref_service_, this,
// Pass an empty file path since the path is for Extended Variations Safe
// Mode, which is N/A to Android embedders.
std::wstring(), base::FilePath(), StartupVisibility::kUnknown,
{
// The low entropy provider is used instead of the default provider
// because the default provider needs to know if UMA is enabled and
// querying GMS to determine whether UMA is enabled is slow.
// The low entropy provider has fewer unique experiment combinations,
// which is better for privacy, but can have crosstalk issues between
// experiments.
.default_entropy_provider_type = metrics::EntropyProviderType::kLow,
.force_benchmarking_mode =
base::CommandLine::ForCurrentProcess()->HasSwitch(
cc::switches::kEnableGpuBenchmarking),
});
metrics_state_manager_->InstantiateFieldTrialList();
init_finished_ = true;
synthetic_trial_registry_ =
std::make_unique<variations::SyntheticTrialRegistry>();
synthetic_trial_observation_.Observe(synthetic_trial_registry_.get());
// Create the MetricsService immediately so that other code can make use of
// it. Chrome always creates the MetricsService as well.
metrics_service_ = std::make_unique<MetricsService>(
metrics_state_manager_.get(), this, pref_service_);
// Registration of providers has to wait until consent is determined. To
// do otherwise means the providers would always be configured with reporting
// disabled (because when this is called in production consent hasn't been
// determined). If consent has not been determined, this does nothing.
MaybeStartMetrics();
}
// TODO:(crbug.com/1148351) Make the initialization consistent with Chrome.
void AndroidMetricsServiceClient::MaybeStartMetrics() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!IsConsentDetermined())
return;
#if DCHECK_IS_ON()
// This function should be called only once after consent has been determined.
DCHECK(!did_start_metrics_with_consent_);
did_start_metrics_with_consent_ = true;
#endif
// 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 (app_consent_ && user_consent_or_flag) {
did_start_metrics_ = true;
// Make GetSampleBucketValue() work properly.
metrics_state_manager_->ForceClientIdCreation();
is_client_id_forced_ = true;
RegisterMetricsProvidersAndInitState();
// 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.
OnMetricsStart();
if (IsReportingEnabled()) {
// We assume the embedder has no shutdown sequence, so there's no need
// for a matching Stop() call.
metrics_service_->Start();
}
CreateUkmService();
} else {
// Even though reporting is not enabled, CreateFileMetricsProvider() is
// called. This ensures on disk state is removed.
metrics_service_->RegisterMetricsProvider(CreateFileMetricsProvider(
pref_service_, /* metrics_reporting_enabled */ false));
OnMetricsNotStarted();
pref_service_->ClearPref(prefs::kMetricsClientID);
pref_service_->ClearPref(prefs::kMetricsProvisionalClientID);
pref_service_->ClearPref(prefs::kMetricsLogRecordId);
}
}
void AndroidMetricsServiceClient::RegisterMetricsProvidersAndInitState() {
CHECK(metrics::SubprocessMetricsProvider::GetInstance());
metrics_service_->RegisterMetricsProvider(
std::make_unique<NetworkMetricsProvider>(
content::CreateNetworkConnectionTrackerAsyncGetter()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<CPUMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<EntropyStateProvider>(pref_service_));
metrics_service_->RegisterMetricsProvider(
std::make_unique<ScreenInfoMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::FormFactorMetricsProvider>());
metrics_service_->RegisterMetricsProvider(CreateFileMetricsProvider(
pref_service_, metrics_state_manager_->IsMetricsReportingEnabled()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<CallStackProfileMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::AndroidMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::DriveMetricsProvider>(
base::DIR_ANDROID_APP_DATA));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::GPUMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::SamplingMetricsProvider>(
GetSampleRatePerMille()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<AccessibilityMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<ContentStabilityMetricsProvider>(
pref_service(), /*extensions_helper=*/nullptr));
RegisterAdditionalMetricsProviders(metrics_service_.get());
// The file metrics provider performs IO.
base::ScopedAllowBlocking allow_io;
metrics_service_->InitializeMetricsRecordingState();
}
void AndroidMetricsServiceClient::CreateUkmService() {
ukm_service_ = std::make_unique<ukm::UkmService>(
pref_service_, this, /*demographics_provider=*/nullptr);
ukm_service_->RegisterMetricsProvider(
std::make_unique<metrics::NetworkMetricsProvider>(
content::CreateNetworkConnectionTrackerAsyncGetter()));
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()));
UpdateUkmService();
}
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;
}
void AndroidMetricsServiceClient::UpdateUkm(bool must_purge) {
if (!ukm_service_)
return;
if (must_purge) {
ukm_service_->Purge();
ukm_service_->ResetClientState(ukm::ResetReason::kOnUkmAllowedStateChanged);
}
UpdateUkmService();
}
void AndroidMetricsServiceClient::UpdateUkmService() {
if (!ukm_service_)
return;
bool consent_or_flag = IsConsentGiven() || IsMetricsReportingForceEnabled();
bool allowed = IsUkmAllowedForAllProfiles();
bool is_incognito = IsOffTheRecordSessionActive();
if (consent_or_flag && allowed && !is_incognito) {
ukm_service_->EnableRecording();
ukm_service_->EnableReporting();
} else {
ukm_service_->DisableRecording();
ukm_service_->DisableReporting();
}
}
bool AndroidMetricsServiceClient::IsConsentDetermined() const {
return init_finished_ && set_consent_finished_;
}
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() && IsInSample());
}
MetricsService* AndroidMetricsServiceClient::GetMetricsServiceIfStarted() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return did_start_metrics_ ? metrics_service_.get() : nullptr;
}
variations::SyntheticTrialRegistry*
AndroidMetricsServiceClient::GetSyntheticTrialRegistry() {
return synthetic_trial_registry_.get();
}
MetricsService* AndroidMetricsServiceClient::GetMetricsService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This will be null if initialization hasn't finished.
return metrics_service_.get();
}
ukm::UkmService* AndroidMetricsServiceClient::GetUkmService() {
return ukm_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();
}
const network_time::NetworkTimeTracker*
AndroidMetricsServiceClient::GetNetworkTimeTracker() {
return nullptr;
}
bool AndroidMetricsServiceClient::GetBrand(std::string* brand_code) {
// AndroidMetricsServiceClients don't use brand codes.
return false;
}
SystemProfileProto::Channel AndroidMetricsServiceClient::GetChannel() {
return AsProtobufChannel(version_info::android::GetChannel());
}
bool AndroidMetricsServiceClient::IsExtendedStableChannel() {
return false; // Not supported on AndroidMetricsServiceClients.
}
std::string AndroidMetricsServiceClient::GetVersionString() {
return metrics::GetVersionString();
}
void AndroidMetricsServiceClient::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 AndroidMetricsServiceClient::CollectFinalMetricsForLog(
base::OnceClosure done_callback) {
auto barrier_closure =
base::BarrierClosure(/*num_closures=*/2, std::move(done_callback));
// Merge histograms from metrics providers into StatisticsRecorder.
base::StatisticsRecorder::ImportProvidedHistograms(
/*async=*/true, /*done_callback=*/barrier_closure);
base::TimeDelta timeout =
base::Milliseconds(kMaxHistogramGatheringWaitDuration);
// 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(),
CreateChainedClosure(barrier_closure,
on_final_metrics_collected_listener_),
timeout);
if (collect_final_metrics_for_log_closure_)
std::move(collect_final_metrics_for_log_closure_).Run();
}
std::unique_ptr<MetricsLogUploader> AndroidMetricsServiceClient::CreateUploader(
const GURL& server_url,
const GURL& insecure_server_url,
std::string_view mime_type,
MetricsLogUploader::MetricServiceType service_type,
const MetricsLogUploader::UploadCallback& on_upload_complete) {
if (service_type == metrics::MetricsLogUploader::UKM) {
// Clearcut doesn't handle UKMs.
auto url_loader_factory = GetURLLoaderFactory();
DCHECK(url_loader_factory);
return std::make_unique<metrics::NetMetricsLogUploader>(
url_loader_factory, server_url, insecure_server_url, mime_type,
service_type, 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::IsUkmAllowedForAllProfiles() {
return false;
}
bool AndroidMetricsServiceClient::ShouldStartUpFastForTesting() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return fast_startup_for_testing_;
}
void AndroidMetricsServiceClient::OnRenderProcessHostCreated(
content::RenderProcessHost* host) {
if (!host_observation_.IsObservingSource(host)) {
host_observation_.AddObservation(host);
}
}
void AndroidMetricsServiceClient::RenderProcessExited(
content::RenderProcessHost* host,
const content::ChildProcessTerminationInfo& info) {
host_observation_.RemoveObservation(host);
if (did_start_metrics_) {
metrics_service_->OnApplicationNotIdle();
}
}
void AndroidMetricsServiceClient::OnWebContentsCreated(
content::WebContents* web_contents) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
metrics::MetricsServicesWebContentsObserver::CreateForWebContents(
web_contents,
/*OnDidStartLoadingCb=*/
base::BindRepeating(&AndroidMetricsServiceClient::OnDidStartLoading,
weak_ptr_factory_.GetWeakPtr()),
/*OnDidStopLoadingCb=*/
base::BindRepeating(&AndroidMetricsServiceClient::OnApplicationNotIdle,
weak_ptr_factory_.GetWeakPtr()),
/*OnRendererUnresponsiveCb=*/
base::BindRepeating(&AndroidMetricsServiceClient::OnApplicationNotIdle,
weak_ptr_factory_.GetWeakPtr()));
}
void AndroidMetricsServiceClient::SetCollectFinalMetricsForLogClosureForTesting(
base::OnceClosure closure) {
collect_final_metrics_for_log_closure_ = std::move(closure);
}
void AndroidMetricsServiceClient::SetOnFinalMetricsCollectedListenerForTesting(
base::RepeatingClosure listener) {
on_final_metrics_collected_listener_ = std::move(listener);
}
int AndroidMetricsServiceClient::GetSampleBucketValue() const {
DCHECK(is_client_id_forced_);
return UintToPerMille(base::PersistentHash(metrics_service_->GetClientId()));
}
bool AndroidMetricsServiceClient::IsInSample() const {
// Called in MaybeStartMetrics(), after |metrics_service_| is created.
// NOTE IsInSample and ShouldRecordPackageName deliberately use the same hash
// to guarantee we never exceed 10% of total, opted-in clients for
// PackageNames.
return GetSampleBucketValue() < GetSampleRatePerMille();
}
InstallerPackageType AndroidMetricsServiceClient::GetInstallerPackageType() {
// Check with Java side, to see if it's OK to log the package name for this
// type of app (see Java side for the specific requirements).
JNIEnv* env = base::android::AttachCurrentThread();
int type = Java_AndroidMetricsServiceClient_getInstallerPackageType(env);
return static_cast<InstallerPackageType>(type);
}
bool AndroidMetricsServiceClient::CanRecordPackageNameForAppType() {
return GetInstallerPackageType() != InstallerPackageType::OTHER;
}
bool AndroidMetricsServiceClient::ShouldRecordPackageName() {
return GetSampleBucketValue() < GetPackageNameLimitRatePerMille();
}
void AndroidMetricsServiceClient::RegisterAdditionalMetricsProviders(
MetricsService* service) {}
std::string AndroidMetricsServiceClient::GetAppPackageNameIfLoggable() {
if (ShouldRecordPackageName() && CanRecordPackageNameForAppType())
return GetAppPackageName();
return std::string();
}
std::string AndroidMetricsServiceClient::GetAppPackageName() {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jstring> j_app_name =
Java_AndroidMetricsServiceClient_getAppPackageName(env);
if (j_app_name)
return base::android::ConvertJavaStringToUTF8(env, j_app_name);
return std::string();
}
bool AndroidMetricsServiceClient::IsOffTheRecordSessionActive() {
return false;
}
scoped_refptr<network::SharedURLLoaderFactory>
AndroidMetricsServiceClient::GetURLLoaderFactory() {
return nullptr;
}
void AndroidMetricsServiceClient::OnApplicationNotIdle() {
auto* metrics_service = GetMetricsServiceIfStarted();
if (!metrics_service) {
return;
}
metrics_service->OnApplicationNotIdle();
}
void AndroidMetricsServiceClient::OnDidStartLoading() {
OnApplicationNotIdle();
auto* metrics_service = GetMetricsService();
if (!metrics_service) {
return;
}
metrics_service->OnPageLoadStarted();
}
} // namespace metrics