chromium/chromeos/dbus/power/native_timer.h

// Copyright 2018 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_DBUS_POWER_NATIVE_TIMER_H_
#define CHROMEOS_DBUS_POWER_NATIVE_TIMER_H_

#include <memory>
#include <string>
#include <vector>

#include "base/files/file_descriptor_watcher_posix.h"
#include "base/files/scoped_file.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromeos/dbus/power/power_manager_client.h"

namespace chromeos {

using OnStartNativeTimerCallback = base::OnceCallback<void(bool)>;

// Sets timers that can also wake up the device from suspend by making D-Bus
// calls to the power daemon.
class COMPONENT_EXPORT(DBUS_POWER) NativeTimer {
 public:
  // While exists, `NativeTimer::Start` will fail and call `result_callback`
  // with failed status.
  class ScopedFailureSimulatorForTesting {
   public:
    ScopedFailureSimulatorForTesting();
    ~ScopedFailureSimulatorForTesting();
  };

  explicit NativeTimer(const std::string& tag);

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

  ~NativeTimer();

  // Starts a timer to expire at |absolute_expiration_time|. Runs
  // |timer_expiration_callback| on timer expiration. Runs |result_callback|
  // with the result of the start operation. If starting the timer failed then
  // |timer_expiration_callback| will not be called.
  //
  // Consecutive |Start| calls override the previous |Start| call.
  void Start(base::TimeTicks absolute_expiration_time,
             base::OnceClosure timer_expiration_callback,
             OnStartNativeTimerCallback result_callback);

 private:
  struct StartTimerParams;

  // D-Bus callback for a create timer D-Bus call.
  void OnCreateTimer(base::ScopedFD expiration_fd,
                     std::optional<std::vector<int32_t>> timer_ids);

  // D-Bus callback for a start timer D-Bus call.
  void OnStartTimer(base::OnceClosure timer_expiration_callback,
                    OnStartNativeTimerCallback result_callback,
                    bool result);

  // Callback for timer expiration.
  void OnExpiration();

  // Resets the |expiration_fd_watcher_| and cancels any inflight callbacks.
  void ResetState();

  // Calls the result callback for a pending |Start| operation with false iff
  // |result| is false. Else, schedules a timer using the D-Bus API and calls
  // the result callback for a pending |Start| operation with true. Resets
  // |in_flight_start_timer_params_| in all cases.
  void ProcessAndResetInFlightStartParams(bool result);

  // Stores the parameters for |Start| when timer is not yet created i.e.
  // |timer_id_| is uninitialized. Since |Start| calls override each other at
  // any point only the latest |Start| call's parameters are stored in this.
  std::unique_ptr<StartTimerParams> in_flight_start_timer_params_;

  // Timer id returned by the power daemon, to be used as a handle for the timer
  // APIs.
  PowerManagerClient::TimerId timer_id_;

  // Tag associated with the D-Bus API. Cached for deleting the timer in the
  // destructor.
  std::string tag_;

  // File descriptor that will be written to when a Chrome OS alarm fires.
  base::ScopedFD expiration_fd_;

  // Callback to run when the timer expires.
  base::OnceClosure timer_expiration_callback_;

  // Watches |expiration_fd_| for an event.
  std::unique_ptr<base::FileDescriptorWatcher::Controller>
      expiration_fd_watcher_;

  // Indicating if the timer creation should fail. Only set by tests.
  static bool simulate_timer_creation_failure_for_testing_;

  SEQUENCE_CHECKER(sequence_checker_);

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

}  // namespace chromeos

#endif  // CHROMEOS_DBUS_POWER_NATIVE_TIMER_H_