chromium/chrome/browser/ash/policy/remote_commands/device_command_reboot_job.h

// Copyright 2015 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_REMOTE_COMMANDS_DEVICE_COMMAND_REBOOT_JOB_H_
#define CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_REBOOT_JOB_H_

#include <string>

#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/wall_clock_timer.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "components/policy/core/common/remote_commands/remote_command_job.h"

namespace ash {
class LoginState;
class SessionTerminationManager;
}  // namespace ash

namespace base {
class Clock;
class TickClock;
}  // namespace base

namespace policy {

class RebootNotificationsScheduler;

// Reboots a device with regards to its current mode. See
// go/cros-reboot-command-dd for detailed design. Handles the following cases:
// * If the device was booted after the command was issued: does not reboot and
//   reports success.
// * If the power manager service is unavailable, reports failure.
// * If the devices runs in a kiosk mode, reports success and reboots
//   immediately.
// * If the device runs in a regular mode:
//   * If there is no logged in user, reports success and reboots immediately.
//   * If a user is logged in, notifies the user, waits for a timeout, reports
//     success and reboots.
//   * If the user signs out during the waiting period, reports success and
//     reboots.
class DeviceCommandRebootJob : public RemoteCommandJob,
                               public chromeos::PowerManagerClient::Observer {
 public:
  DeviceCommandRebootJob();

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

  ~DeviceCommandRebootJob() override;

  // RemoteCommandJob:
  enterprise_management::RemoteCommand_Type GetType() const override;

  // chromeos::PowerManagerClient::Observer:
  void PowerManagerBecameAvailable(bool available) override;

 protected:
  using GetBootTimeCallback = base::RepeatingCallback<base::TimeTicks()>;

  // Extended constructor for testing puproses.
  // Extended constructor for testing puproses. `power_manager_client`,
  // `loging_state`, `session_termination_manager`,
  // `in_session_notifications_scheduler`, `clock` and `tick_clock` must
  // outlive the job.
  DeviceCommandRebootJob(
      chromeos::PowerManagerClient* power_manager_client,
      ash::LoginState* loging_state,
      ash::SessionTerminationManager* session_termination_manager,
      RebootNotificationsScheduler* in_session_notifications_scheduler,
      const base::Clock* clock,
      const base::TickClock* tick_clock,
      GetBootTimeCallback get_boot_time_callback);

  bool ParseCommandPayload(const std::string& command_payload) override;

 private:
  // Posts a task with a callback. Command's callbacks cannot be run
  // synchronously from `RunImpl`.
  static void RunAsyncCallback(CallbackWithResult callback,
                               ResultType result,
                               base::Location from_where);

  // RemoteCommandJob:
  void RunImpl(CallbackWithResult result_callback) override;

  // Handles reboot with an active user. Shows a reboot notification, waits for
  // the timeout or sign out, and reboots.
  void RebootUserSession();

  // Called when `session_termination_manager_` is about to reboot on signout.
  void OnSignout();

  // Called when a user clicks reboot button on the reboot dialog.
  void OnRebootButtonClicked();

  void OnRebootTimeoutExpired();

  // Reports success and initiates a reboot request with given `reason`.
  // Shall be called once.
  void DoReboot(const std::string& reason);

  // Unsubscribes from events that trigger reboot, e.g. in-session timer.
  void ResetTriggeringEvents();

  // Sends the reboot request to power manager service. Unowned.
  const raw_ptr<chromeos::PowerManagerClient> power_manager_client_;
  // Checks the availability of `power_manager_client_`.
  base::ScopedObservation<chromeos::PowerManagerClient, DeviceCommandRebootJob>
      power_manager_availability_observation_{this};

  // Provides information about current logins status and device mode to
  // determine how to proceed with the reboot.
  const raw_ptr<ash::LoginState> login_state_;

  // Handles reboot on signout.
  raw_ptr<ash::SessionTerminationManager> session_termination_manager_;

  // Scheduler for reboot notification and dialog. Unowned.
  raw_ptr<RebootNotificationsScheduler> in_session_notifications_scheduler_;
  // Timer tracking the delayed reboot event.
  base::WallClockTimer in_session_reboot_timer_;

  // Clock to schedule in-user-session reboot delay. Can be mocked for testing.
  // Unowned.
  raw_ptr<const base::Clock> clock_;

  // Returns device's boot timestamp. The boot time is not constant and may
  // change at runtime, e.g. because of time sync.
  const GetBootTimeCallback get_boot_time_callback_;

  CallbackWithResult result_callback_;

  // Delay between execution start in user session and the reboot.
  base::TimeDelta user_session_delay_;

  base::WeakPtrFactory<DeviceCommandRebootJob> weak_factory_{this};
};

}  // namespace policy

#endif  // CHROME_BROWSER_ASH_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_REBOOT_JOB_H_