// 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_ARC_SESSION_ARC_SESSION_MANAGER_H_
#define CHROME_BROWSER_ASH_ARC_SESSION_ARC_SESSION_MANAGER_H_

#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <utility>

#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "base/timer/timer.h"
#include "chrome/browser/ash/arc/arc_support_host.h"
#include "chrome/browser/ash/arc/policy/arc_android_management_checker.h"
#include "chrome/browser/ash/arc/session/adb_sideloading_availability_delegate_impl.h"
#include "chrome/browser/ash/arc/session/arc_activation_necessity_checker.h"
#include "chrome/browser/ash/arc/session/arc_app_id_provider_impl.h"
#include "chrome/browser/ash/arc/session/arc_requirement_checker.h"
#include "chrome/browser/ash/arc/session/arc_session_manager_observer.h"
#include "chrome/browser/ash/guest_os/public/guest_os_mount_provider_registry.h"
#include "chrome/browser/ash/policy/arc/android_management_client.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
#include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"
#include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
#include "chromeos/ash/experiences/arc/arc_util.h"
#include "chromeos/ash/experiences/arc/dlc_installer/arc_dlc_installer.h"
#include "chromeos/ash/experiences/arc/session/arc_session_runner.h"
#include "chromeos/ash/experiences/arc/session/arc_stop_reason.h"
#include "components/session_manager/core/session_manager.h"
#include "components/session_manager/core/session_manager_observer.h"

class ApplicationLocaleStorage;
class ArcAppLauncher;
class PrefService;
class Profile;

namespace metrics {
class MetricsService;
}  // namespace metrics

namespace arc {

// The file exists only when ARC container is in use.
inline constexpr char kGeneratedBuildPropertyFilePath[] =
    "/run/arc/host_generated/build.prop";

// The file exists only when ARCVM is in use.
inline constexpr char kGeneratedCombinedPropertyFilePathVm[] =
    "/run/arcvm/host_generated/combined.prop";

class ArcDataRemover;
class ArcFastAppReinstallStarter;
class ArcPaiStarter;
class ArcProvisioningResult;
class ArcUiAvailabilityReporter;

enum class ProvisioningStatus;
enum class ArcStopReason;

// This class is responsible for handing stages of ARC life-cycle.
class ArcSessionManager : public ArcSessionRunner::Observer,
                          public ArcSupportHost::ErrorDelegate,
                          public ash::SessionManagerClient::Observer,
                          public ash::ConciergeClient::VmObserver,
                          public ArcRequirementChecker::Observer,
                          public session_manager::SessionManagerObserver {
 public:
  // Represents each State of ARC session.
  // NOT_INITIALIZED: represents the state that the Profile is not yet ready
  //   so that this service is not yet initialized, or Chrome is being shut
  //   down so that this is destroyed.
  // STOPPED: ARC session is not running, or being terminated.
  // CHECKING_REQUIREMENTS: Checking requirements before starting ARC.
  //   First, negotiates Google Play Store "Terms of Service" with a user. There
  //   are several ways for the negotiation, including opt-in flow, which shows
  //   "Terms of Service" page on ARC support app, and OOBE flow, which shows
  //   "Terms of Service" page as a part of Chrome OOBE flow. If user does not
  //   accept the Terms of Service, disables Google Play Store, which triggers
  //   RequestDisable() and the state will be set to STOPPED, then.
  //   Second, checks Android management status. Note that the status is checked
  //   for each ARC session starting, but this is the state only for the first
  //   boot case (= opt-in case). The second time and later the management check
  //   is running in parallel with ARC session starting, and in such a case,
  //   State is ACTIVE, instead.
  // REMOVING_DATA_DIR: When ARC is disabled, the data directory is removed.
  //   While removing is processed, ARC cannot be started. This is the state.
  // CHECKING_DATA_MIGRATION_NECESSITY: When ARC /data migration is enabled but
  //   not started yet, we need to check whether the migration is necessary by
  //   inspecting the content of /data. ARC cannot be started while the check is
  //   being performed, which is indicated by this state.
  // READY: ARC is ready to run, but not running yet. This state is skipped on
  //   the first boot case.
  // ACTIVE: ARC is running.
  // STOPPING: ARC is being shut down.
  //
  // State transition should be as follows:
  //
  // NOT_INITIALIZED -> STOPPED: when the primary Profile gets ready.
  // ...(any)... -> NOT_INITIALIZED: when the Chrome is being shutdown.
  // ...(any)... -> STOPPED: on error.
  //
  // In the first boot case:
  //   STOPPED -> CHECKING_REQUIREMENTS: On request to enable.
  //   CHECKING_REQUIREMENTS -> ACTIVE: when a user accepts "Terms Of Service"
  //     and the auth token is successfully fetched.
  //
  // In the second (or later) boot case:
  //   STOPPED -> READY: when arc.enabled preference is checked that it is true.
  //     Practically, this is when the primary Profile gets ready.
  //   READY -> ACTIVE: when activation is allowed.
  //
  // In the disabling case:
  //   CHECKING_REQUIREMENTS -> STOPPED
  //   READY -> STOPPED
  //   ACTIVE -> STOPPING -> (maybe REMOVING_DATA_DIR ->) STOPPED
  //   STOPPING: Eventually change the state to STOPPED. Do nothing
  //     immediately.
  //   REMOVING_DATA_DIR: Eventually state will become STOPPED. Do nothing
  //     immediately.
  //   CHECKING_DATA_MIGRATION_NECESSITY: Eventually state will become STOPPED.
  //     Do nothing immediately.
  //
  // TODO(hidehiko): Fix the state machine, and update the comment including
  // relationship with |enable_requested_|.
  enum class State {
    NOT_INITIALIZED,
    STOPPED,
    CHECKING_REQUIREMENTS,
    REMOVING_DATA_DIR,
    CHECKING_DATA_MIGRATION_NECESSITY,
    READY,
    ACTIVE,
    STOPPING,
  };

  using ExpansionResult = std::pair<std::string /* salt on disk */,
                                    bool /* expansion successful */>;

  // `local_state` and `application_locale_storage` must be non-null and must
  // outlive `this`.
  // `metrics_service` may be null in tests. If non-null, it must remain valid
  // until Shutdown() is called.
  ArcSessionManager(PrefService* local_state,
                    const ApplicationLocaleStorage* application_locale_storage,
                    metrics::MetricsService* metrics_service,
                    std::unique_ptr<ArcSessionRunner> arc_session_runner,
                    std::unique_ptr<AdbSideloadingAvailabilityDelegateImpl>
                        adb_sideloading_availability_delegate,
                    ArcDlcInstaller* arc_dlc_installer);

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

  ~ArcSessionManager() override;

  static ArcSessionManager* Get();

  static void SetUiEnabledForTesting(bool enabled);
  static void SetArcTermsOfServiceOobeNegotiatorEnabledForTesting(bool enabled);
  static void EnableCheckAndroidManagementForTesting(bool enable);

  // Returns true if ARC is allowed to run for the current session.
  // TODO(hidehiko): The name is very close to IsArcAllowedForProfile(), but
  // has different meaning. Clean this up.
  bool IsAllowed() const;

  // Start expanding the property files. Note that these property files are
  // needed to start the mini instance. This function also tries to read
  // /var/lib/misc/arc_salt when ARCVM is enabled.
  void ExpandPropertyFilesAndReadSalt();

  // Initializes ArcSessionManager. Before this runs, Profile must be set
  // via SetProfile().
  void Initialize();

  // Set the device scale factor used to start the arc. This must be called
  // before staring mini-ARC.
  void SetDefaultDeviceScaleFactor(float default_device_scale_factor);

  void Shutdown();

  // Sets the |profile|, and sets up Profile related fields in this instance.
  // IsArcAllowedForProfile() must return true for the given |profile|.
  void SetProfile(Profile* profile);
  Profile* profile() { return profile_; }
  const Profile* profile() const { return profile_; }

  State state() const { return state_; }

  // Adds or removes observers.
  void AddObserver(ArcSessionManagerObserver* observer);
  void RemoveObserver(ArcSessionManagerObserver* observer);

  // Notifies observers that Google Play Store enabled preference is changed.
  // Note: ArcPlayStoreEnabledPreferenceHandler has the main responsibility to
  // notify the event. However, due to life time, it is difficult for non-ARC
  // services to subscribe the handler instance directly. Instead, they can
  // subscribe to ArcSessionManager, and ArcSessionManager proxies the event.
  void NotifyArcPlayStoreEnabledChanged(bool enabled);

  // Called from ARC support platform app when user cancels signing.
  void CancelAuthCode();

  // Requests to enable ARC session. This starts ARC instance, or maybe starts
  // Terms Of Service negotiation if they haven't been accepted yet.
  // If it is already requested to enable, no-op.
  // Currently, enabled/disabled is tied to whether Google Play Store is
  // enabled or disabled. Please see also TODO of
  // SetArcPlayStoreEnabledForProfile().
  void RequestEnable();

  enum class AllowActivationReason {
    // Activated when ARCVM is ready to be launched.
    kImmediateActivation = 0,

    // User session start up tasks are completed, so deferred ARC activation
    // is done.
    kUserSessionStartUpTaskCompleted = 1,

    // AlwaysStart option is set, so forced to launch ARC.
    kAlwaysStartIsEnabled = 2,

    // Policy enforces to start ARC.
    kForcedByPolicy = 3,

    // User has taken an action to launch ARC app.
    kUserLaunchAction = 4,

    // User flipped the flag to enable ARC in the system.
    kUserEnableAction = 5,

    // ARC app is being restored.
    kRestoreApps = 6,

    kMaxValue = kRestoreApps,
  };

  // Allows changing the state from READY to ACTIVE. If the state is already
  // READY, calling this method changes the state to ACTIVE.
  void AllowActivation(AllowActivationReason reason);

  // Requests to disable ARC session. This stops ARC instance, or quits Terms
  // Of Service negotiation if it is the middle of the process (e.g. closing
  // UI for manual negotiation if it is shown). This does not remove user ARC
  // data.
  // If it is already requested to disable, no-op.
  void RequestDisable();

  // Requests to disable ARC session and remove ARC data.
  // If it is already requested to disable, no-op.
  void RequestDisableWithArcDataRemoval();

  // Requests to remove the ARC data.
  // If ARC is stopped, triggers to remove the data. Otherwise, queues to
  // remove the data after ARC stops.
  // A log statement with the removal reason must be added prior to calling
  // this.
  void RequestArcDataRemoval();

  // Stops ARC instance without removing user ARC data.
  // Unlike RequestDisable(), this doesn't clear user ARC prefs, and ARC is not
  // supposed to restart within the same user session.
  // NOTE: This method should be used only for the purpose of stopping ARC
  //       under low disk space.
  // TODO(b/236325019): Remove this once ArcSessionManager officially supports
  //       a method to stop ARC without clearing user ARC prefs, or when we
  //       remove ArcDiskSpaceMonitor after Storage Balloon is ready.
  void RequestStopOnLowDiskSpace();

  // ArcSupportHost:::ErrorDelegate:
  void OnWindowClosed() override;
  void OnRetryClicked() override;
  void OnSendFeedbackClicked() override;
  void OnRunNetworkTestsClicked() override;
  void OnErrorPageShown(bool network_tests_shown) override;

  // StopArc(), then restart. Between them data clear may happens.
  // This is a special method to support enterprise device lost case.
  // This can be called only when ARC is running.
  void StopAndEnableArc();

  ArcSupportHost* support_host() { return support_host_.get(); }

  // On provisioning completion (regardless of whether successfully done or
  // not), this is called with its status. On success, is_success() of
  // |result| returns true, otherwise ArcSignInResult can be retrieved from
  // get() if sign-in result came from ARC or stop_reason()
  // will indicate that ARC stopped prematurely and provisioning could
  // not finish successfully. is_timedout() indicates that operation timed
  // out.
  void OnProvisioningFinished(const ArcProvisioningResult& result);

  // A helper function that calls ArcSessionRunner's SetUserInfo.
  void SetUserInfo();

  // Trims VM's memory by moving it to zram.
  // When the operation is done |callback| is called.
  // If nonzero, |page_limit| defines the max number of pages to reclaim.
  using TrimVmMemoryCallback = ArcSessionRunner::TrimVmMemoryCallback;
  void TrimVmMemory(TrimVmMemoryCallback callback, int page_limit);

  // Returns the time when ARC was pre-started (mini-ARC start), or a null time
  // if ARC has not been pre-started yet.
  base::TimeTicks pre_start_time() const { return pre_start_time_; }

  // Returns the time when ARC was about to start, or a null time if ARC has
  // not been started yet.
  base::TimeTicks start_time() const { return start_time_; }

  // Returns the time when the sign in process started, or a null time if
  // signing in didn't happen during this session.
  base::TimeTicks sign_in_start_time() const { return sign_in_start_time_; }

  // Returns true if ARC requested to start.
  bool enable_requested() const { return enable_requested_; }

  // Returns PAI starter that is used to start Play Auto Install flow. It is
  // available only on initial start.
  ArcPaiStarter* pai_starter() { return pai_starter_.get(); }

  // Returns Fast App Reinstall starter that is used to start Play Fast App
  // Reinstall flow. It is available only on initial start.
  ArcFastAppReinstallStarter* fast_app_resintall_starter() {
    return fast_app_reinstall_starter_.get();
  }

  // Returns true if the current ARC run has started with skipping user ToS
  // negotiation, because the user had accepted already or policy does not
  // require ToS acceptance. Returns false in other cases, including one when
  // ARC is not currently running.
  bool skipped_terms_of_service_negotiation() const {
    return skipped_terms_of_service_negotiation_;
  }
  void set_skipped_terms_of_service_negotiation_for_testing(
      bool skipped_terms_of_service_negotiation) {
    skipped_terms_of_service_negotiation_ =
        skipped_terms_of_service_negotiation;
  }

  // Injectors for testing.
  void SetArcSessionRunnerForTesting(
      std::unique_ptr<ArcSessionRunner> arc_session_runner);
  ArcSessionRunner* GetArcSessionRunnerForTesting();
  void SetAttemptRestartCallbackForTesting(
      const base::RepeatingClosure& callback);
  void SetAndroidManagementCheckerFactoryForTesting(
      ArcRequirementChecker::AndroidManagementCheckerFactory
          android_management_checker_factory) {
    android_management_checker_factory_ = android_management_checker_factory;
  }

  // Returns whether the Play Store app is requested to be launched by this
  // class. Should be used only for tests.
  bool IsPlaystoreLaunchRequestedForTesting() const;

  // Invoking StartArc() only for testing, e.g., to emulate accepting Terms of
  // Service then passing Android management check successfully.
  void StartArcForTesting();

  // Invokes functions as if requirement checks are completed for testing.
  void EmulateRequirementCheckCompletionForTesting() {
    DCHECK(requirement_checker_);
    requirement_checker_->EmulateRequirementCheckCompletionForTesting();
  }

  // Invokes OnExpandPropertyFilesAndReadSalt as if the expansion is done.
  void OnExpandPropertyFilesAndReadSaltForTesting(bool result) {
    OnExpandPropertyFilesAndReadSalt(ExpansionResult{{}, result});
  }

  void reset_property_files_expansion_result() {
    property_files_expansion_result_.reset();
  }

  // ash::ConciergeClient::VmObserver overrides.
  void OnVmStarted(
      const vm_tools::concierge::VmStartedSignal& vm_signal) override;
  void OnVmStopped(
      const vm_tools::concierge::VmStoppedSignal& vm_signal) override;

  // session_manager::SessionManagerObserver overrides.
  void OnUserSessionStartUpTaskCompleted() override;

  // Getter for |serialno|.
  std::string GetSerialNumber() const;

  // Helper to Get Serial number for Attestation and KeyMint.
  // Calls GetSerialNumber() internally.
  std::string GetSerialNumberForKeyMint();

  // Stops mini-ARC instance. This should only be called before login.
  void StopMiniArcIfNecessary();

  // Returns whether ARC activation is delayed by ARC on Demand
  bool IsActivationDelayed() const {
    return is_activation_delayed_.value_or(false);
  }

  // Sets a callback that is run when the provisioning timer is started.
  void SetProvisioningTimerStartedCallbackForTesting(
      base::OnceClosure callback) {
    provisioning_timer_started_callback_for_testing_ = std::move(callback);
  }

 private:
  // TODO(crbug.com/395161942, crbug.com/393644378): Tracking
  // internal state transition for the production behavior.
  // We saw some unexpected behavior, but we didn't see the root cause
  // yet. This is for additional logging purpose only. We should remove
  // once we get the idea why unexpected behavior happens.
  enum InternalState {
    kNotInitialized,
    kRunning,
    kShutdown,
    kDestroying,
  };

  // Reports statuses of OptIn flow to UMA.
  class ScopedOptInFlowTracker;

  // Requests to disable ARC session and allows to optionally remove ARC data.
  // If ARC is already disabled, no-op.
  void RequestDisable(bool remove_arc_data);

  // RequestEnable() has a check in order not to trigger starting procedure
  // twice. This method can be called to bypass that check when restarting.
  void RequestEnableImpl();

  // Called when activation necessity check is done.
  void OnActivationNecessityChecked(bool result);

  // Negotiates the terms of service to user, if necessary.
  // Otherwise, move to StartAndroidManagementCheck().
  void MaybeStartTermsOfServiceNegotiation();

  // ArcRequirementChecker::Observer override:
  void OnArcOptInManagementCheckStarted() override;

  // Called when requirement checks are done.
  void OnRequirementChecksDone(
      ArcRequirementChecker::RequirementCheckResult result);

  void ShutdownSession();
  void ResetArcState();
  void OnArcSignInTimeout();

  // Starts requirement checks in background (in parallel with starting
  // ARC). This is for secondary or later ARC enabling.
  // The reason running them in parallel is for performance. The secondary or
  // later ARC enabling is typically on "logging into Chrome" for the user who
  // already opted in to use Google Play Store. In such a case, network is
  // typically not yet ready. Thus, if we block ARC boot, it delays several
  // seconds, which is not very user friendly.
  void StartBackgroundRequirementChecks();

  // Called when the background requirement checks are done.
  void OnBackgroundRequirementChecksDone(
      ArcRequirementChecker::BackgroundCheckResult result);

  // Requests to start ARC instance. Also, updates the internal state to
  // ACTIVE.
  void StartArc();

  // Calls StartArc() and starts background requirement checks.
  void StartArcForRegularBoot();

  // Requests to stop ARC instance. This resets two persistent flags:
  // kArcSignedIn and kArcTermsAccepted, so that, in next enabling,
  // it is started from Terms of Service negotiation.
  // TODO(hidehiko): Introduce STOPPING state, and this function should
  // transition to it.
  void StopArc();

  // ArcSessionRunner::Observer:
  void OnSessionStopped(ArcStopReason reason, bool restarting) override;
  void OnSessionRestarting() override;

  // Starts to remove ARC data, if it is requested via RequestArcDataRemoval().
  // On completion, OnArcDataRemoved() is called.
  // If not requested, just skipping the data removal, and moves to
  // MaybeReenableArc() directly.
  void MaybeStartArcDataRemoval();
  void OnArcDataRemoved(std::optional<bool> success);

  // On ARC session stopped and/or data removal completion, this is called
  // so that, if necessary, ARC session is restarted.
  // TODO(hidehiko): This can be removed after the racy state machine
  // is fixed.
  void MaybeReenableArc();

  // Starts a timer to check if provisioning takes too long.
  // The timer will not be set if this device was previously provisioned
  // successfully.
  void MaybeStartTimer();

  // Starts mini-ARC and updates related information.
  void StartMiniArc();

  // Requests the support host (if it exists) to show the error, and notifies
  // the observers.
  void ShowArcSupportHostError(ArcSupportHost::ErrorInfo error_info,
                               bool should_show_send_feedback,
                               bool should_show_run_network_tests);

  // ash::SessionManagerClient::Observer:
  void EmitLoginPromptVisibleCalled() override;

  // Called when the first part of ExpandPropertyFilesAndReadSalt is done.
  void OnExpandPropertyFiles(bool result);

  // Called when ExpandPropertyFilesAndReadSalt is done.
  void OnExpandPropertyFilesAndReadSalt(ExpansionResult result);

  // Records whether the first activation is triggered during
  // the user session start up.
  // Only the first invocation records it, and following calls
  // will be no-op.
  void MaybeRecordFirstActivationDuringUserSessionStartUp(bool value);

  // Called after the ARCVM DLC state has been checked. Starts the provisioning
  // timer with the appropriate timeout.
  void OnDlcCheckDoneForTimer(ArcDlcInstaller::DlcState state);

  // Starts the ARC sign-in provisioning timer with the specified |timeout|.
  void StartProvisioningTimerWithTimeout(base::TimeDelta timeout);

  // Invoked after WaitForServiceToBeAvailable(). Proceeds to query DLC state
  // if |available|, otherwise aborts ARC provisioning
  void OnDlcServiceReady(bool available);

  const raw_ref<PrefService> local_state_;
  const raw_ref<const ApplicationLocaleStorage> application_locale_storage_;
  raw_ptr<metrics::MetricsService> metrics_service_ = nullptr;

  std::unique_ptr<ArcSessionRunner> arc_session_runner_;
  std::unique_ptr<AdbSideloadingAvailabilityDelegateImpl>
      adb_sideloading_availability_delegate_;

  // Unowned pointer. Keeps current profile.
  raw_ptr<Profile> profile_ = nullptr;

  // Whether ArcSessionManager is requested to enable (starting to run ARC
  // instance) or not.
  bool enable_requested_ = false;

  // Internal state machine. See also State enum class.
  State state_ = State::NOT_INITIALIZED;

  // Internal state for investigation purpose.
  // TODO(crbug.com/395161942, crbug.com/393644378): remove these once
  // we figure out the cause.
  InternalState internal_state_ = InternalState::kNotInitialized;

  base::ObserverList<ArcSessionManagerObserver>::UncheckedAndDanglingUntriaged
      observer_list_;
  std::unique_ptr<ArcAppLauncher> playstore_launcher_;
  bool reenable_arc_ = false;
  bool provisioning_reported_ = false;
  bool skipped_terms_of_service_negotiation_ = false;
  bool activation_is_allowed_ = false;
  bool is_post_oobe_shutdown_4gb_device_ = false;
  // Tri-state of if Activation is delayed. 1) std::nullopt means it is yet
  // unknown, 2) true means Activation is delayed by ARC-on-demand, and 3)
  // false means Activation is not delayed by ARC-on-demand.
  // TODO(hidehiko): Consider to rename to make it more explicit that this is
  // for ARC-On-Demand only.
  std::optional<bool> is_activation_delayed_ = false;
  bool is_first_activation_during_user_session_start_up_recorded_ = false;
  base::OneShotTimer arc_sign_in_timer_;

  std::unique_ptr<ArcSupportHost> support_host_;
  std::unique_ptr<ArcDataRemover> data_remover_;

  ArcRequirementChecker::AndroidManagementCheckerFactory
      android_management_checker_factory_;
  std::unique_ptr<ArcRequirementChecker> requirement_checker_;

  std::unique_ptr<ArcActivationNecessityChecker> activation_necessity_checker_;

  std::unique_ptr<ScopedOptInFlowTracker> scoped_opt_in_tracker_;
  std::unique_ptr<ArcPaiStarter> pai_starter_;
  std::unique_ptr<ArcFastAppReinstallStarter> fast_app_reinstall_starter_;
  std::unique_ptr<ArcUiAvailabilityReporter> arc_ui_availability_reporter_;
  const raw_ptr<ArcDlcInstaller> arc_dlc_installer_;

  // The time when the sign in process started.
  base::TimeTicks sign_in_start_time_;
  // The time when ARC was pre-started (mini-ARC start).
  base::TimeTicks pre_start_time_;
  // The time when ARC was about to start.
  base::TimeTicks start_time_;

  // Timer set up when ARC necessity check is completed
  // but user session start up task are not yet completed.
  // Used to measure the elapsed time between it and the user session
  // start up task completion.
  struct UserSessionStartUpTaskTimer {
    base::ElapsedTimer timer;
    bool deferred;
  };
  std::optional<UserSessionStartUpTaskTimer> user_session_start_up_task_timer_;

  base::RepeatingClosure attempt_restart_callback_;

  ArcAppIdProviderImpl app_id_provider_;

  // The content of /var/lib/misc/arc_salt. Empty if the file doesn't exist.
  std::optional<std::string> arc_salt_on_disk_;

  std::optional<bool> property_files_expansion_result_;

  std::optional<guest_os::GuestOsMountProviderRegistry::Id>
      arcvm_mount_provider_id_;

  base::ScopedObservation<session_manager::SessionManager,
                          session_manager::SessionManagerObserver>
      session_manager_observation_{this};

  base::OnceClosure provisioning_timer_started_callback_for_testing_;

  // Must be the last member.
  base::WeakPtrFactory<ArcSessionManager> weak_ptr_factory_{this};
};

// Outputs the stringified |state| to |os|. This is only for logging purposes.
std::ostream& operator<<(std::ostream& os,
                         const ArcSessionManager::State& state);

}  // namespace arc

#endif  // CHROME_BROWSER_ASH_ARC_SESSION_ARC_SESSION_MANAGER_H_
