123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- // Copyright 2014 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 "chromecast/metrics/cast_metrics_service_client.h"
- #include <string>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/command_line.h"
- #include "base/files/file_path.h"
- #include "base/guid.h"
- #include "base/i18n/rtl.h"
- #include "base/logging.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "build/build_config.h"
- #include "chromecast/base/cast_sys_info_util.h"
- #include "chromecast/base/chromecast_switches.h"
- #include "chromecast/base/path_utils.h"
- #include "chromecast/base/pref_names.h"
- #include "chromecast/base/version.h"
- #include "components/metrics/client_info.h"
- #include "components/metrics/enabled_state_provider.h"
- #include "components/metrics/metrics_log_uploader.h"
- #include "components/metrics/metrics_provider.h"
- #include "components/metrics/metrics_service.h"
- #include "components/metrics/metrics_state_manager.h"
- #include "components/metrics/net/net_metrics_log_uploader.h"
- #include "components/metrics/url_constants.h"
- #include "components/prefs/pref_registry_simple.h"
- #include "components/prefs/pref_service.h"
- #include "services/network/public/cpp/shared_url_loader_factory.h"
- #if BUILDFLAG(IS_ANDROID)
- #include "chromecast/base/android/dumpstate_writer.h"
- #endif
- namespace chromecast {
- namespace metrics {
- namespace {
- const int kStandardUploadIntervalMinutes = 5;
- const char kMetricsOldClientID[] = "user_experience_metrics.client_id";
- #if BUILDFLAG(IS_ANDROID)
- const char kClientIdName[] = "Client ID";
- #endif // BUILDFLAG(IS_ANDROID)
- #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
- const struct ChannelMap {
- const char* chromecast_channel;
- const ::metrics::SystemProfileProto::Channel chrome_channel;
- } kMetricsChannelMap[] = {
- {"canary-channel", ::metrics::SystemProfileProto::CHANNEL_CANARY},
- {"dev-channel", ::metrics::SystemProfileProto::CHANNEL_DEV},
- {"developer-channel", ::metrics::SystemProfileProto::CHANNEL_DEV},
- {"beta-channel", ::metrics::SystemProfileProto::CHANNEL_BETA},
- {"dogfood-channel", ::metrics::SystemProfileProto::CHANNEL_BETA},
- {"stable-channel", ::metrics::SystemProfileProto::CHANNEL_STABLE},
- };
- ::metrics::SystemProfileProto::Channel GetReleaseChannelFromUpdateChannelName(
- const std::string& channel_name) {
- if (channel_name.empty())
- return ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
- for (const auto& channel_map : kMetricsChannelMap) {
- if (channel_name.compare(channel_map.chromecast_channel) == 0)
- return channel_map.chrome_channel;
- }
- // Any non-empty channel name is considered beta channel
- return ::metrics::SystemProfileProto::CHANNEL_BETA;
- }
- #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
- } // namespace
- void CastMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterStringPref(kMetricsOldClientID, std::string());
- }
- variations::SyntheticTrialRegistry*
- CastMetricsServiceClient::GetSyntheticTrialRegistry() {
- return synthetic_trial_registry_.get();
- }
- ::metrics::MetricsService* CastMetricsServiceClient::GetMetricsService() {
- return metrics_service_.get();
- }
- void CastMetricsServiceClient::SetMetricsClientId(
- const std::string& client_id) {
- client_id_ = client_id;
- LOG(INFO) << "Metrics client ID set: " << client_id;
- if (delegate_)
- delegate_->SetMetricsClientId(client_id);
- #if BUILDFLAG(IS_ANDROID)
- DumpstateWriter::AddDumpValue(kClientIdName, client_id);
- #endif
- }
- void CastMetricsServiceClient::StoreClientInfo(
- const ::metrics::ClientInfo& client_info) {
- // TODO(gfhuang): |force_client_id_| logic is super ugly, we should refactor
- // to align load/save logic of |force_client_id_| with Load/StoreClientInfo.
- // Currently it's lumped inside SetMetricsClientId(client_id).
- }
- std::unique_ptr<::metrics::ClientInfo>
- CastMetricsServiceClient::LoadClientInfo() {
- std::unique_ptr<::metrics::ClientInfo> client_info(new ::metrics::ClientInfo);
- client_info_loaded_ = true;
- // kMetricsIsNewClientID would be missing if either the device was just
- // FDR'ed, or it is on pre-v1.2 build.
- if (!pref_service_->GetBoolean(prefs::kMetricsIsNewClientID)) {
- // If the old client id exists, the device must be on pre-v1.2 build,
- // instead of just being FDR'ed.
- if (!pref_service_->GetString(kMetricsOldClientID).empty()) {
- // Force old client id to be regenerated. See b/9487011.
- client_info->client_id = base::GenerateGUID();
- pref_service_->SetBoolean(prefs::kMetricsIsNewClientID, true);
- return client_info;
- }
- // else the device was just FDR'ed, pass through.
- }
- // Use "forced" client ID if available.
- if (!force_client_id_.empty() && base::IsValidGUID(force_client_id_)) {
- client_info->client_id = force_client_id_;
- return client_info;
- }
- if (force_client_id_.empty()) {
- LOG(WARNING) << "Empty client id from platform,"
- << " assuming this is the first boot up of a new device.";
- } else {
- LOG(ERROR) << "Invalid client id from platform: " << force_client_id_
- << " from platform.";
- }
- return nullptr;
- }
- int32_t CastMetricsServiceClient::GetProduct() {
- // Chromecast currently uses the same product identifier as Chrome.
- return ::metrics::ChromeUserMetricsExtension::CAST;
- }
- std::string CastMetricsServiceClient::GetApplicationLocale() {
- return base::i18n::GetConfiguredLocale();
- }
- const network_time::NetworkTimeTracker*
- CastMetricsServiceClient::GetNetworkTimeTracker() {
- return nullptr;
- }
- bool CastMetricsServiceClient::GetBrand(std::string* brand_code) {
- return false;
- }
- ::metrics::SystemProfileProto::Channel CastMetricsServiceClient::GetChannel() {
- #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
- switch (cast_sys_info_->GetBuildType()) {
- case CastSysInfo::BUILD_ENG:
- return ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
- case CastSysInfo::BUILD_BETA:
- return ::metrics::SystemProfileProto::CHANNEL_BETA;
- case CastSysInfo::BUILD_PRODUCTION:
- return ::metrics::SystemProfileProto::CHANNEL_STABLE;
- }
- NOTREACHED();
- return ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
- #else
- // Use the system (or signed) release channel here to avoid the noise in the
- // metrics caused by the virtual channel which could be temporary or
- // arbitrary.
- return GetReleaseChannelFromUpdateChannelName(
- cast_sys_info_->GetSystemReleaseChannel());
- #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
- }
- bool CastMetricsServiceClient::IsExtendedStableChannel() {
- return false; // Not supported on Chromecast.
- }
- std::string CastMetricsServiceClient::GetVersionString() {
- int build_number;
- if (!base::StringToInt(CAST_BUILD_INCREMENTAL, &build_number))
- build_number = 0;
- // Sample result: 31.0.1650.0-K15386-devel
- std::string version_string(PRODUCT_VERSION);
- version_string.append("-K");
- version_string.append(base::NumberToString(build_number));
- const ::metrics::SystemProfileProto::Channel channel = GetChannel();
- CHECK(!CAST_IS_DEBUG_BUILD() ||
- channel != ::metrics::SystemProfileProto::CHANNEL_STABLE);
- const bool is_official_build =
- build_number > 0 && !CAST_IS_DEBUG_BUILD() &&
- channel != ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
- if (!is_official_build)
- version_string.append("-devel");
- return version_string;
- }
- void CastMetricsServiceClient::CollectFinalMetricsForLog(
- base::OnceClosure done_callback) {
- if (collect_final_metrics_cb_)
- collect_final_metrics_cb_.Run(std::move(done_callback));
- else
- std::move(done_callback).Run();
- }
- void CastMetricsServiceClient::SetCallbacks(
- base::RepeatingCallback<void(base::OnceClosure)> collect_final_metrics_cb,
- base::RepeatingCallback<void(base::OnceClosure)> external_events_cb) {
- collect_final_metrics_cb_ = collect_final_metrics_cb;
- external_events_cb_ = external_events_cb;
- }
- GURL CastMetricsServiceClient::GetMetricsServerUrl() {
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kOverrideMetricsUploadUrl)) {
- return GURL(
- command_line->GetSwitchValueASCII(switches::kOverrideMetricsUploadUrl));
- }
- // Note: This uses the old metrics service URL because some server-side
- // provisioning is needed to support the extra Cast traffic on the new URL.
- return GURL(::metrics::kOldMetricsServerUrl);
- }
- std::unique_ptr<::metrics::MetricsLogUploader>
- CastMetricsServiceClient::CreateUploader(
- const GURL& server_url,
- const GURL& insecure_server_url,
- base::StringPiece mime_type,
- ::metrics::MetricsLogUploader::MetricServiceType service_type,
- const ::metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
- return std::make_unique<::metrics::NetMetricsLogUploader>(
- url_loader_factory_, server_url, insecure_server_url, mime_type,
- service_type, on_upload_complete);
- }
- base::TimeDelta CastMetricsServiceClient::GetStandardUploadInterval() {
- return base::Minutes(kStandardUploadIntervalMinutes);
- }
- ::metrics::MetricsLogStore::StorageLimits
- CastMetricsServiceClient::GetStorageLimits() const {
- auto limits = ::metrics::MetricsServiceClient::GetStorageLimits();
- if (delegate_)
- delegate_->ApplyMetricsStorageLimits(&limits);
- return limits;
- }
- bool CastMetricsServiceClient::IsConsentGiven() const {
- return pref_service_->GetBoolean(prefs::kOptInStats);
- }
- void CastMetricsServiceClient::EnableMetricsService(bool enabled) {
- if (!task_runner_->BelongsToCurrentThread()) {
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&CastMetricsServiceClient::EnableMetricsService,
- base::Unretained(this), enabled));
- return;
- }
- if (enabled) {
- metrics_service_->Start();
- } else {
- metrics_service_->Stop();
- }
- }
- CastMetricsServiceClient::CastMetricsServiceClient(
- CastMetricsServiceDelegate* delegate,
- PrefService* pref_service,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
- : delegate_(delegate),
- pref_service_(pref_service),
- client_info_loaded_(false),
- task_runner_(base::ThreadTaskRunnerHandle::Get()),
- url_loader_factory_(url_loader_factory),
- cast_sys_info_(CreateSysInfo()) {}
- CastMetricsServiceClient::~CastMetricsServiceClient() = default;
- void CastMetricsServiceClient::OnApplicationNotIdle() {
- metrics_service_->OnApplicationNotIdle();
- }
- void CastMetricsServiceClient::SetForceClientId(const std::string& client_id) {
- DCHECK(force_client_id_.empty());
- DCHECK(!client_info_loaded_)
- << "Force client ID must be set before client info is loaded.";
- force_client_id_ = client_id;
- SetMetricsClientId(force_client_id_);
- }
- void CastMetricsServiceClient::InitializeMetricsService() {
- DCHECK(!metrics_state_manager_);
- metrics_state_manager_ = ::metrics::MetricsStateManager::Create(
- pref_service_, this, std::wstring(),
- // Pass an empty file path since Chromecast does not use the Variations
- // framework.
- /*user_data_dir=*/base::FilePath(),
- ::metrics::StartupVisibility::kUnknown,
- base::BindRepeating(&CastMetricsServiceClient::StoreClientInfo,
- base::Unretained(this)),
- base::BindRepeating(&CastMetricsServiceClient::LoadClientInfo,
- base::Unretained(this)));
- // Check that the FieldTrialList already exists. This happens in
- // CastMainDelegate::PostEarlyInitialization().
- DCHECK(base::FieldTrialList::GetInstance());
- // Perform additional setup that should be done after the FieldTrialList, the
- // MetricsStateManager, and its CleanExitBeacon exist. Since the list already
- // exists, the entropy provider type is unused.
- // TODO(crbug/1249485): Make Chromecast consistent with other platforms. I.e.
- // create the FieldTrialList and the MetricsStateManager around the same time.
- metrics_state_manager_->InstantiateFieldTrialList();
- synthetic_trial_registry_ =
- std::make_unique<variations::SyntheticTrialRegistry>(
- IsExternalExperimentAllowlistEnabled());
- metrics_service_.reset(new ::metrics::MetricsService(
- metrics_state_manager_.get(), this, pref_service_));
- // Always create a client id as it may also be used by crash reporting,
- // (indirectly) included in feedback, and can be queried during setup. For UMA
- // and crash reporting, associated opt-in settings control sending reports as
- // directed by the user. For setup (which also communicates the user's opt-in
- // preferences), report the client id and expect setup to handle the current
- // opt-in value.
- metrics_state_manager_->ForceClientIdCreation();
- // Populate |client_id| in other component parts.
- SetMetricsClientId(metrics_state_manager_->client_id());
- }
- void CastMetricsServiceClient::StartMetricsService() {
- if (delegate_)
- delegate_->RegisterMetricsProviders(metrics_service_.get());
- metrics_service_->InitializeMetricsRecordingState();
- #if !BUILDFLAG(IS_ANDROID)
- // Signal that the session has not yet exited cleanly. We later signal that
- // the session exited cleanly via MetricsService::LogCleanShutdown().
- // TODO(crbug.com/1208587): See whether this can be called even earlier.
- metrics_state_manager_->LogHasSessionShutdownCleanly(false);
- #endif // !BUILDFLAG(IS_ANDROID)
- if (IsReportingEnabled())
- metrics_service_->Start();
- }
- void CastMetricsServiceClient::Finalize() {
- metrics_service_->Stop();
- }
- void CastMetricsServiceClient::ProcessExternalEvents(base::OnceClosure cb) {
- if (external_events_cb_)
- external_events_cb_.Run(std::move(cb));
- else
- std::move(cb).Run();
- }
- } // namespace metrics
- } // namespace chromecast
|