blob: 9b39c7de928d851b917a8b8ebb8a1e1a15f55535 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/metrics/aw_metrics_service_client.h"
#include <jni.h>
#include <cstdint>
#include <string>
#include <string_view>
#include "android_webview/browser/metrics/android_metrics_log_uploader.h"
#include "android_webview/browser/metrics/android_metrics_provider.h"
#include "android_webview/common/aw_features.h"
#include "base/android/callback_android.h"
#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 "base/time/time.h"
#include "build/build_config.h"
#include "cc/base/switches.h"
#include "components/metrics/android_metrics_provider.h"
#include "components/metrics/call_stacks/call_stack_profile_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/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/version_info/android/channel_getter.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 "android_webview/browser_jni_headers/AwMetricsServiceClient_jni.h"
namespace android_webview {
using InstallerPackageType = AwMetricsServiceClient::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.
// `is_fre` will always be false for Android WV because the concept of First
// Run Experience is not applicable.
std::unique_ptr<FileMetricsProvider> file_metrics_provider =
std::make_unique<FileMetricsProvider>(pref_service,
/*is_fre=*/false);
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);
// WebView never configured Crashpad to actually create these metrics files,
// so it's not useful to try to upload them.
// TODO(crbug.com/440359722): decide if we want these metrics and either
// configure Crashpad appropriately or clean up this code.
// 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));
}
// IMPORTANT: DO NOT CHANGE sample rates without first ensuring the Chrome
// Metrics team has the appropriate backend bandwidth and storage.
// Sample at 2%, based on storage concerns. We sample at a different rate than
// Chrome because we have more metrics "clients" (each app on the device counts
// as a separate client).
const int kStableUnfilteredSampledInRatePerMille = 20;
// Sample non-stable channels at 99%, to boost volume for pre-stable
// experiments. We choose 99% instead of 100% for consistency with Chrome and to
// exercise the out-of-sample code path.
const int kBetaDevCanaryUnfilteredSampledInRatePerMille = 990;
AwMetricsServiceClient* g_aw_metrics_service_client = nullptr;
} // namespace
// Needs to be kept in sync with the writer in
// third_party/crashpad/crashpad/handler/handler_main.cc.
const char kCrashpadHistogramAllocatorName[] = "CrashpadMetrics";
AwMetricsServiceClient::Delegate::Delegate() = default;
AwMetricsServiceClient::Delegate::~Delegate() = default;
// static
AwMetricsServiceClient* AwMetricsServiceClient::GetInstance() {
DCHECK(g_aw_metrics_service_client);
DCHECK_CALLED_ON_VALID_SEQUENCE(
g_aw_metrics_service_client->sequence_checker_);
return g_aw_metrics_service_client;
}
// static
void AwMetricsServiceClient::SetInstance(
std::unique_ptr<AwMetricsServiceClient> aw_metrics_service_client) {
DCHECK(!g_aw_metrics_service_client);
DCHECK(aw_metrics_service_client);
g_aw_metrics_service_client = aw_metrics_service_client.release();
DCHECK_CALLED_ON_VALID_SEQUENCE(
g_aw_metrics_service_client->sequence_checker_);
}
AwMetricsServiceClient::AwMetricsServiceClient(
std::unique_ptr<Delegate> delegate)
: time_created_(base::Time::Now()), delegate_(std::move(delegate)) {}
AwMetricsServiceClient::~AwMetricsServiceClient() = default;
void AwMetricsServiceClient::Initialize(PrefService* pref_service) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!init_finished_);
pref_service_ = pref_service;
metrics_state_manager_ = metrics::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(), metrics::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(
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<metrics::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 AwMetricsServiceClient::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.
delegate_->AddWebViewAppStateObserver(this);
if (IsReportingEnabled()) {
// We assume the embedder has no shutdown sequence, so there's no need
// for a matching Stop() call.
metrics_service_->Start();
}
} 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));
pref_service_->ClearPref(metrics::prefs::kMetricsClientID);
pref_service_->ClearPref(metrics::prefs::kMetricsProvisionalClientID);
pref_service_->ClearPref(metrics::prefs::kMetricsLogRecordId);
}
}
void AwMetricsServiceClient::RegisterMetricsProvidersAndInitState() {
CHECK(metrics::SubprocessMetricsProvider::GetInstance());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::NetworkMetricsProvider>(
content::CreateNetworkConnectionTrackerAsyncGetter()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::CPUMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::EntropyStateProvider>(pref_service_));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::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<metrics::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>(
GetUnfilteredSampleRatePerMille()));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::ContentStabilityMetricsProvider>(
pref_service_, /*extensions_helper=*/nullptr));
delegate_->RegisterAdditionalMetricsProviders(metrics_service_.get());
// The file metrics provider performs IO.
base::ScopedAllowBlocking allow_io;
metrics_service_->InitializeMetricsRecordingState();
}
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;
}
bool AwMetricsServiceClient::IsConsentDetermined() const {
return init_finished_ && set_consent_finished_;
}
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();
}
metrics::MetricsService* AwMetricsServiceClient::GetMetricsServiceIfStarted() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return did_start_metrics_ ? metrics_service_.get() : nullptr;
}
variations::SyntheticTrialRegistry*
AwMetricsServiceClient::GetSyntheticTrialRegistry() {
return synthetic_trial_registry_.get();
}
metrics::MetricsService* AwMetricsServiceClient::GetMetricsService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// This will be null if initialization hasn't finished.
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 AwMetricsServiceClients
// UMA and Crashpad are independent, so this is a no-op.
void AwMetricsServiceClient::SetMetricsClientId(const std::string& client_id) {}
int32_t AwMetricsServiceClient::GetProduct() {
return metrics::ChromeUserMetricsExtension::ANDROID_WEBVIEW;
}
std::string AwMetricsServiceClient::GetApplicationLocale() {
return base::i18n::GetConfiguredLocale();
}
const network_time::NetworkTimeTracker*
AwMetricsServiceClient::GetNetworkTimeTracker() {
return nullptr;
}
bool AwMetricsServiceClient::GetBrand(std::string* brand_code) {
// AwMetricsServiceClients don't use brand codes.
return false;
}
metrics::SystemProfileProto::Channel AwMetricsServiceClient::GetChannel() {
return metrics::AsProtobufChannel(version_info::android::GetChannel());
}
bool AwMetricsServiceClient::IsExtendedStableChannel() {
return false; // Not supported on AwMetricsServiceClients.
}
std::string AwMetricsServiceClient::GetVersionString() {
return metrics::GetVersionString();
}
void AwMetricsServiceClient::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 AwMetricsServiceClient::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<metrics::MetricsLogUploader>
AwMetricsServiceClient::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) {
CHECK_EQ(service_type, metrics::MetricsLogUploader::UMA);
// |server_url|, |insecure_server_url|, and |mime_type| are unused because
// AwMetricsServiceClients send metrics to the platform logging mechanism
// rather than to Chrome's metrics server.
return std::make_unique<metrics::AndroidMetricsLogUploader>(
on_upload_complete);
}
base::TimeDelta AwMetricsServiceClient::GetStandardUploadInterval() {
// In AwMetricsServiceClients, 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
// AwMetricsServiceClients 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 AwMetricsServiceClient::ShouldStartUpFast() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return fast_startup_for_testing_;
}
void AwMetricsServiceClient::OnRenderProcessHostCreated(
content::RenderProcessHost* host) {
if (!host_observation_.IsObservingSource(host)) {
host_observation_.AddObservation(host);
}
}
void AwMetricsServiceClient::RenderProcessExited(
content::RenderProcessHost* host,
const content::ChildProcessTerminationInfo& info) {
host_observation_.RemoveObservation(host);
if (did_start_metrics_) {
metrics_service_->OnApplicationNotIdle();
}
}
void AwMetricsServiceClient::OnWebContentsCreated(
content::WebContents* web_contents) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
metrics::MetricsServicesWebContentsObserver::CreateForWebContents(
web_contents,
/*OnDidStartLoadingCb=*/
base::BindRepeating(&AwMetricsServiceClient::OnDidStartLoading,
weak_ptr_factory_.GetWeakPtr()),
/*OnDidStopLoadingCb=*/
base::BindRepeating(&AwMetricsServiceClient::OnApplicationNotIdle,
weak_ptr_factory_.GetWeakPtr()),
/*OnRendererUnresponsiveCb=*/
base::BindRepeating(&AwMetricsServiceClient::OnApplicationNotIdle,
weak_ptr_factory_.GetWeakPtr()));
}
void AwMetricsServiceClient::SetCollectFinalMetricsForLogClosureForTesting(
base::OnceClosure closure) {
collect_final_metrics_for_log_closure_ = std::move(closure);
}
void AwMetricsServiceClient::SetOnFinalMetricsCollectedListenerForTesting(
base::RepeatingClosure listener) {
on_final_metrics_collected_listener_ = std::move(listener);
}
int AwMetricsServiceClient::GetSampleBucketValue() const {
DCHECK(is_client_id_forced_);
return UintToPerMille(base::PersistentHash(metrics_service_->GetClientId()));
}
InstallerPackageType AwMetricsServiceClient::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_AwMetricsServiceClient_getInstallerPackageType(env);
return static_cast<InstallerPackageType>(type);
}
bool AwMetricsServiceClient::CanRecordPackageNameForAppType() {
InstallerPackageType installer_type = GetInstallerPackageType();
// Allow recording the app package name of system apps and apps
// from the play store.
return (installer_type == InstallerPackageType::SYSTEM_APP ||
installer_type == InstallerPackageType::GOOGLE_PLAY_STORE);
}
std::string AwMetricsServiceClient::GetAppPackageNameIfLoggable() {
if (CanRecordPackageNameForAppType()) {
return GetAppPackageName();
}
return std::string();
}
std::string AwMetricsServiceClient::GetAppPackageName() {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jstring> j_app_name =
Java_AwMetricsServiceClient_getAppPackageName(env);
if (j_app_name) {
return base::android::ConvertJavaStringToUTF8(env, j_app_name);
}
return std::string();
}
void AwMetricsServiceClient::OnApplicationNotIdle() {
auto* metrics_service = GetMetricsServiceIfStarted();
if (!metrics_service) {
return;
}
metrics_service->OnApplicationNotIdle();
}
void AwMetricsServiceClient::OnDidStartLoading() {
OnApplicationNotIdle();
auto* metrics_service = GetMetricsService();
if (!metrics_service) {
return;
}
metrics_service->OnPageLoadStarted();
}
int AwMetricsServiceClient::GetUnfilteredSampleRatePerMille() const {
// 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) {
return kStableUnfilteredSampledInRatePerMille;
}
return kBetaDevCanaryUnfilteredSampledInRatePerMille;
}
bool AwMetricsServiceClient::ShouldApplyMetricsFiltering() const {
bool in_unfiltered_sample =
GetSampleBucketValue() < GetUnfilteredSampleRatePerMille();
bool force_enabled = IsMetricsReportingForceEnabled();
return !(in_unfiltered_sample || force_enabled);
}
void AwMetricsServiceClient::OnAppStateChanged(
WebViewAppStateObserver::State state) {
// To match MetricsService's expectation,
// - does nothing if no WebView has ever been created.
// - starts notifying MetricsService once a WebView is created and the app
// is foreground.
// - consolidates the other states other than kForeground into background.
// - avoids the duplicated notification.
if (state == WebViewAppStateObserver::State::kDestroyed &&
!delegate_->HasAwContentsEverCreated()) {
return;
}
bool foreground = state == WebViewAppStateObserver::State::kForeground;
if (foreground == app_in_foreground_)
return;
app_in_foreground_ = foreground;
if (app_in_foreground_) {
GetMetricsService()->OnAppEnterForeground();
} else {
// TODO(crbug.com/40118864): Turn on the background recording.
// Not recording in background, this matches Chrome's behavior.
GetMetricsService()->OnAppEnterBackground(
/* keep_recording_in_background = false */);
}
}
// static
void AwMetricsServiceClient::RegisterMetricsPrefs(
PrefRegistrySimple* registry) {
metrics::MetricsService::RegisterPrefs(registry);
metrics::FileMetricsProvider::RegisterSourcePrefs(registry,
kBrowserMetricsName);
metrics::FileMetricsProvider::RegisterSourcePrefs(
registry, kCrashpadHistogramAllocatorName);
metrics::FileMetricsProvider::RegisterPrefs(registry);
metrics::StabilityMetricsHelper::RegisterPrefs(registry);
AndroidMetricsProvider::RegisterPrefs(registry);
}
// static
void JNI_AwMetricsServiceClient_SetHaveMetricsConsent(JNIEnv* env,
jboolean user_consent,
jboolean app_consent) {
AwMetricsServiceClient::GetInstance()->SetHaveMetricsConsent(user_consent,
app_consent);
}
// static
void JNI_AwMetricsServiceClient_SetFastStartupForTesting(
JNIEnv* env,
jboolean fast_startup_for_testing) {
AwMetricsServiceClient::GetInstance()->SetFastStartupForTesting(
fast_startup_for_testing);
}
// static
void JNI_AwMetricsServiceClient_SetUploadIntervalForTesting(
JNIEnv* env,
jlong upload_interval_ms) {
AwMetricsServiceClient::GetInstance()->SetUploadIntervalForTesting(
base::Milliseconds(upload_interval_ms));
}
// static
void JNI_AwMetricsServiceClient_SetOnFinalMetricsCollectedListenerForTesting(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& listener) {
AwMetricsServiceClient::GetInstance()
->SetOnFinalMetricsCollectedListenerForTesting(base::BindRepeating(
base::android::RunRunnableAndroid,
base::android::ScopedJavaGlobalRef<jobject>(listener)));
}
} // namespace android_webview