chromium/chrome/browser/ash/app_list/arc/arc_package_syncable_service.h

// Copyright 2016 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_APP_LIST_ARC_ARC_PACKAGE_SYNCABLE_SERVICE_H_
#define CHROME_BROWSER_ASH_APP_LIST_ARC_ARC_PACKAGE_SYNCABLE_SERVICE_H_

#include <stddef.h>

#include <memory>
#include <string>
#include <unordered_map>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/app_list/arc/arc_app_list_prefs.h"
#include "chrome/browser/ash/app_list/arc/arc_app_sync_metrics_helper.h"
#include "chrome/browser/ash/arc/session/arc_session_manager_observer.h"
#include "chrome/browser/sync/glue/sync_start_util.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_change_processor.h"
#include "components/sync/model/syncable_service.h"
#include "components/sync/protocol/arc_package_specifics.pb.h"

class Profile;

namespace content {
class BrowserContext;
}  // namespace content

namespace arc {

// Class that syncs ARC packages install/uninstall.
class ArcPackageSyncableService : public syncer::SyncableService,
                                  public KeyedService,
                                  public ArcAppListPrefs::Observer,
                                  public ArcSessionManagerObserver {
 public:
  struct SyncItem {
    SyncItem(const std::string& package_name,
             int32_t package_version,
             int64_t last_backup_android_id,
             int64_t last_backup_time);
    const std::string package_name;
    int32_t package_version;
    int64_t last_backup_android_id;
    int64_t last_backup_time;
  };

  // Use ArcPackageSyncableServiceFactory instead.
  ArcPackageSyncableService(Profile* profile, ArcAppListPrefs* prefs);
  ArcPackageSyncableService(const ArcPackageSyncableService&) = delete;
  ArcPackageSyncableService& operator=(const ArcPackageSyncableService&) =
      delete;

  ~ArcPackageSyncableService() override;

  static std::unique_ptr<ArcPackageSyncableService> Create(
      Profile* profile,
      ArcAppListPrefs* prefs);
  static ArcPackageSyncableService* Get(content::BrowserContext* context);

  // Returns true if requested package has pending sync request.
  bool IsPackageSyncing(const std::string& package_name) const;

  // syncer::SyncableService:
  void WaitUntilReadyToSync(base::OnceClosure done) override;
  std::optional<syncer::ModelError> MergeDataAndStartSyncing(
      syncer::DataType type,
      const syncer::SyncDataList& initial_sync_data,
      std::unique_ptr<syncer::SyncChangeProcessor> sync_processor) override;
  void StopSyncing(syncer::DataType type) override;
  std::optional<syncer::ModelError> ProcessSyncChanges(
      const base::Location& from_here,
      const syncer::SyncChangeList& change_list) override;
  base::WeakPtr<SyncableService> AsWeakPtr() override;

  bool SyncStarted();

  // Tries to install/resinstall a package that is in the pending list.
  // Sends the request to Android.
  void InstallPendingPackage(const std::string& package_name,
                             arc::mojom::InstallPriority priority);

 private:
  using SyncItemMap =
      std::unordered_map<std::string, std::unique_ptr<SyncItem>>;

  // ArcAppListPrefs::Observer:
  void OnPackageInstalled(const mojom::ArcPackageInfo& package_info) override;
  void OnPackageModified(const mojom::ArcPackageInfo& package_info) override;
  void OnPackageRemoved(const std::string& package_name,
                        bool uninstalled) override;
  void OnPackageListInitialRefreshed() override;

  // ArcSessionManagerObserver:
  void OnArcSessionStopped(ArcStopReason stop_reason) override;

  // Sends adds/updates sync change to sync server.
  void SendSyncChange(
      const mojom::ArcPackageInfo& package_info,
      const syncer::SyncChange::SyncChangeType& sync_change_type);

  // Creates or updates local syncItem with data change from sync server. Sends
  // request to install/update package to Android.
  bool ProcessSyncItemSpecifics(const sync_pb::ArcPackageSpecifics& specifics);

  // Deletes local syncItem corresponding to data change from sync server.
  // Sends request to uninstall package to Android.
  bool DeleteSyncItemSpecifics(const sync_pb::ArcPackageSpecifics& specifics);

  // Sends uninstall notification for given package to Android.
  void UninstallPackage(const SyncItem* sync_item);

  // Returns if a package should be synced.
  // TODO(lgcheng@) Support may need to be added in this function for different
  // use cases.
  bool ShouldSyncPackage(const std::string& package_name) const;

  // Maybe updates installation info for app sync metrics.
  void MaybeUpdateInstallMetrics(const mojom::ArcPackageInfo& package_info);

  const raw_ptr<Profile> profile_;
  base::OnceClosure wait_until_ready_to_sync_cb_;
  std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;

  // Items which are synced.
  SyncItemMap sync_items_;

  // Items new from sync service, waiting for confirmation of installation.
  // These items may never be approved for installation and this structure is
  // used to ensure syncer::SyncDataList GetAllSyncData(syncer::DataType type)
  // returns consistent results from different devices.
  // API to re-install pending_install_items_ can be created when needed.
  SyncItemMap pending_install_items_;

  // Items to delete from sync service, waiting for confirmation of
  // uninstallation. These items will no longer be counted in
  // syncer::SyncDataList GetAllSyncData(syncer::DataType type).
  // API to re-uninstall pending_uninstall_items_ can be created when needed.
  SyncItemMap pending_uninstall_items_;

  // Run()ning tells sync to try and start soon, because syncable changes
  // have started happening. It will cause sync to call us back
  // asynchronously via MergeDataAndStartSyncing as soon as possible.
  syncer::SyncableService::StartSyncFlare flare_;

  const raw_ptr<ArcAppListPrefs> prefs_;

  ArcAppSyncMetricsHelper metrics_helper_;

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

}  // namespace arc

#endif  // CHROME_BROWSER_ASH_APP_LIST_ARC_ARC_PACKAGE_SYNCABLE_SERVICE_H_