chromium/ash/webui/diagnostics_ui/backend/system/system_routine_controller.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 ASH_WEBUI_DIAGNOSTICS_UI_BACKEND_SYSTEM_SYSTEM_ROUTINE_CONTROLLER_H_
#define ASH_WEBUI_DIAGNOSTICS_UI_BACKEND_SYSTEM_SYSTEM_ROUTINE_CONTROLLER_H_

#include <memory>
#include <optional>

#include "ash/webui/diagnostics_ui/mojom/system_routine_controller.mojom.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
#include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom-forward.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"

namespace base {
class OneShotTimer;
}  // namespace base

namespace ash::diagnostics {

using RunRoutineCallback =
    base::OnceCallback<void(cros_healthd::mojom::RunRoutineResponsePtr)>;

constexpr int32_t kInvalidRoutineId = 0;

class SystemRoutineController : public mojom::SystemRoutineController {
 public:
  SystemRoutineController();
  ~SystemRoutineController() override;

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

  // mojom::SystemRoutineController:
  void GetSupportedRoutines(GetSupportedRoutinesCallback callback) override;
  void RunRoutine(mojom::RoutineType type,
                  mojo::PendingRemote<mojom::RoutineRunner> runner) override;

  void BindInterface(
      mojo::PendingReceiver<mojom::SystemRoutineController> pending_receiver);
  // Handler for when remote attached to |receiver_| disconnects.
  void OnBoundInterfaceDisconnect();
  bool IsReceiverBoundForTesting();

  void SetWakeLockProviderForTesting(
      mojo::Remote<device::mojom::WakeLockProvider> provider) {
    wake_lock_provider_ = std::move(provider);
  }

 private:
  friend class SystemRoutineControllerTest;

  void OnAvailableRoutinesFetched(
      GetSupportedRoutinesCallback callback,
      const std::vector<cros_healthd::mojom::DiagnosticRoutineEnum>&
          supported_routines);

  void ExecuteRoutine(mojom::RoutineType routine_type);

  void OnRoutineStarted(
      mojom::RoutineType routine_type,
      cros_healthd::mojom::RunRoutineResponsePtr response_ptr);

  void OnPowerRoutineStarted(
      mojom::RoutineType routine_type,
      cros_healthd::mojom::RunRoutineResponsePtr response_ptr);

  void ContinuePowerRoutine(mojom::RoutineType routine_type);

  void OnPowerRoutineContinued(
      mojom::RoutineType routine_type,
      cros_healthd::mojom::RoutineUpdatePtr update_ptr);

  void CheckRoutineStatus(mojom::RoutineType routine_type);

  void OnRoutineStatusUpdated(mojom::RoutineType routine_type,
                              cros_healthd::mojom::RoutineUpdatePtr update_ptr);

  void HandlePowerRoutineStatusUpdate(
      mojom ::RoutineType routine_type,
      cros_healthd::mojom::RoutineUpdatePtr update_ptr);

  bool IsRoutineRunning() const;

  void ScheduleCheckRoutineStatus(uint32_t duration_in_seconds,
                                  mojom::RoutineType routine_type);

  void ParsePowerRoutineResult(mojom::RoutineType routine_type,
                               mojom::StandardRoutineResult result,
                               mojo::ScopedHandle output_handle);

  void OnPowerRoutineResultFetched(mojom::RoutineType routine_type,
                                   const std::string& file_contents);

  void OnPowerRoutineJsonParsed(mojom::RoutineType routine_type,
                                data_decoder::DataDecoder::ValueOrError result);

  void OnStandardRoutineResult(mojom::RoutineType routine_type,
                               mojom::StandardRoutineResult result);

  void OnPowerRoutineResult(mojom::RoutineType routine_type,
                            mojom::StandardRoutineResult result,
                            double percent_change,
                            uint32_t seconds_elapsed);

  void SendRoutineResult(mojom::RoutineResultInfoPtr result_info);

  void BindCrosHealthdDiagnosticsServiceIfNeccessary();

  void OnDiagnosticsServiceDisconnected();

  void OnInflightRoutineRunnerDisconnected();

  void OnRoutineCancelAttempted(
      cros_healthd::mojom::RoutineUpdatePtr update_ptr);

  void AcquireWakeLock();

  void ReleaseWakeLock();

  // Keeps track of the id created by CrosHealthd for the currently running
  // routine.
  int32_t inflight_routine_id_ = kInvalidRoutineId;

  // The currently inflight routine (if any). This is used to correctly
  // attribute cancellations.
  std::optional<mojom::RoutineType> inflight_routine_type_;

  // Records the number of routines that a user attempts to run during one
  // session in the app. Emitted when the app is closed.
  uint16_t routine_count_ = 0;

  // Timestamp of when the memory routine was started. Undefined if the memory
  // routine is not running.
  base::Time memory_routine_start_timestamp_;

  mojo::Remote<mojom::RoutineRunner> inflight_routine_runner_;
  std::unique_ptr<base::OneShotTimer> inflight_routine_timer_;

  mojo::Remote<cros_healthd::mojom::CrosHealthdDiagnosticsService>
      diagnostics_service_;

  mojo::Receiver<mojom::SystemRoutineController> receiver_{this};

  // `wake_lock_` is used to prevent the device from sleeping during the
  // memory test.
  mojo::Remote<device::mojom::WakeLock> wake_lock_;

  mojo::Remote<device::mojom::WakeLockProvider> wake_lock_provider_;

  // Keeps track of supported routines. Allows us to bypass querying CrosHealthd
  // on subsequent "GetSupportedRoutines" calls since the list never changes.
  std::vector<mojom::RoutineType> supported_routines_;

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

}  // namespace ash::diagnostics

#endif  // ASH_WEBUI_DIAGNOSTICS_UI_BACKEND_SYSTEM_SYSTEM_ROUTINE_CONTROLLER_H_