cast_metrics_service_client.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "chromecast/metrics/cast_metrics_service_client.h"
  5. #include <string>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/command_line.h"
  9. #include "base/files/file_path.h"
  10. #include "base/guid.h"
  11. #include "base/i18n/rtl.h"
  12. #include "base/logging.h"
  13. #include "base/strings/string_number_conversions.h"
  14. #include "base/threading/thread_task_runner_handle.h"
  15. #include "build/build_config.h"
  16. #include "chromecast/base/cast_sys_info_util.h"
  17. #include "chromecast/base/chromecast_switches.h"
  18. #include "chromecast/base/path_utils.h"
  19. #include "chromecast/base/pref_names.h"
  20. #include "chromecast/base/version.h"
  21. #include "components/metrics/client_info.h"
  22. #include "components/metrics/enabled_state_provider.h"
  23. #include "components/metrics/metrics_log_uploader.h"
  24. #include "components/metrics/metrics_provider.h"
  25. #include "components/metrics/metrics_service.h"
  26. #include "components/metrics/metrics_state_manager.h"
  27. #include "components/metrics/net/net_metrics_log_uploader.h"
  28. #include "components/metrics/url_constants.h"
  29. #include "components/prefs/pref_registry_simple.h"
  30. #include "components/prefs/pref_service.h"
  31. #include "services/network/public/cpp/shared_url_loader_factory.h"
  32. #if BUILDFLAG(IS_ANDROID)
  33. #include "chromecast/base/android/dumpstate_writer.h"
  34. #endif
  35. namespace chromecast {
  36. namespace metrics {
  37. namespace {
  38. const int kStandardUploadIntervalMinutes = 5;
  39. const char kMetricsOldClientID[] = "user_experience_metrics.client_id";
  40. #if BUILDFLAG(IS_ANDROID)
  41. const char kClientIdName[] = "Client ID";
  42. #endif // BUILDFLAG(IS_ANDROID)
  43. #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
  44. const struct ChannelMap {
  45. const char* chromecast_channel;
  46. const ::metrics::SystemProfileProto::Channel chrome_channel;
  47. } kMetricsChannelMap[] = {
  48. {"canary-channel", ::metrics::SystemProfileProto::CHANNEL_CANARY},
  49. {"dev-channel", ::metrics::SystemProfileProto::CHANNEL_DEV},
  50. {"developer-channel", ::metrics::SystemProfileProto::CHANNEL_DEV},
  51. {"beta-channel", ::metrics::SystemProfileProto::CHANNEL_BETA},
  52. {"dogfood-channel", ::metrics::SystemProfileProto::CHANNEL_BETA},
  53. {"stable-channel", ::metrics::SystemProfileProto::CHANNEL_STABLE},
  54. };
  55. ::metrics::SystemProfileProto::Channel GetReleaseChannelFromUpdateChannelName(
  56. const std::string& channel_name) {
  57. if (channel_name.empty())
  58. return ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
  59. for (const auto& channel_map : kMetricsChannelMap) {
  60. if (channel_name.compare(channel_map.chromecast_channel) == 0)
  61. return channel_map.chrome_channel;
  62. }
  63. // Any non-empty channel name is considered beta channel
  64. return ::metrics::SystemProfileProto::CHANNEL_BETA;
  65. }
  66. #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
  67. } // namespace
  68. void CastMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
  69. registry->RegisterStringPref(kMetricsOldClientID, std::string());
  70. }
  71. variations::SyntheticTrialRegistry*
  72. CastMetricsServiceClient::GetSyntheticTrialRegistry() {
  73. return synthetic_trial_registry_.get();
  74. }
  75. ::metrics::MetricsService* CastMetricsServiceClient::GetMetricsService() {
  76. return metrics_service_.get();
  77. }
  78. void CastMetricsServiceClient::SetMetricsClientId(
  79. const std::string& client_id) {
  80. client_id_ = client_id;
  81. LOG(INFO) << "Metrics client ID set: " << client_id;
  82. if (delegate_)
  83. delegate_->SetMetricsClientId(client_id);
  84. #if BUILDFLAG(IS_ANDROID)
  85. DumpstateWriter::AddDumpValue(kClientIdName, client_id);
  86. #endif
  87. }
  88. void CastMetricsServiceClient::StoreClientInfo(
  89. const ::metrics::ClientInfo& client_info) {
  90. // TODO(gfhuang): |force_client_id_| logic is super ugly, we should refactor
  91. // to align load/save logic of |force_client_id_| with Load/StoreClientInfo.
  92. // Currently it's lumped inside SetMetricsClientId(client_id).
  93. }
  94. std::unique_ptr<::metrics::ClientInfo>
  95. CastMetricsServiceClient::LoadClientInfo() {
  96. std::unique_ptr<::metrics::ClientInfo> client_info(new ::metrics::ClientInfo);
  97. client_info_loaded_ = true;
  98. // kMetricsIsNewClientID would be missing if either the device was just
  99. // FDR'ed, or it is on pre-v1.2 build.
  100. if (!pref_service_->GetBoolean(prefs::kMetricsIsNewClientID)) {
  101. // If the old client id exists, the device must be on pre-v1.2 build,
  102. // instead of just being FDR'ed.
  103. if (!pref_service_->GetString(kMetricsOldClientID).empty()) {
  104. // Force old client id to be regenerated. See b/9487011.
  105. client_info->client_id = base::GenerateGUID();
  106. pref_service_->SetBoolean(prefs::kMetricsIsNewClientID, true);
  107. return client_info;
  108. }
  109. // else the device was just FDR'ed, pass through.
  110. }
  111. // Use "forced" client ID if available.
  112. if (!force_client_id_.empty() && base::IsValidGUID(force_client_id_)) {
  113. client_info->client_id = force_client_id_;
  114. return client_info;
  115. }
  116. if (force_client_id_.empty()) {
  117. LOG(WARNING) << "Empty client id from platform,"
  118. << " assuming this is the first boot up of a new device.";
  119. } else {
  120. LOG(ERROR) << "Invalid client id from platform: " << force_client_id_
  121. << " from platform.";
  122. }
  123. return nullptr;
  124. }
  125. int32_t CastMetricsServiceClient::GetProduct() {
  126. // Chromecast currently uses the same product identifier as Chrome.
  127. return ::metrics::ChromeUserMetricsExtension::CAST;
  128. }
  129. std::string CastMetricsServiceClient::GetApplicationLocale() {
  130. return base::i18n::GetConfiguredLocale();
  131. }
  132. const network_time::NetworkTimeTracker*
  133. CastMetricsServiceClient::GetNetworkTimeTracker() {
  134. return nullptr;
  135. }
  136. bool CastMetricsServiceClient::GetBrand(std::string* brand_code) {
  137. return false;
  138. }
  139. ::metrics::SystemProfileProto::Channel CastMetricsServiceClient::GetChannel() {
  140. #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
  141. switch (cast_sys_info_->GetBuildType()) {
  142. case CastSysInfo::BUILD_ENG:
  143. return ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
  144. case CastSysInfo::BUILD_BETA:
  145. return ::metrics::SystemProfileProto::CHANNEL_BETA;
  146. case CastSysInfo::BUILD_PRODUCTION:
  147. return ::metrics::SystemProfileProto::CHANNEL_STABLE;
  148. }
  149. NOTREACHED();
  150. return ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
  151. #else
  152. // Use the system (or signed) release channel here to avoid the noise in the
  153. // metrics caused by the virtual channel which could be temporary or
  154. // arbitrary.
  155. return GetReleaseChannelFromUpdateChannelName(
  156. cast_sys_info_->GetSystemReleaseChannel());
  157. #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
  158. }
  159. bool CastMetricsServiceClient::IsExtendedStableChannel() {
  160. return false; // Not supported on Chromecast.
  161. }
  162. std::string CastMetricsServiceClient::GetVersionString() {
  163. int build_number;
  164. if (!base::StringToInt(CAST_BUILD_INCREMENTAL, &build_number))
  165. build_number = 0;
  166. // Sample result: 31.0.1650.0-K15386-devel
  167. std::string version_string(PRODUCT_VERSION);
  168. version_string.append("-K");
  169. version_string.append(base::NumberToString(build_number));
  170. const ::metrics::SystemProfileProto::Channel channel = GetChannel();
  171. CHECK(!CAST_IS_DEBUG_BUILD() ||
  172. channel != ::metrics::SystemProfileProto::CHANNEL_STABLE);
  173. const bool is_official_build =
  174. build_number > 0 && !CAST_IS_DEBUG_BUILD() &&
  175. channel != ::metrics::SystemProfileProto::CHANNEL_UNKNOWN;
  176. if (!is_official_build)
  177. version_string.append("-devel");
  178. return version_string;
  179. }
  180. void CastMetricsServiceClient::CollectFinalMetricsForLog(
  181. base::OnceClosure done_callback) {
  182. if (collect_final_metrics_cb_)
  183. collect_final_metrics_cb_.Run(std::move(done_callback));
  184. else
  185. std::move(done_callback).Run();
  186. }
  187. void CastMetricsServiceClient::SetCallbacks(
  188. base::RepeatingCallback<void(base::OnceClosure)> collect_final_metrics_cb,
  189. base::RepeatingCallback<void(base::OnceClosure)> external_events_cb) {
  190. collect_final_metrics_cb_ = collect_final_metrics_cb;
  191. external_events_cb_ = external_events_cb;
  192. }
  193. GURL CastMetricsServiceClient::GetMetricsServerUrl() {
  194. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  195. if (command_line->HasSwitch(switches::kOverrideMetricsUploadUrl)) {
  196. return GURL(
  197. command_line->GetSwitchValueASCII(switches::kOverrideMetricsUploadUrl));
  198. }
  199. // Note: This uses the old metrics service URL because some server-side
  200. // provisioning is needed to support the extra Cast traffic on the new URL.
  201. return GURL(::metrics::kOldMetricsServerUrl);
  202. }
  203. std::unique_ptr<::metrics::MetricsLogUploader>
  204. CastMetricsServiceClient::CreateUploader(
  205. const GURL& server_url,
  206. const GURL& insecure_server_url,
  207. base::StringPiece mime_type,
  208. ::metrics::MetricsLogUploader::MetricServiceType service_type,
  209. const ::metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
  210. return std::make_unique<::metrics::NetMetricsLogUploader>(
  211. url_loader_factory_, server_url, insecure_server_url, mime_type,
  212. service_type, on_upload_complete);
  213. }
  214. base::TimeDelta CastMetricsServiceClient::GetStandardUploadInterval() {
  215. return base::Minutes(kStandardUploadIntervalMinutes);
  216. }
  217. ::metrics::MetricsLogStore::StorageLimits
  218. CastMetricsServiceClient::GetStorageLimits() const {
  219. auto limits = ::metrics::MetricsServiceClient::GetStorageLimits();
  220. if (delegate_)
  221. delegate_->ApplyMetricsStorageLimits(&limits);
  222. return limits;
  223. }
  224. bool CastMetricsServiceClient::IsConsentGiven() const {
  225. return pref_service_->GetBoolean(prefs::kOptInStats);
  226. }
  227. void CastMetricsServiceClient::EnableMetricsService(bool enabled) {
  228. if (!task_runner_->BelongsToCurrentThread()) {
  229. task_runner_->PostTask(
  230. FROM_HERE,
  231. base::BindOnce(&CastMetricsServiceClient::EnableMetricsService,
  232. base::Unretained(this), enabled));
  233. return;
  234. }
  235. if (enabled) {
  236. metrics_service_->Start();
  237. } else {
  238. metrics_service_->Stop();
  239. }
  240. }
  241. CastMetricsServiceClient::CastMetricsServiceClient(
  242. CastMetricsServiceDelegate* delegate,
  243. PrefService* pref_service,
  244. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
  245. : delegate_(delegate),
  246. pref_service_(pref_service),
  247. client_info_loaded_(false),
  248. task_runner_(base::ThreadTaskRunnerHandle::Get()),
  249. url_loader_factory_(url_loader_factory),
  250. cast_sys_info_(CreateSysInfo()) {}
  251. CastMetricsServiceClient::~CastMetricsServiceClient() = default;
  252. void CastMetricsServiceClient::OnApplicationNotIdle() {
  253. metrics_service_->OnApplicationNotIdle();
  254. }
  255. void CastMetricsServiceClient::SetForceClientId(const std::string& client_id) {
  256. DCHECK(force_client_id_.empty());
  257. DCHECK(!client_info_loaded_)
  258. << "Force client ID must be set before client info is loaded.";
  259. force_client_id_ = client_id;
  260. SetMetricsClientId(force_client_id_);
  261. }
  262. void CastMetricsServiceClient::InitializeMetricsService() {
  263. DCHECK(!metrics_state_manager_);
  264. metrics_state_manager_ = ::metrics::MetricsStateManager::Create(
  265. pref_service_, this, std::wstring(),
  266. // Pass an empty file path since Chromecast does not use the Variations
  267. // framework.
  268. /*user_data_dir=*/base::FilePath(),
  269. ::metrics::StartupVisibility::kUnknown,
  270. base::BindRepeating(&CastMetricsServiceClient::StoreClientInfo,
  271. base::Unretained(this)),
  272. base::BindRepeating(&CastMetricsServiceClient::LoadClientInfo,
  273. base::Unretained(this)));
  274. // Check that the FieldTrialList already exists. This happens in
  275. // CastMainDelegate::PostEarlyInitialization().
  276. DCHECK(base::FieldTrialList::GetInstance());
  277. // Perform additional setup that should be done after the FieldTrialList, the
  278. // MetricsStateManager, and its CleanExitBeacon exist. Since the list already
  279. // exists, the entropy provider type is unused.
  280. // TODO(crbug/1249485): Make Chromecast consistent with other platforms. I.e.
  281. // create the FieldTrialList and the MetricsStateManager around the same time.
  282. metrics_state_manager_->InstantiateFieldTrialList();
  283. synthetic_trial_registry_ =
  284. std::make_unique<variations::SyntheticTrialRegistry>(
  285. IsExternalExperimentAllowlistEnabled());
  286. metrics_service_.reset(new ::metrics::MetricsService(
  287. metrics_state_manager_.get(), this, pref_service_));
  288. // Always create a client id as it may also be used by crash reporting,
  289. // (indirectly) included in feedback, and can be queried during setup. For UMA
  290. // and crash reporting, associated opt-in settings control sending reports as
  291. // directed by the user. For setup (which also communicates the user's opt-in
  292. // preferences), report the client id and expect setup to handle the current
  293. // opt-in value.
  294. metrics_state_manager_->ForceClientIdCreation();
  295. // Populate |client_id| in other component parts.
  296. SetMetricsClientId(metrics_state_manager_->client_id());
  297. }
  298. void CastMetricsServiceClient::StartMetricsService() {
  299. if (delegate_)
  300. delegate_->RegisterMetricsProviders(metrics_service_.get());
  301. metrics_service_->InitializeMetricsRecordingState();
  302. #if !BUILDFLAG(IS_ANDROID)
  303. // Signal that the session has not yet exited cleanly. We later signal that
  304. // the session exited cleanly via MetricsService::LogCleanShutdown().
  305. // TODO(crbug.com/1208587): See whether this can be called even earlier.
  306. metrics_state_manager_->LogHasSessionShutdownCleanly(false);
  307. #endif // !BUILDFLAG(IS_ANDROID)
  308. if (IsReportingEnabled())
  309. metrics_service_->Start();
  310. }
  311. void CastMetricsServiceClient::Finalize() {
  312. metrics_service_->Stop();
  313. }
  314. void CastMetricsServiceClient::ProcessExternalEvents(base::OnceClosure cb) {
  315. if (external_events_cb_)
  316. external_events_cb_.Run(std::move(cb));
  317. else
  318. std::move(cb).Run();
  319. }
  320. } // namespace metrics
  321. } // namespace chromecast