chromium/chromecast/browser/metrics/cast_browser_metrics.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromecast/browser/metrics/cast_browser_metrics.h"

#include "base/check.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "chromecast/base/chromecast_switches.h"
#include "chromecast/base/path_utils.h"
#include "chromecast/browser/metrics/cast_stability_metrics_provider.h"
#include "components/metrics/content/gpu_metrics_provider.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/net/network_metrics_provider.h"
#include "components/metrics/ui/screen_info_metrics_provider.h"
#include "content/public/browser/histogram_fetcher.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/common/content_switches.h"

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "chromecast/browser/metrics/external_metrics.h"
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_ANDROID)
#include "chromecast/base/android/dumpstate_writer.h"
#endif

namespace chromecast {
namespace metrics {

const int kMetricsFetchTimeoutSeconds = 60;

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
const char kExternalUmaEventsRelativePath[] = "metrics/uma-events";
const char kPlatformUmaEventsPath[] = "/data/share/chrome/metrics/uma-events";
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

CastBrowserMetrics::CastBrowserMetrics(
    std::unique_ptr<CastMetricsServiceClient> metrics_service_client) {
  metrics_service_client_ = std::move(metrics_service_client);
  metrics_service_client_->SetCallbacks(
      base::BindRepeating(&CastBrowserMetrics::CollectFinalMetricsForLog,
                          base::Unretained(this)),
      base::BindRepeating(&CastBrowserMetrics::ProcessExternalEvents,
                          base::Unretained(this)));
}

CastBrowserMetrics::~CastBrowserMetrics() {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  DCHECK(!external_metrics_);
  DCHECK(!platform_metrics_);
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
}

void CastBrowserMetrics::Initialize() {
  metrics_service_client_->InitializeMetricsService();

  auto* metrics_service = metrics_service_client_->GetMetricsService();
  auto stability_provider_unique_ptr =
      std::make_unique<CastStabilityMetricsProvider>(
          metrics_service, metrics_service_client_->pref_service());
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  auto* stability_provider = stability_provider_unique_ptr.get();
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  metrics_service->RegisterMetricsProvider(
      std::move(stability_provider_unique_ptr));

  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  if (!command_line->HasSwitch(switches::kDisableGpu)) {
    metrics_service->RegisterMetricsProvider(
        std::make_unique<::metrics::GPUMetricsProvider>());

    // TODO(gfhuang): Does ChromeCast actually need metrics about screen info?
    // crbug.com/541577
    metrics_service->RegisterMetricsProvider(
        std::make_unique<::metrics::ScreenInfoMetricsProvider>());
  }

  metrics_service->RegisterMetricsProvider(
      std::make_unique<::metrics::NetworkMetricsProvider>(
          content::CreateNetworkConnectionTrackerAsyncGetter()));

  metrics_service_client_->StartMetricsService();

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  // Start external metrics collection, which feeds data from external
  // processes into the main external metrics.
  external_metrics_ = new ExternalMetrics(
      stability_provider,
      GetHomePathASCII(kExternalUmaEventsRelativePath).value());
  external_metrics_->Start();
  platform_metrics_ =
      new ExternalMetrics(stability_provider, kPlatformUmaEventsPath);
  platform_metrics_->Start();
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
}

void CastBrowserMetrics::Finalize() {
#if !BUILDFLAG(IS_ANDROID)
  // Signal that the session has exited cleanly.
  metrics_service_client_->GetMetricsService()->LogCleanShutdown();
#endif  // !BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  // Stop metrics service cleanly before destructing CastMetricsServiceClient.
  // The pointer will be deleted in StopAndDestroy().
  external_metrics_->StopAndDestroy();
  external_metrics_ = nullptr;
  platform_metrics_->StopAndDestroy();
  platform_metrics_ = nullptr;
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

  metrics_service_client_->Finalize();
}

void CastBrowserMetrics::CollectFinalMetricsForLog(
    base::OnceClosure done_callback) {
  // Asynchronously fetch metrics data from child processes. Since this method
  // is called on log upload, metrics that occur between log upload and child
  // process termination will not be uploaded.
  content::FetchHistogramsAsynchronously(
      base::SingleThreadTaskRunner::GetCurrentDefault(),
      std::move(done_callback), base::Seconds(kMetricsFetchTimeoutSeconds));
}

void CastBrowserMetrics::ProcessExternalEvents(base::OnceClosure cb) {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  external_metrics_->ProcessExternalEvents(
      base::BindOnce(&ExternalMetrics::ProcessExternalEvents,
                     base::Unretained(platform_metrics_), std::move(cb)));
#else
  std::move(cb).Run();
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
}

}  // namespace metrics
}  // namespace chromecast