chromium/chromeos/ash/components/carrier_lock/carrier_lock_manager.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMEOS_ASH_COMPONENTS_CARRIER_LOCK_CARRIER_LOCK_MANAGER_H_
#define CHROMEOS_ASH_COMPONENTS_CARRIER_LOCK_CARRIER_LOCK_MANAGER_H_

#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chromeos/ash/components/carrier_lock/common.h"
#include "chromeos/ash/components/network/network_3gpp_handler.h"
#include "chromeos/ash/components/network/network_state_handler_observer.h"
#include "components/gcm_driver/gcm_driver.h"
#include "components/session_manager/core/session_manager_observer.h"
#include "net/base/backoff_entry.h"

class PrefService;
class PrefRegistrySimple;

namespace ash {
enum class CarrierLockResult;
class Network3gppHandler;
}  // namespace ash

namespace network {
class NetworkState;
class NetworkStateHandler;
class SharedURLLoaderFactory;
}  // namespace network

namespace session_manager {
class SessionManager;
}

namespace ash::carrier_lock {
class ProvisioningConfigFetcher;
class FcmTopicSubscriber;
class PsmClaimVerifier;

inline constexpr base::TimeDelta kRetryDelay = base::Seconds(15);
inline constexpr base::TimeDelta kConfigDelay = base::Minutes(1);
inline constexpr int kMaxRetries = 2;

enum class ModemLockStatus {
  kUnknown,
  kNotLocked,
  kCarrierLocked,
};

// State of Carrier Lock configuration process
enum class ConfigurationState {
  kNone,
  kInitialize,
  kPsmCheckClaim,
  kFcmGetToken,
  kRequestConfig,
  kSetupModem,
  kFcmCheckTopic,
  kFcmSubscribe,
  kDeviceLocked,
  kDeviceUnlocked,
  kFatalError
};

inline const char kLastConfigTimePref[] =
    "cellular.carrier_lock.last_configuration_time";
inline const char kDisableManagerPref[] = "cellular.carrier_lock.disable";
inline const char kLastImeiPref[] = "cellular.carrier_lock.last_imei";
inline const char kFcmTopicPref[] = "cellular.carrier_lock.fcm_topic";
inline const char kErrorCounterPref[] = "cellular.carrier_lock.error_counter";
inline const char kSignedConfigPref[] =
    "cellular.carrier_lock.signed_configuration";

// This is the main class that controls configuration process of cellular modem.
// It uses PsmClaimVerifier, ProvisioningConfigFetcher, Network3gppHandler and
// FcmTopicSubscriber to check whether the device should be Carrier Locked,
// download lock configuration, configure the modem and subscribe for
// notifications about configuration updates. (go/cros-carrier-lock-service)
class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_CARRIER_LOCK) CarrierLockManager
    : public NetworkStateHandlerObserver,
      public session_manager::SessionManagerObserver {
 public:
  explicit CarrierLockManager(PrefService*);
  CarrierLockManager() = delete;
  CarrierLockManager(const CarrierLockManager&) = delete;
  CarrierLockManager& operator=(const CarrierLockManager&) = delete;
  ~CarrierLockManager() override;

  // Create a new instance of Carrier Lock Manager
  // For testing, use CreateForTesting()
  static std::unique_ptr<CarrierLockManager> Create(
      PrefService*,
      gcm::GCMDriver*,
      scoped_refptr<network::SharedURLLoaderFactory>);

  // Register local preferences to keep configuration state between reboots
  static void RegisterLocalPrefs(PrefRegistrySimple*);

  // Return current status of modem lock configuration
  static ModemLockStatus GetModemLockStatus();

  static std::unique_ptr<CarrierLockManager> CreateForTesting(
      PrefService*,
      Network3gppHandler*,
      std::unique_ptr<FcmTopicSubscriber>,
      std::unique_ptr<PsmClaimVerifier>,
      std::unique_ptr<ProvisioningConfigFetcher>);

 private:
  friend class CarrierLockManagerTest;

  // ash::NetworkStateHandlerObserver:
  void DefaultNetworkChanged(const NetworkState*) override;
  void DevicePropertiesUpdated(const DeviceState* device) override;

  // session_manager::SessionManagerObserver:
  void OnSessionStateChanged() override;

  void Initialize();

  void RunStep(ConfigurationState);
  bool RetryStep();
  void CheckState();
  void LogError(Result result);

  void RequestConfig();
  void ConfigCallback(Result result);

  void CheckPsmClaim();
  void PsmCallback(Result result);

  void SetupModem();
  void SetupModemCallback(CarrierLockResult result);

  void GetFcmToken();
  void FcmTokenCallback(Result result);
  void CheckFcmTopic();
  void SubscribeFcmTopic();
  void FcmTopicCallback(Result result);
  void FcmNotification(bool is_from_topic);

  // Store a method pointer to quickly rebind last method in RetryStep().
  void (CarrierLockManager::*function_)();

  ConfigurationState configuration_state_;
  int remaining_retries_;

  raw_ptr<PrefService> local_state_;
  std::string serial_;
  std::string imei_;
  std::string fcm_token_;
  std::string manufacturer_;
  std::string model_;
  int error_counter_ = 0;
  bool is_first_setup_ = true;
  size_t trigger_first_run_ = 0;
  size_t trigger_network_ = 0;
  size_t trigger_retry_step_ = 0;
  size_t trigger_scheduler_ = 0;

  raw_ptr<NetworkStateHandler> network_state_handler_ = nullptr;
  raw_ptr<Network3gppHandler> modem_handler_ = nullptr;
  raw_ptr<session_manager::SessionManager> session_manager_ = nullptr;

  std::unique_ptr<ProvisioningConfigFetcher> config_;
  std::unique_ptr<PsmClaimVerifier> psm_;
  std::unique_ptr<FcmTopicSubscriber> fcm_;

  net::BackoffEntry retry_backoff_;
  base::WeakPtrFactory<CarrierLockManager> weak_ptr_factory_{this};
};

}  // namespace ash::carrier_lock

#endif  // CHROMEOS_ASH_COMPONENTS_CARRIER_LOCK_CARRIER_LOCK_MANAGER_H_