chromium/chrome/browser/ui/webui/ash/settings/calculator/size_calculator.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_UI_WEBUI_ASH_SETTINGS_CALCULATOR_SIZE_CALCULATOR_H_
#define CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_CALCULATOR_SIZE_CALCULATOR_H_

#include <array>
#include <bitset>
#include <memory>
#include <ostream>
#include <vector>

#include "ash/components/arc/disk_space/arc_disk_space_bridge.h"
#include "ash/components/arc/mojom/disk_space.mojom.h"
#include "ash/components/arc/session/connection_observer.h"
#include "base/files/file_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list_types.h"
#include "chrome/browser/browsing_data/site_data_size_collector.h"
#include "chromeos/ash/components/dbus/cryptohome/UserDataAuth.pb.h"
#include "chromeos/ash/components/dbus/cryptohome/rpc.pb.h"
#include "components/user_manager/user.h"

class Profile;

namespace vm_tools::concierge {
class ListVmDisksResponse;
}  // namespace vm_tools::concierge

namespace ash::settings {

// Base class for the calculation of a specific storage item. Instances of this
// class rely on their observers calling StartCalculation, and are designed to
// notify observers about the calculated sizes.
class SizeCalculator {
 public:
  // Enumeration listing the items displayed on the storage page.
  enum class CalculationType {
    kTotal = 0,
    kAvailable,
    kMyFiles,
    kBrowsingData,
    kAppsExtensions,
    kDriveOfflineFiles,
    kCrostini,
    kOtherUsers,
    kLastCalculationItem = kOtherUsers,
    kSystem,
  };

  // Implement this interface to be notified about item size callbacks.
  class Observer : public base::CheckedObserver {
   public:
    virtual void OnSizeCalculated(const CalculationType& item_id,
                                  int64_t total_bytes) = 0;
  };

  // Total number of storage items.
  static constexpr int kCalculationTypeCount =
      static_cast<int>(CalculationType::kLastCalculationItem) + 1;

  explicit SizeCalculator(CalculationType calculation_type);
  virtual ~SizeCalculator();

  // Starts the size calculation of a given storage item.
  void StartCalculation();

  // Adds an observer.
  virtual void AddObserver(Observer* observer);

  // Removes an observer.
  virtual void RemoveObserver(Observer* observer);

 protected:
  // Performs the size calculation.
  virtual void PerformCalculation() = 0;

  // Notify the StorageHandler about the calculated storage item size
  void NotifySizeCalculated(int64_t size);

  // Item id.
  const CalculationType calculation_type_;

  // Flag indicating that fetch operations for storage size are ongoing.
  bool calculating_ = false;

  // Observers being notified about storage items size changes.
  base::ObserverList<Observer> observers_;
};

std::ostream& operator<<(std::ostream& out, SizeCalculator::CalculationType t);

// Class handling the calculation of the total disk space on the system.
class TotalDiskSpaceCalculator : public SizeCalculator {
 public:
  explicit TotalDiskSpaceCalculator(Profile* profile);

  TotalDiskSpaceCalculator(const TotalDiskSpaceCalculator&) = delete;
  TotalDiskSpaceCalculator& operator=(const TotalDiskSpaceCalculator&) = delete;

  ~TotalDiskSpaceCalculator() override;

 private:
  friend class TotalDiskSpaceTestAPI;

  // SizeCalculator:
  void PerformCalculation() override;

  void GetRootDeviceSize();

  void OnGetRootDeviceSize(std::optional<int64_t> reply);

  void GetTotalDiskSpace();

  raw_ptr<Profile> profile_;
  base::WeakPtrFactory<TotalDiskSpaceCalculator> weak_ptr_factory_{this};
};

// Class handling the calculation of the amount free usable disk space.
class FreeDiskSpaceCalculator : public SizeCalculator {
 public:
  explicit FreeDiskSpaceCalculator(Profile* profile);

  FreeDiskSpaceCalculator(const FreeDiskSpaceCalculator&) = delete;
  FreeDiskSpaceCalculator& operator=(const FreeDiskSpaceCalculator&) = delete;

  ~FreeDiskSpaceCalculator() override;

 private:
  friend class FreeDiskSpaceTestAPI;

  // SizeCalculator:
  void PerformCalculation() override;

  void GetUserFreeDiskSpace();

  void OnGetUserFreeDiskSpace(std::optional<int64_t> reply);

  void GetFreeDiskSpace();

  raw_ptr<Profile> profile_;
  base::WeakPtrFactory<FreeDiskSpaceCalculator> weak_ptr_factory_{this};
};

class DriveOfflineSizeCalculator : public SizeCalculator {
 public:
  explicit DriveOfflineSizeCalculator(Profile* profile);

  DriveOfflineSizeCalculator(const DriveOfflineSizeCalculator&) = delete;
  DriveOfflineSizeCalculator& operator=(const DriveOfflineSizeCalculator&) =
      delete;

  ~DriveOfflineSizeCalculator() override;

 private:
  friend class DriveOfflineSizeTestAPI;

  void PerformCalculation() override;

  raw_ptr<Profile> profile_;
  base::WeakPtrFactory<DriveOfflineSizeCalculator> weak_ptr_factory_{this};
};

// Class handling the calculation of the size of the user's personal files: My
// files + Android Play files.
class MyFilesSizeCalculator : public SizeCalculator {
 public:
  explicit MyFilesSizeCalculator(Profile* profile);

  MyFilesSizeCalculator(const MyFilesSizeCalculator&) = delete;
  MyFilesSizeCalculator& operator=(const MyFilesSizeCalculator&) = delete;

  ~MyFilesSizeCalculator() override;

 private:
  friend class MyFilesSizeTestAPI;

  // SizeCalculator:
  void PerformCalculation() override;

  raw_ptr<Profile> profile_;
  base::WeakPtrFactory<MyFilesSizeCalculator> weak_ptr_factory_{this};
};

// Class handling the calculation of browsing data and cache.
class BrowsingDataSizeCalculator : public SizeCalculator {
 public:
  explicit BrowsingDataSizeCalculator(Profile* profile);

  BrowsingDataSizeCalculator(const BrowsingDataSizeCalculator&) = delete;
  BrowsingDataSizeCalculator& operator=(const BrowsingDataSizeCalculator&) =
      delete;

  ~BrowsingDataSizeCalculator() override;

 private:
  friend class BrowsingDataSizeTestAPI;

  // SizeCalculator:
  void PerformCalculation() override;

  // Callback to receive the cache size.
  void OnGetCacheSize(bool is_upper_limit, int64_t size);

  // Callback to update the size of browsing data.
  void OnGetBrowsingDataSize(bool is_site_data, int64_t size);

  // Total size of cache data in browsing data.
  int64_t browser_cache_size_ = -1;

  // True if we have already received the size of http cache.
  bool has_browser_cache_size_ = false;

  // Total size of site data in browsing data.
  int64_t browser_site_data_size_ = -1;

  // True if we have already received the size of http cache.
  bool has_browser_site_data_size_ = false;

  // Helper to compute the total size of all types of site date.
  std::unique_ptr<SiteDataSizeCollector> site_data_size_collector_;

  raw_ptr<Profile> profile_;
  base::WeakPtrFactory<BrowsingDataSizeCalculator> weak_ptr_factory_{this};
};

// Class handling the calculation of the size of the user's apps and extensions.
class AppsSizeCalculator
    : public SizeCalculator,
      public arc::ConnectionObserver<arc::mojom::DiskSpaceInstance> {
 public:
  explicit AppsSizeCalculator(Profile* profile);

  AppsSizeCalculator(const AppsSizeCalculator&) = delete;
  AppsSizeCalculator& operator=(const AppsSizeCalculator&) = delete;

  ~AppsSizeCalculator() override;

  // arc::ConnectionObserver<arc::mojom::DiskSpaceInstance>:
  void OnConnectionReady() override;
  void OnConnectionClosed() override;

  // Adds an observer. When the first observer is added, start observing the arc
  // mojo connection UpdateAndroidAppsSize relies on.
  void AddObserver(Observer* observer) override;

  // Removes an observer. When the last observer is removed, stop observing the
  // arc mojo connection.
  void RemoveObserver(Observer* observer) override;

 private:
  friend class AppsSizeTestAPI;

  // SizeCalculator:
  void PerformCalculation() override;

  // Requests updating the size of web store apps and extensions.
  void UpdateAppsSize();

  // Callback to update web store apps and extensions size.
  void OnGetAppsSize(int64_t total_bytes);

  // Requests updating the size of android apps.
  void UpdateAndroidAppsSize();

  // Callback to update Android apps and cache.
  void OnGetAndroidAppsSize(bool succeeded,
                            arc::mojom::ApplicationsSizePtr size);

  // Requests updating the size of Borealis apps.
  void UpdateBorealisAppsSize();

  // Callback to update Borealis apps and cache.
  void OnGetBorealisAppsSize(
      std::optional<vm_tools::concierge::ListVmDisksResponse> response);

  // Updates apps and extensions size.
  void UpdateAppsAndExtensionsSize();

  // Total size of apps and extensions
  int64_t apps_extensions_size_ = 0;

  // True if we have already received the size of apps and extensions.
  bool has_apps_extensions_size_ = false;

  // Total size of android apps
  int64_t android_apps_size_ = 0;

  // True if we have already received the size of Android apps.
  bool has_android_apps_size_ = false;

  // A flag for keeping track of the mojo connection status to the ARC
  // container.
  bool is_android_running_ = false;

  // Total size of Borealis apps (bytes).
  int64_t borealis_apps_size_ = 0;

  // True if we have already received the size of Borealis apps.
  bool has_borealis_apps_size_ = false;

  raw_ptr<Profile> profile_;
  base::WeakPtrFactory<AppsSizeCalculator> weak_ptr_factory_{this};
};

// Class handling the calculation of crostini VM size.
class CrostiniSizeCalculator : public SizeCalculator {
 public:
  explicit CrostiniSizeCalculator(Profile* profile);

  CrostiniSizeCalculator(const CrostiniSizeCalculator&) = delete;
  CrostiniSizeCalculator& operator=(const CrostiniSizeCalculator&) = delete;

  ~CrostiniSizeCalculator() override;

 private:
  friend class CrostiniSizeTestAPI;

  // SizeCalculator:
  void PerformCalculation() override;

  // Callback to update the size of Crostini VMs.
  void OnGetCrostiniSize(
      std::optional<vm_tools::concierge::ListVmDisksResponse>);

  raw_ptr<Profile> profile_;
  base::WeakPtrFactory<CrostiniSizeCalculator> weak_ptr_factory_{this};
};

// Class handling the calculation of other users' cryptohomes.
class OtherUsersSizeCalculator : public SizeCalculator {
 public:
  OtherUsersSizeCalculator();

  OtherUsersSizeCalculator(const OtherUsersSizeCalculator&) = delete;
  OtherUsersSizeCalculator& operator=(const OtherUsersSizeCalculator&) = delete;

  ~OtherUsersSizeCalculator() override;

 private:
  friend class OtherUsersSizeTestAPI;

  // SizeCalculator:
  void PerformCalculation() override;

  // Callback to update the sizes of the other users.
  void OnGetOtherUserSize(
      std::optional<::user_data_auth::GetAccountDiskUsageReply> reply);

  // The list of other users whose directory sizes will be accumulated as the
  // size of "Other users".
  user_manager::UserList other_users_;

  // Fetched sizes of user directories.
  std::vector<int64_t> user_sizes_;

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

}  // namespace ash::settings

#endif  // CHROME_BROWSER_UI_WEBUI_ASH_SETTINGS_CALCULATOR_SIZE_CALCULATOR_H_