chromium/chrome/browser/chromeos/reporting/metric_reporting_manager_lacros.cc

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

#include "chrome/browser/chromeos/reporting/metric_reporting_manager_lacros.h"

#include <memory>
#include <string>
#include <vector>

#include "base/functional/bind.h"
#include "base/location.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/reporting/device_reporting_settings_lacros.h"
#include "chrome/browser/chromeos/reporting/metric_default_utils.h"
#include "chrome/browser/chromeos/reporting/metric_reporting_prefs.h"
#include "chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.h"
#include "chrome/browser/chromeos/reporting/user_reporting_settings.h"
#include "chrome/browser/chromeos/reporting/websites/website_events_observer.h"
#include "chrome/browser/chromeos/reporting/websites/website_metrics_retriever_lacros.h"
#include "chrome/browser/chromeos/reporting/websites/website_usage_observer.h"
#include "chrome/browser/chromeos/reporting/websites/website_usage_telemetry_periodic_collector_lacros.h"
#include "chrome/browser/chromeos/reporting/websites/website_usage_telemetry_sampler.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chromeos/lacros/lacros_service.h"
#include "components/policy/policy_constants.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/version_info/version_info.h"

namespace reporting::metrics {

void MetricReportingManagerLacros::Delegate::CheckDeviceDeprovisioned(
    crosapi::mojom::DeviceSettingsService::IsDeviceDeprovisionedCallback
        callback) {
  auto* const lacros_service = ::chromeos::LacrosService::Get();
  if (!lacros_service ||
      !lacros_service->IsRegistered<crosapi::mojom::DeviceSettingsService>() ||
      !lacros_service->IsAvailable<crosapi::mojom::DeviceSettingsService>()) {
    // We should rarely get here since Lacros is initialized via Ash on ChromeOS
    // devices, but we return false anyway.
    std::move(callback).Run(false);
    return;
  }

  lacros_service->GetRemote<crosapi::mojom::DeviceSettingsService>()
      ->IsDeviceDeprovisioned(std::move(callback));
}

std::unique_ptr<DeviceReportingSettingsLacros>
MetricReportingManagerLacros::Delegate::CreateDeviceReportingSettings() {
  return DeviceReportingSettingsLacros::Create();
}

void MetricReportingManagerLacros::Delegate::RegisterObserverWithCrosApiClient(
    MetricReportingManagerLacros* const instance) {
  g_browser_process->browser_policy_connector()
      ->device_settings_lacros()
      ->AddObserver(instance);
}

MetricReportingManagerLacros::MetricReportingManagerLacros(
    Profile* profile,
    std::unique_ptr<MetricReportingManagerLacros::Delegate> delegate)
    : profile_(profile),
      delegate_(std::move(delegate)),
      device_reporting_settings_(delegate_->CreateDeviceReportingSettings()),
      user_reporting_settings_(
          std::make_unique<UserReportingSettings>(profile_->GetWeakPtr())),
      is_device_deprovisioned_(false) {
  CHECK_NE(profile, nullptr);
  if (!delegate_->IsUserAffiliated(*profile_)) {
    // We only report data for affiliated users on managed devices as of today.
    return;
  }

  // Update cached device deprovisioned state and initialize appropriate
  // components.
  auto is_deprovisioned_callback = base::BindOnce(
      [](base::WeakPtr<MetricReportingManagerLacros> instance,
         bool is_deprovisioned) {
        if (!instance) {
          return;
        }

        DCHECK_CALLED_ON_VALID_SEQUENCE(instance->sequence_checker_);
        instance->is_device_deprovisioned_ = is_deprovisioned;
        if (is_deprovisioned) {
          return;
        }

        SourceInfo source_info;
        source_info.set_source(SourceInfo::LACROS);
        source_info.set_source_version(
            std::string(::version_info::GetVersionNumber()));
        instance->telemetry_report_queue_ =
            instance->delegate_->CreatePeriodicUploadReportQueue(
                EventType::kUser, Destination::TELEMETRY_METRIC,
                Priority::MANUAL_BATCH_LACROS,
                instance->device_reporting_settings_.get(),
                ::policy::key::kReportUploadFrequency,
                GetDefaultReportUploadFrequency(),
                /*rate_unit_to_ms=*/1, source_info);
        auto website_event_rate_limiter =
            instance->delegate_->CreateSlidingWindowRateLimiter(
                kWebsiteEventsTotalSize, kWebsiteEventsWindow,
                kWebsiteEventsBucketCount);
        instance->website_event_report_queue_ =
            instance->delegate_->CreateMetricReportQueue(
                EventType::kUser, Destination::EVENT_METRIC,
                Priority::SLOW_BATCH, std::move(website_event_rate_limiter),
                std::move(source_info));

        instance->delegate_->RegisterObserverWithCrosApiClient(instance.get());
        instance->Init();
        instance->delayed_init_timer_.Start(
            FROM_HERE, instance->delegate_->GetInitDelay(),
            base::BindOnce(&MetricReportingManagerLacros::DelayedInit,
                           instance));
      },
      weak_ptr_factory_.GetWeakPtr());
  delegate_->CheckDeviceDeprovisioned(std::move(is_deprovisioned_callback));
}

MetricReportingManagerLacros::~MetricReportingManagerLacros() = default;

void MetricReportingManagerLacros::OnDeviceSettingsUpdated() {
  // Update cached device deprovisioned state and trigger shutdown if needed.
  auto is_deprovisioned_callback = base::BindOnce(
      [](base::WeakPtr<MetricReportingManagerLacros> instance,
         bool is_deprovisioned) {
        if (!instance) {
          return;
        }

        DCHECK_CALLED_ON_VALID_SEQUENCE(instance->sequence_checker_);
        instance->is_device_deprovisioned_ = is_deprovisioned;
        if (is_deprovisioned) {
          instance->Shutdown();
        }
      },
      weak_ptr_factory_.GetWeakPtr());
  delegate_->CheckDeviceDeprovisioned(std::move(is_deprovisioned_callback));
}

void MetricReportingManagerLacros::Shutdown() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  periodic_collectors_.clear();
  website_usage_observer_.reset();
  samplers_.clear();
  event_observer_managers_.clear();
  website_event_report_queue_.reset();
  telemetry_report_queue_.reset();
}

void MetricReportingManagerLacros::Init() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (is_device_deprovisioned_) {
    return;
  }
  InitWebsiteMetricCollectors();
}

void MetricReportingManagerLacros::DelayedInit() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (is_device_deprovisioned_) {
    return;
  }

  InitNetworkCollectors();
  initial_upload_timer_.Start(FROM_HERE, delegate_->GetInitialUploadDelay(),
                              this,
                              &MetricReportingManagerLacros::UploadTelemetry);
}

void MetricReportingManagerLacros::InitNetworkCollectors() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  auto network_bandwidth_sampler = std::make_unique<NetworkBandwidthSampler>(
      g_browser_process->network_quality_tracker(), profile_->GetWeakPtr());

  // Network bandwidth telemetry.
  InitPeriodicCollector(
      std::move(network_bandwidth_sampler), telemetry_report_queue_.get(),
      /*enable_setting_path=*/::policy::key::kReportDeviceNetworkStatus,
      kReportDeviceNetworkStatusDefaultValue,
      ::policy::key::kReportDeviceNetworkTelemetryCollectionRateMs,
      GetDefaultCollectionRate(kDefaultNetworkTelemetryCollectionRate));
}

void MetricReportingManagerLacros::InitWebsiteMetricCollectors() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  CHECK(profile_);
  const auto profile_weak_ptr = profile_->GetWeakPtr();

  // Website events.
  auto website_events_observer = std::make_unique<WebsiteEventsObserver>(
      std::make_unique<WebsiteMetricsRetrieverLacros>(profile_weak_ptr),
      user_reporting_settings_.get());
  InitEventObserverManager(
      std::move(website_events_observer), website_event_report_queue_.get(),
      user_reporting_settings_.get(), kReportWebsiteActivityAllowlist,
      kReportWebsiteActivityEnabledDefaultValue,
      /*init_delay=*/base::TimeDelta());

  // Website telemetry.
  website_usage_observer_ = std::make_unique<WebsiteUsageObserver>(
      profile_weak_ptr, user_reporting_settings_.get(),
      std::make_unique<WebsiteMetricsRetrieverLacros>(profile_weak_ptr));
  auto website_usage_telemetry_sampler =
      std::make_unique<WebsiteUsageTelemetrySampler>(profile_weak_ptr);
  auto website_usage_telemetry_periodic_collector =
      std::make_unique<WebsiteUsageTelemetryPeriodicCollectorLacros>(
          profile_, website_usage_telemetry_sampler.get(),
          telemetry_report_queue_.get(), user_reporting_settings_.get());
  samplers_.emplace_back(std::move(website_usage_telemetry_sampler));
  periodic_collectors_.emplace_back(
      std::move(website_usage_telemetry_periodic_collector));
}

void MetricReportingManagerLacros::InitPeriodicCollector(
    std::unique_ptr<Sampler> sampler,
    MetricReportQueue* metric_report_queue,
    const std::string& enable_setting_path,
    bool setting_enabled_default_value,
    const std::string& rate_setting_path,
    base::TimeDelta default_rate,
    int rate_unit_to_ms) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  auto* const sampler_ptr = sampler.get();
  samplers_.emplace_back(std::move(sampler));
  if (!metric_report_queue) {
    return;
  }
  periodic_collectors_.emplace_back(delegate_->CreatePeriodicCollector(
      sampler_ptr, metric_report_queue, device_reporting_settings_.get(),
      enable_setting_path, setting_enabled_default_value, rate_setting_path,
      default_rate, rate_unit_to_ms));
}

void MetricReportingManagerLacros::InitEventObserverManager(
    std::unique_ptr<MetricEventObserver> event_observer,
    MetricReportQueue* metric_report_queue,
    ReportingSettings* reporting_settings,
    const std::string& enable_setting_path,
    bool setting_enabled_default_value,
    base::TimeDelta init_delay) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (!metric_report_queue) {
    return;
  }
  event_observer_managers_.emplace_back(delegate_->CreateEventObserverManager(
      std::move(event_observer), metric_report_queue, reporting_settings,
      enable_setting_path, setting_enabled_default_value,
      /*collector_pool=*/nullptr, init_delay));
}

void MetricReportingManagerLacros::UploadTelemetry() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (!telemetry_report_queue_) {
    return;
  }
  telemetry_report_queue_->Upload();
}

}  // namespace reporting::metrics