chromium/chrome/browser/ash/policy/status_collector/app_info_generator.h

// Copyright 2020 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_STATUS_COLLECTOR_APP_INFO_GENERATOR_H_
#define CHROME_BROWSER_ASH_POLICY_STATUS_COLLECTOR_APP_INFO_GENERATOR_H_

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "base/memory/raw_ref.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "chrome/browser/apps/app_service/app_service_proxy_forward.h"
#include "chrome/browser/ash/policy/status_collector/activity_storage.h"
#include "chrome/browser/ash/policy/status_collector/managed_session_service.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/services/app_service/public/cpp/instance_registry.h"

class Profile;

namespace apps {
class AppUpdate;
}

namespace enterprise_management {
class AppInfo;
}  // namespace enterprise_management

namespace policy {

// A class that is responsible for collecting application inventory and usage
// information.
class AppInfoGenerator : public apps::InstanceRegistry::Observer,
                         public ManagedSessionService::Observer {
 public:
  using Result = std::optional<std::vector<enterprise_management::AppInfo>>;

  explicit AppInfoGenerator(
      ManagedSessionService* managed_session_service,
      base::TimeDelta max_stored_past_activity_interval,
      base::Clock* clock = base::DefaultClock::GetInstance());
  AppInfoGenerator(const AppInfoGenerator&) = delete;
  AppInfoGenerator& operator=(const AppInfoGenerator&) = delete;
  ~AppInfoGenerator() override;

  // If reporting is enabled and there is an active affiliated user session,
  // generates an app info report with usage per app for up to the last
  // |max_stored_past_activity_interval| days for the current user, not
  // including the current day, otherwise returns a null optional.
  const Result Generate() const;

  // When not reporting usage is no longer recorded and app information is not
  // reported when generating the report.
  void OnReportingChanged(bool should_report);

  // Occurs when usage has been reported successfully. This removes reported
  // usage before |report_time| so it will not be reported again.
  void OnReportedSuccessfully(base::Time report_time);

  // Occurs when usage will be reported, which records active usage in the pref
  // up until the current time, so it may be reported.
  void OnWillReport();

  // ManagedSessionService::Observer
  void OnLogin(Profile* profile) override;
  void OnLogout(Profile* profile) override;
  void OnLocked() override;
  void OnUnlocked() override;
  void OnResumeActive(base::Time suspend_time) override;

  // InstanceRegistry::Observer
  void OnInstanceUpdate(const apps::InstanceUpdate& update) override;
  void OnInstanceRegistryWillBeDestroyed(
      apps::InstanceRegistry* cache) override;

  static void RegisterProfilePrefs(PrefRegistrySimple* registry);

 private:
  struct AppInstances {
    explicit AppInstances(const base::Time start_time_);
    AppInstances(const AppInstances&) = delete;
    AppInstances& operator=(const AppInstances&) = delete;
    ~AppInstances();

    const base::Time start_time;
    std::unordered_set<base::UnguessableToken, base::UnguessableTokenHash>
        running_instances;
  };
  struct AppInfoProvider {
    explicit AppInfoProvider(Profile* profile);
    AppInfoProvider(const AppInfoProvider&) = delete;
    AppInfoProvider& operator=(const AppInfoProvider&) = delete;
    ~AppInfoProvider();

    ActivityStorage activity_storage;
    const raw_ref<apps::AppServiceProxy> app_service_proxy;
  };

  const enterprise_management::AppInfo ConvertToAppInfo(
      const apps::AppUpdate& update,
      const std::vector<enterprise_management::TimePeriod>& app_activity) const;

  void SetOpenDurationsToClosed(base::Time end_time);

  void SetIdleDurationsToOpen();

  void OpenUsageInterval(const std::string& app_id,
                         const base::UnguessableToken& instance_key,
                         const base::Time start_time);

  void CloseUsageInterval(const std::string& app_id,
                          const base::UnguessableToken& instance_key,
                          const base::Time end_time);

  std::unique_ptr<AppInfoProvider> provider_;

  bool should_report_ = false;

  bool device_locked_ = false;

  std::map<std::string, std::unique_ptr<AppInstances>> app_instances_by_id_;

  // The timeout in the past to store activity.
  // This is kept in case status uploads fail for a number of days.
  base::TimeDelta max_stored_past_activity_interval_;

  const raw_ref<const base::Clock> clock_;

  base::ScopedObservation<ManagedSessionService,
                          ManagedSessionService::Observer>
      managed_session_observation_{this};
};

}  // namespace policy

#endif  // CHROME_BROWSER_ASH_POLICY_STATUS_COLLECTOR_APP_INFO_GENERATOR_H_