chromium/chrome/browser/ash/policy/reporting/metrics_reporting/apps/app_events_observer.h

// 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.

#ifndef CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_APPS_APP_EVENTS_OBSERVER_H_
#define CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_APPS_APP_EVENTS_OBSERVER_H_

#include <memory>
#include <string_view>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
#include "chrome/browser/apps/app_service/metrics/app_platform_metrics.h"
#include "chrome/browser/ash/policy/reporting/metrics_reporting/apps/app_platform_metrics_retriever.h"
#include "chrome/browser/profiles/profile.h"
#include "components/reporting/metrics/metric_event_observer.h"
#include "components/reporting/metrics/reporting_settings.h"
#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "components/services/app_service/public/cpp/app_types.h"

namespace reporting {

// Event observer that listens to relevant app related events supported by the
// `AppPlatformMetrics` component for reporting purposes.
class AppEventsObserver : public MetricEventObserver,
                          public ::apps::AppPlatformMetrics::Observer {
 public:
  // Static helper that instantiates the `AppEventsObserver` for the given
  // profile using the specified `ReportingSettings`.
  static std::unique_ptr<AppEventsObserver> CreateForProfile(
      Profile* profile,
      const ReportingSettings* reporting_settings);

  // Static test helper that instantiates the `AppEventsObserver` for the given
  // profile using the specified `AppPlatformMetricsRetriever` and
  // `ReportingSettings`.
  static std::unique_ptr<AppEventsObserver> CreateForTest(
      Profile* profile,
      std::unique_ptr<AppPlatformMetricsRetriever>
          app_platform_metrics_retriever,
      const ReportingSettings* reporting_settings);

  AppEventsObserver(const AppEventsObserver& other) = delete;
  AppEventsObserver& operator=(const AppEventsObserver& other) = delete;
  ~AppEventsObserver() override;

  // MetricEventObserver:
  void SetOnEventObservedCallback(MetricRepeatingCallback callback) override;

  // MetricEventObserver:
  void SetReportingEnabled(bool is_enabled) override;

 private:
  // Tracker that tracks app installs in the user pref store and helps
  // determine if the app was already installed. The `AppRegistryCache` attempts
  // to notify observers of app updates that facilitate tracking new installs,
  // but only if the component is initialized before app is actually installed.
  // It normally reports a list of apps registered on the device on init once
  // app publishers report them, and the tracker helps identify apps that were
  // newly installed so we can ignore the ones that were previously installed.
  // TODO (go/add-app-storage-in-app-service): This will be deprecated in favor
  // of the unified app storage setup in the app service once it is implemented.
  class AppInstallTracker {
   public:
    // Disk consumption metrics name.
    static constexpr char kDiskConsumptionMetricsName[] =
        "Browser.ERP.AppInstallTrackerDiskConsumption";

    explicit AppInstallTracker(base::WeakPtr<Profile> profile);
    AppInstallTracker(const AppInstallTracker& other) = delete;
    AppInstallTracker& operator=(const AppInstallTracker& other) = delete;
    ~AppInstallTracker();

    // Adds the specified app id for tracking purposes.
    void Add(std::string_view app_id);

    // Removes the specified app id.
    void Remove(std::string_view app_id);

    // Returns true if the specified app is being tracked in the user pref
    // store. False otherwise.
    bool Contains(std::string_view app_id) const;

   private:
    SEQUENCE_CHECKER(sequence_checker_);

    // Weak pointer to the user profile. Needed to access the user pref store.
    const base::WeakPtr<Profile> profile_;
  };

  AppEventsObserver(base::WeakPtr<Profile> profile,
                    std::unique_ptr<AppPlatformMetricsRetriever>
                        app_platform_metrics_retriever,
                    const ReportingSettings* reporting_settings);

  // Initializes events observer and starts observing app events tracked by the
  // `AppPlatformMetrics` component (if initialized).
  void InitEventObserver(::apps::AppPlatformMetrics* app_platform_metrics);

  // ::apps::AppPlatformMetrics::Observer:
  void OnAppInstalled(const std::string& app_id,
                      ::apps::AppType app_type,
                      ::apps::InstallSource app_install_source,
                      ::apps::InstallReason app_install_reason,
                      ::apps::InstallTime app_install_time) override;

  // ::apps::AppPlatformMetrics::Observer:
  void OnAppLaunched(const std::string& app_id,
                     ::apps::AppType app_type,
                     ::apps::LaunchSource app_launch_source) override;

  // ::apps::AppPlatformMetrics::Observer:
  void OnAppUninstalled(const std::string& app_id,
                        ::apps::AppType app_type,
                        ::apps::UninstallSource app_uninstall_source) override;

  // ::apps::AppPlatformMetrics::Observer:
  void OnAppPlatformMetricsDestroyed() override;

  SEQUENCE_CHECKER(sequence_checker_);

  // Weak pointer to the user profile. Needed to retrieve the app publisher id
  // for reporting purposes.
  base::WeakPtr<Profile> profile_;

  // App install tracker used by the event observer to filter out install event
  // notifications that include pre-installed apps.
  std::unique_ptr<AppInstallTracker> app_install_tracker_
      GUARDED_BY_CONTEXT(sequence_checker_);

  // Retriever that retrieves the `AppPlatformMetrics` component so the
  // `AppEventsObserver` can start observing app events.
  const std::unique_ptr<AppPlatformMetricsRetriever>
      app_platform_metrics_retriever_ GUARDED_BY_CONTEXT(sequence_checker_);

  // Pointer to the reporting settings that controls app inventory event
  // reporting. Guaranteed to outlive the observer because it is managed by the
  // `MetricReportingManager`.
  const raw_ptr<const ReportingSettings> reporting_settings_
      GUARDED_BY_CONTEXT(sequence_checker_);

  // Observer for tracking app events. Will be reset if the `AppPlatformMetrics`
  // component gets destructed before the event observer.
  base::ScopedObservation<::apps::AppPlatformMetrics,
                          ::apps::AppPlatformMetrics::Observer>
      observer_ GUARDED_BY_CONTEXT(sequence_checker_){this};

  // Callback triggered when app metrics are collected and app metric
  // reporting is enabled.
  MetricRepeatingCallback on_metric_observed_
      GUARDED_BY_CONTEXT(sequence_checker_);

  base::WeakPtrFactory<AppEventsObserver> weak_ptr_factory_{this};
};

}  // namespace reporting

#endif  // CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_APPS_APP_EVENTS_OBSERVER_H_