chromium/chrome/browser/apps/app_service/metrics/app_platform_metrics_service.cc

// Copyright 2021 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/apps/app_service/metrics/app_platform_metrics_service.h"

#include "base/feature_list.h"
#include "base/time/time.h"
#include "chrome/browser/apps/app_service/app_service_proxy_ash.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"

namespace apps {

namespace {

// Interval for reporting noisy AppKM events.
constexpr base::TimeDelta kNoisyAppKMReportInterval = base::Hours(2);

// Check for a new day every 10 minutes.
constexpr base::TimeDelta kTimerInterval = base::Minutes(10);

// Check for app usage time, input event each 5 minutes.
constexpr base::TimeDelta kFiveMinutes = base::Minutes(5);

// Returns the number of days since the origin.
int GetDayId(base::Time time) {
  return time.UTCMidnight().since_origin().InDaysFloored();
}

}  // namespace

constexpr char kAppPlatformMetricsDayId[] = "app_platform_metrics.day_id";

AppPlatformMetricsService::AppPlatformMetricsService(Profile* profile)
    : profile_(profile) {
  DCHECK(profile_);
}

AppPlatformMetricsService::~AppPlatformMetricsService() {
  timer_.Stop();

  // Also notify observers.
  for (auto& observer : observers_) {
    observer.OnAppPlatformMetricsServiceWillBeDestroyed();
  }
}

// static
void AppPlatformMetricsService::RegisterProfilePrefs(
    PrefRegistrySimple* registry) {
  registry->RegisterIntegerPref(kAppPlatformMetricsDayId, 0);
  registry->RegisterDictionaryPref(kAppRunningDuration);
  registry->RegisterDictionaryPref(kAppActivatedCount);
  registry->RegisterDictionaryPref(kAppUsageTime);
  registry->RegisterDictionaryPref(kAppInputEventsKey);
  registry->RegisterDictionaryPref(kWebsiteUsageTime);

  AppDiscoveryMetrics::RegisterProfilePrefs(registry);
}

// static
int AppPlatformMetricsService::GetDayIdForTesting(base::Time time) {
  return GetDayId(time);
}

void AppPlatformMetricsService::Start(
    apps::AppRegistryCache& app_registry_cache,
    InstanceRegistry& instance_registry,
    apps::AppCapabilityAccessCache& app_capability_access_cache) {
  app_platform_app_metrics_ = std::make_unique<apps::AppPlatformMetrics>(
      profile_, app_registry_cache, instance_registry);
  app_platform_input_metrics_ = std::make_unique<apps::AppPlatformInputMetrics>(
      profile_, app_registry_cache, instance_registry);
  website_metrics_ = std::make_unique<apps::WebsiteMetrics>(
      profile_, GetUserTypeByDeviceTypeMetrics());
  app_discovery_metrics_ = std::make_unique<apps::AppDiscoveryMetrics>(
      profile_, app_registry_cache, instance_registry,
      app_platform_app_metrics_.get(), app_capability_access_cache);

  day_id_ = profile_->GetPrefs()->GetInteger(kAppPlatformMetricsDayId);
  CheckForNewDay();

  // Check for a new day every |kTimerInterval| as well.
  timer_.Start(FROM_HERE, kTimerInterval, this,
               &AppPlatformMetricsService::CheckForNewDay);

  // Check every `kFiveMinutes` to record app usage time and input events.
  five_minutes_timer_.Start(FROM_HERE, kFiveMinutes, this,
                            &AppPlatformMetricsService::CheckForFiveMinutes);

  // Check every `kNoisyAppKMReportInterval` to report noisy AppKM events.
  noisy_appkm_reporting_interval_timer_.Start(
      FROM_HERE, kNoisyAppKMReportInterval, this,
      &AppPlatformMetricsService::CheckForNoisyAppKMReportingInterval);

  // Also notify observers.
  for (auto& observer : observers_) {
    observer.OnAppPlatformMetricsInit(app_platform_app_metrics_.get());
    observer.OnWebsiteMetricsInit(website_metrics_.get());
  }
}

void AppPlatformMetricsService::AddObserver(
    AppPlatformMetricsService::Observer* observer) {
  observers_.AddObserver(observer);
}

void AppPlatformMetricsService::RemoveObserver(
    AppPlatformMetricsService::Observer* observer) {
  observers_.RemoveObserver(observer);
}

void AppPlatformMetricsService::SetWebsiteMetricsForTesting(
    std::unique_ptr<apps::WebsiteMetrics> website_metrics) {
  website_metrics_ = std::move(website_metrics);
}

void AppPlatformMetricsService::CheckForNewDay() {
  base::Time now = base::Time::Now();

  DCHECK(app_platform_app_metrics_);
  app_platform_app_metrics_->OnTenMinutes();

  if (day_id_ < GetDayId(now)) {
    day_id_ = GetDayId(now);
    app_platform_app_metrics_->OnNewDay();
    profile_->GetPrefs()->SetInteger(kAppPlatformMetricsDayId, day_id_);
  }
}

void AppPlatformMetricsService::CheckForFiveMinutes() {
  app_platform_app_metrics_->OnFiveMinutes();
  app_platform_input_metrics_->OnFiveMinutes();
  website_metrics_->OnFiveMinutes();
}

void AppPlatformMetricsService::CheckForNoisyAppKMReportingInterval() {
  app_platform_app_metrics_->OnTwoHours();
  app_platform_input_metrics_->OnTwoHours();
  website_metrics_->OnTwoHours();
}

}  // namespace apps