chromium/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_routines.mojom

// 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.

// Definitions for the diagnostics API exposed by the cros_healthd daemon. This
// API is normally consumed by the browser and the diag command-line tool.

// NOTE: This mojom should be kept in sync with the copy in ChromiumOS repo in
// src/platform2/diagnostics/mojom/public/cros_healthd_routines.mojom.
module ash.cros_healthd.mojom;

import "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_exception.mojom";
import "mojo/public/mojom/base/time.mojom";
import "mojo/public/mojom/base/uuid.mojom";

// Routines interface exposed by the cros_healthd daemon.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
interface CrosHealthdRoutinesService {
  // Requests that a routine using the RoutineControl API is created on the
  // platform. This function creates a different routine based on the
  // RoutineArgument supplied.
  //
  // Error Handling:
  // This method will result in the creation of the routine on the device, which
  // might require allocation of additional resources and checking preconditions
  // for the routine, e.g. available hardware, correct arguments, etc.
  //
  // All exceptions that occur (either during initialization or while executing
  // the routine) will close the connection to the provided RoutineControl with
  // a specific reason (see cros_healthd.mojom.Exception) and a string message
  // containing human readable information about the exception.
  // For that reason it is necessary to always setup a disconnect handler on the
  // RoutineControl remote to be informed about potential exceptions.
  //
  // Please note exceptions are different from a routine reporting `has_passed
  // == false` (in case it failed, see RoutineStateFinished). Exception are
  // something not intended to happen. The details of the reasons for Exceptions
  // can be found in cros_healthd.mojom.Exception type and the corresponding
  // reason enum.
  //
  // To know if an exception occurs during the initialization, callers can wait
  // for the routine being initialized (get via `GetState` or RoutineObserver)
  // on the RoutineControl remote, before calling the `Start` method.
  //
  // The request:
  // * |routine_argument| - a RoutineArgument type that provides all the
  //                        necessary parameters and configs to create a
  //                        particular type of routine.
  // * |routine_receiver| - a receiver that will be bound to the actual routine
  //                        control implementation, where the remote will be
  //                        held by the client for starting the routine.
  //
  // * |routine_observer| - an optional observer to receive status updates about
  //                        changing routine states.
  CreateRoutine@0(RoutineArgument routine_argument,
                  pending_receiver<RoutineControl> routine_receiver,
                  pending_remote<RoutineObserver>? routine_observer);

  // Checks whether a given `RoutineArgument` is supported.
  //
  // The request:
  // * |routine_argument| - a `RoutineArgument` type that provides all the
  //                        necessary parameters to create a particular type of
  //                        routine.
  //
  // The response:
  // * |status| - See the documentation of `SupportStatus`.
  IsRoutineArgumentSupported@1(RoutineArgument routine_argument)
      => (SupportStatus status);
};

// Argument types for the possible routines the routine control API can create.
//
// NextMinVersion: 5, NextIndex: 23
[Stable, Extensible]
union RoutineArgument {
  // Default field is required by extensible unions for backward compatibility.
  // Any unrecognized Mojo field will deserialize to this field. Don't use this.
  [Default]
  bool unrecognizedArgument@0;
  // Arguments to create a memory routine.
  MemoryRoutineArgument memory@1;
  // Arguments to create a volume button routine.
  VolumeButtonRoutineArgument volume_button@2;
  // Arguments to create a fan routine.
  FanRoutineArgument fan@3;
  // Arguments to create an audio driver malfunction test routine.
  AudioDriverRoutineArgument audio_driver@4;
  // Arguments to create a CPU stress routine.
  CpuStressRoutineArgument cpu_stress@5;
  // Arguments to create a UFS lifetime routine.
  UfsLifetimeRoutineArgument ufs_lifetime@6;
  // Arguments to create a disk read routine.
  DiskReadRoutineArgument disk_read@7;
  // Arguments to create a CPU cache routine.
  CpuCacheRoutineArgument cpu_cache@8;
  // Arguments to create a prime search routine.
  PrimeSearchRoutineArgument prime_search@9;
  // Arguments to create a LED lit up routine.
  LedLitUpRoutineArgument led_lit_up@10;
  // Arguments to create a floating point routine.
  FloatingPointRoutineArgument floating_point@11;
  // Arguments to create a Bluetooth power routine.
  BluetoothPowerRoutineArgument bluetooth_power@12;
  // Arguments to create a Bluetooth discovery routine.
  BluetoothDiscoveryRoutineArgument bluetooth_discovery@13;
  // Arguments to create a Bluetooth scanning routine.
  BluetoothScanningRoutineArgument bluetooth_scanning@14;
  // Arguments to create a Bluetooth pairing routine.
  BluetoothPairingRoutineArgument bluetooth_pairing@15;
  // Arguments to create a camera availability routine.
  CameraAvailabilityRoutineArgument camera_availability@16;
  // Arguments to create a urandom routine.
  UrandomRoutineArgument urandom@17;
  // Arguments to create a network bandwidth routine.
  NetworkBandwidthRoutineArgument network_bandwidth@18;
  // Arguments to create a sensitive sensor routine.
  [MinVersion=1]
  SensitiveSensorRoutineArgument sensitive_sensor@19;
  // Arguments to create a camera frame analysis routine.
  [MinVersion=2]
  CameraFrameAnalysisRoutineArgument camera_frame_analysis@20;
  // Arguments to create a battery discharge routine.
  [MinVersion=3]
  BatteryDischargeRoutineArgument battery_discharge@21;
  // Arguments to create a keyboard backlight routine.
  [MinVersion=4]
  KeyboardBacklightRoutineArgument keyboard_backlight@22;
};

// This routine checks whether there is any memory problem by reading/writing
// different patterns.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct MemoryRoutineArgument {
  // An optional field to indicate how much memory should be tested. If the
  // value is null, memory test will run with as much memory as possible.
  uint32? max_testing_mem_kib@0;
};

// |AudioDriverRoutineArgument| is the argument struct to create the audio
// driver malfunction test routine by calling |CreateRoutine|. There is no input
// parameters so the struct remains empty.
//
// The routine checks the health of audio driver. It contains the following
// examinations:
// - CRAS can detect at least one internal audio card.
// - No audio devices failed to open.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct AudioDriverRoutineArgument {};

// This routine checks whether there is any CPU problem by stress testing the
// CPU.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct CpuStressRoutineArgument {
  // |exec_duration| determines how long the stressapptest binary will run. If
  // the provided value is null, default to running for 1 minute. The duration
  // is rounded to the nearest seconds towards zero (see behaviour of
  // std::trunc()).
  mojo_base.mojom.TimeDelta? exec_duration@0;
};

// This routine checks the UFS drive's life time.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct UfsLifetimeRoutineArgument {};

// The routine will create a test file with md5 checksum, read the test file
// either randomly or linearly, repeatedly for a dedicated duration. If the md5
// checksum of read back is validated, then the test will pass.
//
// NextMinVersion: 1, NextIndex: 3
[Stable]
struct DiskReadRoutineArgument {
  // Type of how disk reading is performed, either linear or random.
  DiskReadTypeEnum type@0;
  // Expected duration to read the test file in the DiskRead routine, which will
  // be rounded towards zero to the nearest second. This parameter should be
  // strictly greater than zero.
  mojo_base.mojom.TimeDelta disk_read_duration@1;
  // Test file size, in megabytes (MiB), to test with DiskRead routine
  uint32 file_size_mib@2;
};

// This routine checks whether there is any CPU cache problem by running a CPU
// cache coherency test.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct CpuCacheRoutineArgument {
  // |exec_duration| determines how long the stressapptest binary will run. If
  // the provided value is null, default to running for 1 minute. The duration
  // is rounded to the nearest seconds towards zero (see behaviour of
  // std::trunc()).
  mojo_base.mojom.TimeDelta? exec_duration@0;
};

// This routine checks whether there is any CPU problem by repeatedly
// calculating prime numbers.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct PrimeSearchRoutineArgument {
  // |exec_duration| determines how long the prime search test will run. If the
  // provided value is null, default to running for 1 minute. If the value is
  // less than 1 second, run for 1 second.
  mojo_base.mojom.TimeDelta? exec_duration@0;
};

// This routine checks the functionality of the volume button. The routine
// passes if the specified volume button event is received before the timeout.
// Otherwise, the routine fails.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct VolumeButtonRoutineArgument {
  [Stable, Extensible]
  enum ButtonType {
    // The default value is for backward compatibility, should not be used.
    [Default] kUnmappedEnumField = 0,
    // Test for the volume up button.
    kVolumeUp = 1,
    // Test for the volume down button.
    kVolumeDown = 2,
  };
  // The type of volume button to test.
  ButtonType type@0;
  // Length of time to listen to the volume button events. The timeout should be
  // positive and less or equal to 600 seconds.
  mojo_base.mojom.TimeDelta timeout@1;
};

// The routine lights up the target LED in the specified color and requests the
// caller to verify the change.
//
// This routine is supported if and only if the device has a ChromeOS EC.
//
// When an LED name or LED color is not supported by the EC, it will cause a
// routine exception (by closing the connection of `RoutineControl`) at runtime.
// TODO(b/319047040): add per-LED-name and per-LED-color supported check.
//
// The routine proceeds with the following steps:
// 1. Set the specified LED with the specified color and enter the waiting state
//    with the `CheckLedLitUpStateInquiry` interaction request.
// 2. After receiving `CheckLedLitUpStateReply` with the observed LED state, the
//    color of the LED will be reset (back to auto control). Notice that there
//    is no timeout so the routine will be in the waiting state indefinitely.
// 3. The routine passes if the LED is lit up in the correct color. Otherwise,
//    the routine fails.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct LedLitUpRoutineArgument {
  // The LED to be lit up.
  LedName name@0;
  // The color to be lit up.
  LedColor color@1;
};

// This routine checks whether the keyboard backlight can be lit up at any
// brightness level.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct KeyboardBacklightRoutineArgument {};

// This routine checks whether there is any CPU problem by repeatedly
// calculating floating point values.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct FloatingPointRoutineArgument {
  // `exec_duration` determines how long the prime search test will run. If the
  // provided value is null, default to running for 1 minute. If the value is
  // less than 1 second, run for 1 second.
  mojo_base.mojom.TimeDelta? exec_duration@0;
};

// This routine checks whether the Bluetooth adapter can be powered off/on and
// the powered status is consistent in both HCI and D-Bus levels.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct BluetoothPowerRoutineArgument {};

// This routine checks whether the Bluetooth adapter can start/stop discovery
// mode and the discovering status is consistent in both HCI and D-Bus levels.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct BluetoothDiscoveryRoutineArgument {};

// This routine checks whether the fan is controllable.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct FanRoutineArgument {};

// This routine checks whether the Bluetooth adapter can scan nearby Bluetooth
// peripherals and collect peripherals' information.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct BluetoothScanningRoutineArgument {
  // `exec_duration` determines how long the scanning routine will run. This
  // parameter needs to be strictly greater than zero, otherwise the routine
  // will fail with an exception. If the provided value is null, default to
  // running for 5 seconds.
  mojo_base.mojom.TimeDelta? exec_duration@0;
};

// This routine checks whether the adapter can find and pair with a device with
// a specific peripheral id.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct BluetoothPairingRoutineArgument {
  // The unique id of the target peripheral device to test, which can be
  // obtained from `BluetoothScanningRoutineDetail`.
  string peripheral_id@0;
};

// This routine checks the availability of services related to cameras.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct CameraAvailabilityRoutineArgument {
  // Whether to check the availability of the camera service.
  bool run_camera_service_available_check@0;
  // Whether to check the availability of the camera diagnostic service.
  bool run_camera_diagnostic_service_available_check@1;
};

// This routine checks whether there is any CPU problem by repeatedly
// reading from urandom.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct UrandomRoutineArgument {
  // `exec_duration` determines how long the prime search test will run. If the
  // provided value is null, default to running for 1 minute. If the value is
  // less than 1 second, run for 1 second.
  mojo_base.mojom.TimeDelta? exec_duration@0;
};

// This routine checks the network bandwidth and reports the speed info.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct NetworkBandwidthRoutineArgument {};

// This routine checks that the device's sensors are working correctly by
// monitoring the sensor sample data without user interaction. This routine only
// support sensitive sensors including accelerometers, gyro sensors,
// magnetometers and gravity sensors.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct SensitiveSensorRoutineArgument {};

// This routine checks the frames captured by camera. The frontend should ensure
// the camera is opened during the execution of the routine.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct CameraFrameAnalysisRoutineArgument {};

// This routine checks that the battery discharge rate does not exceed a certain
// percent within a given timeframe. Clients should unplug the AC adapter and
// report done via `UnplugAcAdapterReply`.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct BatteryDischargeRoutineArgument {
  // The length of time this routine is expected to run.
  mojo_base.mojom.TimeDelta exec_duration@0;
  // The maximum change in battery percent allowed for the routine to pass,
  // values should range in [0, 100].
  uint8 maximum_discharge_percent_allowed@1;
};

// Interface exposed to clients for controlling a routine.
//
// Error Handling:
// Please check the Error Handling section of CrosHealthdRoutinesService.
//
// NextMinVersion: 3, NextIndex: 3
[Stable]
interface RoutineControl {
  // Gets the current state of the routine. Note that if the routine fails to
  // initialize, the RoutineControl will disconnect before the callback is
  // called.
  [MinVersion=1]
  GetState@0() => (RoutineState state);

  // Starts the routine. Each routine can only be started once. Calling this
  // method multiple times results in no-ops.
  //
  // See the error handling section above to know how to handle possible
  // exceptions that occur before and after the routine has been started.
  [MinVersion=1]
  Start@1();

  // Reply to the routine inquiry requested in the waiting state. The routine
  // will raise an exception (by closing the connection of this
  // `RoutineControl`) if the routine is not in the waiting state or the reply
  // does not match the inquiry in the waiting state (see
  // `RoutineStateWaiting`).
  [MinVersion=2]
  ReplyInquiry@2(RoutineInquiryReply reply);
};

// Implemented by clients who desire routine update notifications.
//
// NextMinVersion: 2, NextIndex: 1
[Stable]
interface RoutineObserver {
  // Called when the routine state has changed. This is also called as soon
  // as a routine is initialized (right after calling `CreateRoutine`).
  // Note that if the routine fails to initialize, the RoutineControl may
  // disconnect before the first invocation of this observer method.
  [MinVersion=1]
  OnRoutineStateChange@0(RoutineState state);
};

// Used to pass information regarding routine state.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct RoutineState {
  // The percentage of the completion of the routine. 0 to 100.
  uint8 percentage@0;

  RoutineStateUnion state_union@1;
};

// Possible routine states.
//
// NextMinVersion: 1, NextIndex: 4
[Stable]
union RoutineStateUnion {
  // Default field is required by extensible unions for backward compatibility.
  // Any unrecognized Mojo field will deserialize to this field. Don't use this.
  [Default]
  bool unrecognizedArgument@0;
  // Routine has been initialized but not yet started.
  RoutineStateInitialized initialized@1;
  // Routine is running.
  RoutineStateRunning running@2;
  // Routine is waiting for something.
  RoutineStateWaiting waiting@3;
  // Routine has finished.
  RoutineStateFinished finished@4;
};

// Routine has been initialized but not yet started.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct RoutineStateInitialized {};

// Routine is currently running.
//
// NextMinVersion: 2, NextIndex: 1
[Stable]
struct RoutineStateRunning {
  [MinVersion=1]
  RoutineRunningInfo? info@0;
};

// Routine running info. Note that not every routine provides info during the
// running state.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
union RoutineRunningInfo {
  // Default field is required by extensible unions for backward compatibility.
  // Any unrecognized Mojo field will deserialize to this field. Don't use this.
  [Default]
  bool unrecognizedArgument@0;
  // Running info of network bandwidth routine.
  NetworkBandwidthRoutineRunningInfo network_bandwidth@1;
};

// Running info regarding network bandwidth routine.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct NetworkBandwidthRoutineRunningInfo {
  // The type of test that routine is running.
  //
  // NextMinVersion: 1, NextIndex: 3
  [Stable, Extensible]
  enum Type {
    [Default] kUnmappedEnumField = 0,
    // Routine is running download test.
    kDownload = 1,
    // Routine is running upload test.
    kUpload = 2,
  };
  Type type@0;

  // The current network speed in kbit/s.
  double speed_kbps@1;
};

// Routine is currently waiting.
//
// NextMinVersion: 2, NextIndex: 3
[Stable]
struct RoutineStateWaiting {
  // The reason why the routine waits.
  //
  // NextMinVersion: 1, NextIndex: 3
  [Stable, Extensible]
  enum Reason {
    [Default] kUnmappedEnumField = 0,
    // Waiting for the job to be scheduled for running.
    kWaitingToBeScheduled = 1,
    // Waiting for an interaction. Check `interaction` to learn about which
    // interaction is requested.
    kWaitingInteraction = 2,
  };
  // Reason why the routine waits.
  Reason reason@0;
  // Additional information, may be used to pass instruction or explanation.
  string message@1;
  // The requested interaction. This field is set if and only if `reason` is
  // kWaitingInteraction. When set, clients must respond to the interaction for
  // the routine to proceed.
  [MinVersion=1]
  RoutineInteraction? interaction@2;
};

// An interaction that is requested by a routine in the waiting state. See the
// comments on the subtypes to learn how to respond to each interaction request.
//
// Note: this union type contains only one field (apart from the unrecognized
// one) because all interactions currently need to be replied. Another type
// `RoutineTask` should be added when there are interactions that do not need to
// be replied.
//
// NextMinVersion: 1, NextIndex: 2
[Stable, Extensible]
union RoutineInteraction {
  // Default field is required by extensible unions for backward compatibility.
  // Any unrecognized Mojo field will deserialize to this field. Don't use this.
  [Default]
  bool unrecognizedInteraction@0;
  // An interaction that needs to be replied using `ReplyInquiry`.
  RoutineInquiry inquiry@1;
};

// An interaction that has to be replied. Each inquiry type has a corresponding
// reply type in `RoutineInquiryReply`. Clients should call the `ReplyInquiry`
// method of `RoutineControl` with the corresponding reply type.
//
// NextMinVersion: 3, NextIndex: 4
[Stable, Extensible]
union RoutineInquiry {
  // Default field is required by extensible unions for backward compatibility.
  // Any unrecognized Mojo field will deserialize to this field. Don't use this.
  [Default]
  bool unrecognizedInquiry@0;
  // Details of the inquiry to check the LED lit up state.
  CheckLedLitUpStateInquiry check_led_lit_up_state@1;
  // Details of the inquiry to unplug AC adapter.
  [MinVersion=1]
  UnplugAcAdapterInquiry unplug_ac_adapter_inquiry@2;
  // Details of the inquiry to check the keyboard backlight LED state.
  [MinVersion=2]
  CheckKeyboardBacklightStateInquiry check_keyboard_backlight_state@3;
};

// Details to reply to a routine inquiry.
//
// NextMinVersion: 3, NextIndex: 4
[Stable, Extensible]
union RoutineInquiryReply {
  // Default field is required by extensible unions for backward compatibility.
  // Any unrecognized Mojo field will deserialize to this field. Don't use this.
  [Default]
  bool unrecognizedReply@0;
  // Details to resume a routine requesting to check the LED lit up state.
  CheckLedLitUpStateReply check_led_lit_up_state@1;
  // Details to resume a routine requesting to unplug the AC adapter.
  [MinVersion=1]
  UnplugAcAdapterReply unplug_ac_adapter@2;
  // Details to resume a routine requesting to check the keyboard backlight LED
  // state.
  [MinVersion=2]
  CheckKeyboardBacklightStateReply check_keyboard_backlight_state@3;
};

// Details regarding the inquiry to check the LED lit up state. Clients should
// inspect the target LED and report its state using `CheckLedLitUpStateReply`.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct CheckLedLitUpStateInquiry {};

// Details to reply to a routine requesting to check the LED lit up state.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct CheckLedLitUpStateReply {
  // State of the target LED.
  //
  // NextMinVersion: 1, NextIndex: 3
  [Stable, Extensible]
  enum State {
    // The default value is for backward compatibility, should not be used.
    [Default] kUnmappedEnumField = 0,
    // The LED is lit up with the correct color.
    kCorrectColor = 1,
    // The LED is not lit up with the correct color.
    kNotLitUp = 2,
  };
  State state@0;
};

// Details regarding the inquiry to unplug the AC adapter. Clients should unplug
// the AC adapter and reply using `UnplugAcAdapterReply`.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct UnplugAcAdapterInquiry {};

// Details to reply to a routine requesting to unplug the AC adapter.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct UnplugAcAdapterReply {};

// Details regarding the inquiry to check the keyboard backlight lit up state.
// Clients should inspect the keyboard backlight and report its state using
// `CheckKeyboardBacklightStateReply`.
//
// NextMinVersion: 1, NextIndex: 0
[Stable]
struct CheckKeyboardBacklightStateInquiry {};

// Details to reply to a routine requesting to check if all the LEDs on the
// keyboard backlight lit up.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct CheckKeyboardBacklightStateReply {
  // State of the keyboard backlight LED.
  //
  // NextMinVersion: 1, NextIndex: 3
  [Stable, Extensible]
  enum State {
    // The default value is for backward compatibility, should not be used.
    [Default] kUnmappedEnumField = 0,
    // All keyboard backlight LEDs are lit up.
    kOk = 1,
    // Any of the keyboard backlight LED is not lit up.
    kAnyNotLitUp = 2,
  };
  State state@0;
};

// Information about a finished routine.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct RoutineStateFinished {
  // Whether the routine has passed or not.
  bool has_passed@0;
  // The details of the routine.
  RoutineDetail? detail@1;
};

// Details about a finished routine.
//
// NextMinVersion: 5, NextIndex: 14
[Stable, Extensible]
union RoutineDetail {
  // Default field is required by extensible unions for backward compatibility.
  // Any unrecognized Mojo field will deserialize to this field. Don't use this.
  [Default]
  bool unrecognizedArgument@0;
  // Details of a completed memory routine.
  MemoryRoutineDetail memory@1;
  // Details of a completed fan routine.
  FanRoutineDetail fan@2;
  // Details of a completed audio driver routine.
  AudioDriverRoutineDetail audio_driver@3;
  // Details of a completed UFS lifetime routine.
  UfsLifetimeRoutineDetail ufs_lifetime@4;
  // Details of a completed Bluetooth power routine.
  BluetoothPowerRoutineDetail bluetooth_power@5;
  // Details of a completed Bluetooth discovery routine.
  BluetoothDiscoveryRoutineDetail bluetooth_discovery@6;
  // Details of a completed Bluetooth scanning routine.
  BluetoothScanningRoutineDetail bluetooth_scanning@7;
  // Details of a completed Bluetooth pairing routine.
  BluetoothPairingRoutineDetail bluetooth_pairing@8;
  // Details of a completed camera availability routine.
  CameraAvailabilityRoutineDetail camera_availability@9;
  // Details of a completed network bandwidth routine.
  [MinVersion=1]
  NetworkBandwidthRoutineDetail network_bandwidth@10;
  // Details of a completed sensitive sensor routine.
  [MinVersion=2]
  SensitiveSensorRoutineDetail sensitive_sensor@11;
  // Details of a completed camera frame analysis routine.
  [MinVersion=3]
  CameraFrameAnalysisRoutineDetail camera_frame_analysis@12;
  // Details of a completed battery discharge routine.
  [MinVersion=4]
  BatteryDischargeRoutineDetail battery_discharge@13;
};

// Details regarding memory routine.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct MemoryRoutineDetail {
  // Number of bytes tested in the memory routine.
  uint64 bytes_tested@0;
  // Contains the memtester test results.
  MemtesterResult result@1;
};

// Details regarding audio driver routine.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct AudioDriverRoutineDetail {
  // Whether or not the routine can detect an internal audio card.
  bool internal_card_detected@0;
  // Whether or not all audio devices succeed to open.
  bool audio_devices_succeed_to_open@1;
};

// Details regarding UFS lifetime routine.
//
// NextMinVersion: 1, NextIndex: 3
[Stable]
struct UfsLifetimeRoutineDetail {
  // Pre-end of life information.
  uint8 pre_eol_info@0;
  // Device life time estimation (type A).
  uint8 device_life_time_est_a@1;
  // Device life time estimation (type B).
  uint8 device_life_time_est_b@2;
};

// Enumeration of each possible memtester test item.
//
// NextMinVersion: 1, NextIndex: 20
[Stable, Extensible]
enum MemtesterTestItemEnum {
  [Default] kUnmappedEnumField = 0,
  // The memtester test is not recognized.
  kUnknown = 1,

  // Test that all memory addresses to be tested can be set to itself and its
  // complement.
  kStuckAddress = 2,

  // These tests test different operation of a random int64 with buffer
  // initialized as 0xFFFFFFFF, repeating over 64 bit blocks.
  // Perform AND operation.
  kCompareAND = 3,
  // Perform DIV operation.
  kCompareDIV = 4,
  // Perform MUL operation.
  kCompareMUL = 5,
  // Perform OR operation.
  kCompareOR = 6,
  // Perform SUB operation.
  kCompareSUB = 7,
  // Perform XOR operation.
  kCompareXOR = 8,
  // Perform ADD operation.
  kSequentialIncrement = 9,

  // These tests test setting memory regions in a certain pattern, repeating
  // over each 64 bit blocks.
  // Test Pattern: |0*10*| and |1*01*|.
  kBitFlip = 10,
  // Test Pattern:|0*1010*| and |1*0101*|.
  kBitSpread = 11,
  // Test Pattern: all 256 possible combinations of a 8 bit block, repeated 8
  // times.
  kBlockSequential = 12,
  // Test Pattern: Alternating 0 and 1.
  kCheckerboard = 13,
  // Test Pattern: Random 64 bits.
  kRandomValue = 14,
  // Test Pattern: all 0s and all 1s.
  kSolidBits = 15,
  // Test Pattern: |0*10*|.
  kWalkingOnes = 16,
  // Test Pattern: |1*01*|.
  kWalkingZeroes = 17,

  // These tests test writing random n bit words across the memory regions.
  // Test Pattern: 8 bit random words.
  k8BitWrites = 18,
  // Test Pattern: 16 bit random words.
  k16BitWrites = 19,
};

// Result from running memtester.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct MemtesterResult {
  // Tests that have passed.
  array<MemtesterTestItemEnum> passed_items@0;
  // Tests that have failed.
  array<MemtesterTestItemEnum> failed_items@1;
};

// Details regarding Bluetooth powered state.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct BluetoothPoweredDetail {
  // Bluetooth powered state in HCI level.
  bool hci_powered@0;
  // Bluetooth powered state in D-Bus level.
  bool dbus_powered@1;
};

// Details regarding Bluetooth power routine.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct BluetoothPowerRoutineDetail {
  // Result of powering off Bluetooth adapter, or null if error occurs.
  BluetoothPoweredDetail? power_off_result@0;
  // Result of powering on Bluetooth adapter, or null if error occurs.
  BluetoothPoweredDetail? power_on_result@1;
};

// Details regarding Bluetooth discovering state.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct BluetoothDiscoveringDetail {
  // Bluetooth discovering state in HCI level.
  bool hci_discovering@0;
  // Bluetooth discovering state in D-Bus level.
  bool dbus_discovering@1;
};

// Details regarding Bluetooth discovery routine.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct BluetoothDiscoveryRoutineDetail {
  // Result of starting discovery, or null if error occurs.
  BluetoothDiscoveringDetail? start_discovery_result@0;
  // Result of stopping discovery, or null if error occurs.
  BluetoothDiscoveringDetail? stop_discovery_result@1;
};

// Details regarding the scanned peripheral.
//
// NextMinVersion: 2, NextIndex: 4
[Stable]
struct BluetoothScannedPeripheralInfo {
  // All collected RSSI during the routine.
  array<int16> rssi_history@0;
  // The readable name of peripheral, which is reported when the average RSSI is
  // higher than -60.
  string? name@1;
  // The unique id of peripheral, which is reported when the average RSSI is
  // higher than -60.
  string? peripheral_id@2;
  // The list of available services of peripheral, which is reported when the
  // average RSSI is higher than -60.
  [MinVersion=1]
  array<mojo_base.mojom.Uuid>? uuids@3;
};

// Details regarding Bluetooth scanning routine.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct BluetoothScanningRoutineDetail {
  // Scanned nearby peripheral info.
  array<BluetoothScannedPeripheralInfo> peripherals@0;
};

// Details regarding the scanned peripheral for pairing routine.
//
// NextMinVersion: 1, NextIndex: 7
[Stable]
struct BluetoothPairingPeripheralInfo {
  // The error which is reported when the routine fails to finish pairing.
  //
  // NextMinVersion: 1, NextIndex: 6
  [Stable, Extensible]
  enum PairError {
    // The default value is for backward compatibility, should not be used.
    [Default] kUnmappedEnumField = 0,
    // No error.
    kNone = 1,
    // Fails to start creating bond.
    kBondFailed = 2,
    // Gets bad status when creating bond.
    kBadStatus = 3,
    // Fails to handle Secure Simple Pairing request.
    kSspFailed = 4,
    // Timeout.
    kTimeout = 5,
  };
  PairError pair_error@0;

  // The error which is reported when the routine fails to establish a baseband
  // connection when creating bond.
  //
  // NextMinVersion: 1, NextIndex: 4
  [Stable, Extensible]
  enum ConnectError {
    // The default value is for backward compatibility, should not be used.
    [Default] kUnmappedEnumField = 0,
    // No error.
    kNone = 1,
    // Unable to receive connected event.
    kNoConnectedEvent = 2,
    // Connection state is not accessed successfully or `not connected`.
    kNotConnected = 3,
  };
  ConnectError connect_error@1;

  // The list of available services of peripheral.
  array<mojo_base.mojom.Uuid> uuids@2;
  // The Bluetooth class of device (CoD) of peripheral.
  uint32? bluetooth_class@3;

  // The address type of peripheral.
  //
  // NextMinVersion: 1, NextIndex: 4
  [Stable, Extensible]
  enum AddressType {
    // The default value is for backward compatibility, should not be used.
    [Default] kUnmappedEnumField = 0,
    // Unknown.
    kUnknown = 1,
    // Public address type.
    kPublic = 2,
    // Random address type.
    kRandom = 3,
  };
  AddressType address_type@4;
  // The result of peripheral address check.
  bool is_address_valid@5;
  // The first half of Bluetooth address, in the format XX:XX:XX (X: [0-9A-F]).
  // It is reported when `is_address_valid` is false, `address_type` is not
  // unknown and the address can be parsed successfully.
  string? failed_manufacturer_id@6;
};

// Details regarding Bluetooth pairing routine.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct BluetoothPairingRoutineDetail {
  // The info for the test peripheral, or null if the routine fails to find the
  // peripheral.
  BluetoothPairingPeripheralInfo? pairing_peripheral@0;
};

// All possible results for subtests of camera routines.
//
// NextMinVersion: 1, NextIndex: 4
[Stable, Extensible]
enum CameraSubtestResult {
  // The default value is for backward compatibility, should not be used.
  [Default] kUnmappedEnumField = 0,
  // The subtest was not run, possibly because the subtest was not enabled in
  // the routine parameter or the subtest was not available on the device.
  kNotRun = 1,
  // The subtest was passed.
  kPassed = 2,
  // The subtest was failed.
  kFailed = 3,
};

// Details regarding camera availability routine.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct CameraAvailabilityRoutineDetail {
  // The subtest is passed if the camera service is available.
  CameraSubtestResult camera_service_available_check@0;
  // The subtest is passed if the camera diagnostic service is available. This
  // subtest is informational, which means its result does not affect the passed
  // or failed state of the main routine.
  CameraSubtestResult camera_diagnostic_service_available_check@1;
};

// Details regarding battery discharge routine.
//
// NextMinVersion: 1, NextIndex: 1
[Stable]
struct BatteryDischargeRoutineDetail {
  // The number of battery percent dropped in the routine's timeframe, range in
  // [0, 100].
  double discharge_percent@0;
};

// Enumeration of the possible DiskRead routine's command type.
//
// NextMinVersion: 1, NextIndex: 3
[Stable, Extensible]
enum DiskReadTypeEnum {
  // This is required for backwards compatibility, should not be used.
  [Default] kUnmappedEnumField = 0,
  kLinearRead = 1,
  kRandomRead = 2,
};

// Enumeration of each possible LEDs on a device. This enum type is a mirror of
// the enums defined in EC. To find out the actual names of each installed LEDs,
// please refer to the EC firmware.
//
// NextMinVersion: 1, NextIndex: 6
[Stable, Extensible]
enum LedName {
  // The default value is for backward compatibility, should not be used.
  [Default] kUnmappedEnumField = 0,
  kBattery = 1,
  kPower = 2,
  kAdapter = 3,
  kLeft = 4,
  kRight = 5,
};

// Enumeration of each possible LED colors.
//
// NextMinVersion: 1, NextIndex: 7
[Stable, Extensible]
enum LedColor {
  // The default value is for backward compatibility, should not be used.
  [Default] kUnmappedEnumField = 0,
  kRed = 1,
  kGreen = 2,
  kBlue = 3,
  kYellow = 4,
  kWhite = 5,
  kAmber = 6,
};

// Whether the given hardware probed matches the hardware description recorded.
//
// NextMinVersion: 1, NextIndex: 4
[Stable, Extensible]
enum HardwarePresenceStatus {
  // The default value is for backward compatibility, should not be used.
  [Default] kUnmappedEnumField = 0,
  // The hardware presence matches the description.
  kMatched = 1,
  // The hardware presence does not match the description.
  kNotMatched = 2,
  // There is no description available, skipping check.
  kNotConfigured = 3,
};

// Details regarding fan routine.
//
// NextMinVersion: 1, NextIndex: 3
[Stable]
struct FanRoutineDetail {
  // The ids of fans that can be controlled.
  array<uint8> passed_fan_ids@0;
  // The ids of fans that cannot be controlled.
  array<uint8> failed_fan_ids@1;
  // Whether the number of fan probed is matched.
  HardwarePresenceStatus fan_count_status@2;
};

// Details regarding network bandwidth routine.
//
// NextMinVersion: 1, NextIndex: 2
[Stable]
struct NetworkBandwidthRoutineDetail {
  // Average download speed in kbit/s.
  double download_speed_kbps@0;
  // Average upload speed in kbit/s.
  double upload_speed_kbps@1;
};

// The info of single sensor tested in sensitive sensor routine.
//
// NextMinVersion: 1, NextIndex: 3
[Stable]
struct SensitiveSensorInfo {
  // Sensor ID from Iioservice.
  int32 id@0;

  // The sensor types supported by the sensitive sensor routine.
  //
  // NextMinVersion: 1, NextIndex: 5
  [Stable, Extensible]
  enum Type {
    // For mojo backward compatibility, should not be used.
    [Default] kUnmappedEnumField = 0,
    // Accelerometer.
    kAccel = 1,
    // Angular velocity sensor, also known as gyro sensor.
    kGyro = 2,
    // Magnetometer.
    kMagn = 3,
    // Gravity sensor.
    kGravity = 4,
  };
  array<Type> types@1;

  // The sensor channels checked by the sensitive sensor routine. Returns empty
  // array if the channels are not collected successfully.
  array<string> channels@2;
};

// The result of a sensor type in certain location (base or lid) tested in
// sensitive sensor routine. For example: the result of base gyro sensors or lid
// accelerometers.
//
// NextMinVersion: 1, NextIndex: 3
[Stable]
struct SensitiveSensorReport {
  // The info of sensors passed routine.
  array<SensitiveSensorInfo> passed_sensors@0;
  // The info of sensors failed routine.
  array<SensitiveSensorInfo> failed_sensors@1;
  // The status of the sensors presence.
  HardwarePresenceStatus sensor_presence_status@2;
};

// Details regarding sensitive sensor routine.
//
// NextMinVersion: 1, NextIndex: 8
[Stable]
struct SensitiveSensorRoutineDetail {
  // Report of base accelerometer.
  SensitiveSensorReport base_accelerometer@0;
  // Report of lid accelerometer.
  SensitiveSensorReport lid_accelerometer@1;
  // Report of base gyroscope.
  SensitiveSensorReport base_gyroscope@2;
  // Report of lid gyroscope.
  SensitiveSensorReport lid_gyroscope@3;
  // Report of base magnetometer.
  SensitiveSensorReport base_magnetometer@4;
  // Report of lid magnetometer.
  SensitiveSensorReport lid_magnetometer@5;
  // Report of base gravity sensor.
  SensitiveSensorReport base_gravity_sensor@6;
  // Report of lid gravity sensor.
  SensitiveSensorReport lid_gravity_sensor@7;
};

// Details regarding camera frame analysis routine.
//
// NextMinVersion: 1, NextIndex: 3
[Stable]
struct CameraFrameAnalysisRoutineDetail {
  // The issue caught by the routine. See the fields for each subtest for their
  // details.
  //
  // NextMinVersion: 1, NextIndex: 5
  [Stable, Extensible]
  enum Issue {
    // For mojo backward compatibility, should not be used.
    [Default] kUnmappedEnumField = 0,
    // No issue.
    kNone = 1,
    // The camera service is not available.
    kCameraServiceNotAvailable = 2,
    // The len is blocked by the privacy shutter.
    kBlockedByPrivacyShutter = 3,
    // The frames are blurred. Lens might be dirty.
    kLensAreDirty = 4,
  };
  Issue issue@0;
  // The result is `kFailed` if the len is blocked by the privacy shutter. To
  // mitigate the issue, users are suggested to open the privacy shutter to
  // unveil the len.
  CameraSubtestResult privacy_shutter_open_test@1;
  // The result is `kFailed` if the frames are blurred. To mitigate the issue,
  // users are suggested to clean the lens.
  CameraSubtestResult lens_not_dirty_test@2;
};