blob: 874374989cdada31eec0cdf75780408b470c9b2c [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h"
#include <stdint.h>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/process/process_metrics.h"
#include "base/rand_util.h"
#include "base/strings/string16.h"
#include "base/threading/platform_thread.h"
#include "components/crash/core/common/crash_keys.h"
#include "components/metrics/call_stack_profile_metrics_provider.h"
#include "components/metrics/drive_metrics_provider.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_service.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/net/version_utils.h"
#include "components/metrics/profiler/profiler_metrics_provider.h"
#include "components/metrics/profiler/tracking_synchronizer.h"
#include "components/metrics/stability_metrics_helper.h"
#include "components/metrics/ui/screen_info_metrics_provider.h"
#include "components/metrics/url_constants.h"
#include "components/omnibox/browser/omnibox_metrics_provider.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/signin/core/browser/signin_status_metrics_provider.h"
#include "components/sync_driver/device_count_metrics_provider.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/version_info.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/chrome_paths.h"
#include "ios/chrome/browser/google/google_brand.h"
#include "ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h"
#include "ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.h"
#include "ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.h"
#include "ios/chrome/browser/sync/ios_chrome_sync_client.h"
#include "ios/chrome/browser/tab_parenting_global_observer.h"
#include "ios/chrome/browser/ui/browser_otr_state.h"
#include "ios/chrome/common/channel_info.h"
#include "ios/web/public/web_thread.h"
IOSChromeMetricsServiceClient::IOSChromeMetricsServiceClient(
metrics::MetricsStateManager* state_manager)
: metrics_state_manager_(state_manager),
stability_metrics_provider_(nullptr),
profiler_metrics_provider_(nullptr),
drive_metrics_provider_(nullptr),
start_time_(base::TimeTicks::Now()),
has_uploaded_profiler_data_(false),
weak_ptr_factory_(this) {
DCHECK(thread_checker_.CalledOnValidThread());
RegisterForNotifications();
}
IOSChromeMetricsServiceClient::~IOSChromeMetricsServiceClient() {
DCHECK(thread_checker_.CalledOnValidThread());
}
// static
std::unique_ptr<IOSChromeMetricsServiceClient>
IOSChromeMetricsServiceClient::Create(
metrics::MetricsStateManager* state_manager,
PrefService* local_state) {
// Perform two-phase initialization so that |client->metrics_service_| only
// receives pointers to fully constructed objects.
std::unique_ptr<IOSChromeMetricsServiceClient> client(
new IOSChromeMetricsServiceClient(state_manager));
client->Initialize();
return client;
}
// static
void IOSChromeMetricsServiceClient::RegisterPrefs(
PrefRegistrySimple* registry) {
metrics::MetricsService::RegisterPrefs(registry);
metrics::StabilityMetricsHelper::RegisterPrefs(registry);
}
metrics::MetricsService* IOSChromeMetricsServiceClient::GetMetricsService() {
return metrics_service_.get();
}
void IOSChromeMetricsServiceClient::SetMetricsClientId(
const std::string& client_id) {
crash_keys::SetMetricsClientIdFromGUID(client_id);
}
void IOSChromeMetricsServiceClient::OnRecordingDisabled() {
crash_keys::ClearMetricsClientId();
}
bool IOSChromeMetricsServiceClient::IsOffTheRecordSessionActive() {
return ::IsOffTheRecordSessionActive();
}
int32_t IOSChromeMetricsServiceClient::GetProduct() {
return metrics::ChromeUserMetricsExtension::CHROME;
}
std::string IOSChromeMetricsServiceClient::GetApplicationLocale() {
return GetApplicationContext()->GetApplicationLocale();
}
bool IOSChromeMetricsServiceClient::GetBrand(std::string* brand_code) {
return ios::google_brand::GetBrand(brand_code);
}
metrics::SystemProfileProto::Channel
IOSChromeMetricsServiceClient::GetChannel() {
return metrics::AsProtobufChannel(::GetChannel());
}
std::string IOSChromeMetricsServiceClient::GetVersionString() {
return metrics::GetVersionString();
}
void IOSChromeMetricsServiceClient::OnLogUploadComplete() {}
void IOSChromeMetricsServiceClient::InitializeSystemProfileMetrics(
const base::Closure& done_callback) {
finished_init_task_callback_ = done_callback;
drive_metrics_provider_->GetDriveMetrics(
base::Bind(&IOSChromeMetricsServiceClient::OnInitTaskGotDriveMetrics,
weak_ptr_factory_.GetWeakPtr()));
}
void IOSChromeMetricsServiceClient::CollectFinalMetricsForLog(
const base::Closure& done_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
collect_final_metrics_done_callback_ = done_callback;
if (ShouldIncludeProfilerDataInLog()) {
// Fetch profiler data. This will call into
// |FinishedReceivingProfilerData()| when the task completes.
metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
weak_ptr_factory_.GetWeakPtr());
} else {
CollectFinalHistograms();
}
}
std::unique_ptr<metrics::MetricsLogUploader>
IOSChromeMetricsServiceClient::CreateUploader(
const base::Callback<void(int)>& on_upload_complete) {
return std::unique_ptr<metrics::MetricsLogUploader>(
new metrics::NetMetricsLogUploader(
GetApplicationContext()->GetSystemURLRequestContext(),
metrics::kDefaultMetricsServerUrl, metrics::kDefaultMetricsMimeType,
on_upload_complete));
}
base::TimeDelta IOSChromeMetricsServiceClient::GetStandardUploadInterval() {
return metrics::GetUploadInterval();
}
base::string16 IOSChromeMetricsServiceClient::GetRegistryBackupKey() {
return base::string16();
}
void IOSChromeMetricsServiceClient::OnRendererProcessCrash() {
stability_metrics_provider_->LogRendererCrash();
}
void IOSChromeMetricsServiceClient::WebStateDidStartLoading(
web::WebState* web_state) {
metrics_service_->OnApplicationNotIdle();
}
void IOSChromeMetricsServiceClient::WebStateDidStopLoading(
web::WebState* web_state) {
metrics_service_->OnApplicationNotIdle();
}
void IOSChromeMetricsServiceClient::Initialize() {
metrics_service_.reset(new metrics::MetricsService(
metrics_state_manager_, this, GetApplicationContext()->GetLocalState()));
// Register metrics providers.
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(
new metrics::NetworkMetricsProvider(
web::WebThread::GetBlockingPool())));
// Currently, we configure OmniboxMetricsProvider to not log events to UMA
// if there is a single incognito session visible. In the future, it may
// be worth revisiting this to still log events from non-incognito sessions.
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(new OmniboxMetricsProvider(
base::Bind(&::IsOffTheRecordSessionActive))));
stability_metrics_provider_ = new IOSChromeStabilityMetricsProvider(
GetApplicationContext()->GetLocalState());
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(stability_metrics_provider_));
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(
new metrics::ScreenInfoMetricsProvider));
drive_metrics_provider_ = new metrics::DriveMetricsProvider(
web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE),
ios::FILE_LOCAL_STATE);
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(drive_metrics_provider_));
profiler_metrics_provider_ = new metrics::ProfilerMetricsProvider(
base::Bind(&metrics::IsCellularLogicEnabled));
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(profiler_metrics_provider_));
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(
new metrics::CallStackProfileMetricsProvider));
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(
SigninStatusMetricsProvider::CreateInstance(base::WrapUnique(
new IOSChromeSigninStatusMetricsProviderDelegate))));
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(
new MobileSessionShutdownMetricsProvider(metrics_service_.get())));
metrics_service_->RegisterMetricsProvider(
std::unique_ptr<metrics::MetricsProvider>(
new sync_driver::DeviceCountMetricsProvider(
base::Bind(&IOSChromeSyncClient::GetDeviceInfoTrackers))));
}
void IOSChromeMetricsServiceClient::OnInitTaskGotDriveMetrics() {
finished_init_task_callback_.Run();
}
bool IOSChromeMetricsServiceClient::ShouldIncludeProfilerDataInLog() {
// Upload profiler data at most once per session.
if (has_uploaded_profiler_data_)
return false;
// For each log, flip a fair coin. Thus, profiler data is sent with the first
// log with probability 50%, with the second log with probability 25%, and so
// on. As a result, uploaded data is biased toward earlier logs.
// TODO(isherman): Explore other possible algorithms, and choose one that
// might be more appropriate. For example, it might be reasonable to include
// profiler data with some fixed probability, so that a given client might
// upload profiler data more than once; but on average, clients won't upload
// too much data.
if (base::RandDouble() < 0.5)
return false;
has_uploaded_profiler_data_ = true;
return true;
}
void IOSChromeMetricsServiceClient::ReceivedProfilerData(
const metrics::ProfilerDataAttributes& attributes,
const tracked_objects::ProcessDataPhaseSnapshot& process_data_phase,
const metrics::ProfilerEvents& past_events) {
profiler_metrics_provider_->RecordProfilerData(
process_data_phase, attributes.process_id, attributes.process_type,
attributes.profiling_phase, attributes.phase_start - start_time_,
attributes.phase_finish - start_time_, past_events);
}
void IOSChromeMetricsServiceClient::FinishedReceivingProfilerData() {
CollectFinalHistograms();
}
void IOSChromeMetricsServiceClient::CollectFinalHistograms() {
DCHECK(thread_checker_.CalledOnValidThread());
// TODO(ios): Try to extract the flow below into a utility function that is
// shared between the iOS port's usage and
// ChromeMetricsServiceClient::CollectFinalHistograms()'s usage of
// MetricsMemoryDetails.
std::unique_ptr<base::ProcessMetrics> process_metrics(
base::ProcessMetrics::CreateProcessMetrics(
base::GetCurrentProcessHandle()));
UMA_HISTOGRAM_MEMORY_KB("Memory.Browser",
process_metrics->GetWorkingSetSize() / 1024);
collect_final_metrics_done_callback_.Run();
}
void IOSChromeMetricsServiceClient::RegisterForNotifications() {
tab_parented_subscription_ =
TabParentingGlobalObserver::GetInstance()->RegisterCallback(
base::Bind(&IOSChromeMetricsServiceClient::OnTabParented,
base::Unretained(this)));
omnibox_url_opened_subscription_ =
OmniboxEventGlobalTracker::GetInstance()->RegisterCallback(
base::Bind(&IOSChromeMetricsServiceClient::OnURLOpenedFromOmnibox,
base::Unretained(this)));
}
void IOSChromeMetricsServiceClient::OnTabParented(web::WebState* web_state) {
metrics_service_->OnApplicationNotIdle();
}
void IOSChromeMetricsServiceClient::OnURLOpenedFromOmnibox(OmniboxLog* log) {
metrics_service_->OnApplicationNotIdle();
}