Commit 476ebf36 authored by Bailey Berro's avatar Bailey Berro Committed by Commit Bot

Create SystemRoutineController Mojo Interface

This change introduces the SystemRoutineController Mojo interface
which will be used by the Diagnostics SWA to run various diagnostic
routines. The first such routine is the CPU Stress Test.

An example of the CPU routines being called from the app can be seen
enumerated here[1] and executed here[2]

1- https://source.chromium.org/chromium/chromium/src/+/master:chromeos/components/diagnostics_ui/resources/cpu_card.js;drc=28198c08d1153532dbf1375412fc6fa42de320d7;l=37
2 -https://source.chromium.org/chromium/chromium/src/+/master:chromeos/components/diagnostics_ui/resources/routine_list_executor.js;l=88-118


Bug: 1128204
Change-Id: I3662f91d72e86b03e3b40436bbf7a0a9204351ea
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2457926
Commit-Queue: Bailey Berro <baileyberro@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarZentaro Kavanagh <zentaro@chromium.org>
Cr-Commit-Position: refs/heads/master@{#823339}
parent 32c0491a
......@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/strings/string_piece.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
namespace chromeos {
......@@ -21,6 +22,11 @@ using cros_healthd::mojom::CpuResultPtr;
using cros_healthd::mojom::MemoryInfo;
using cros_healthd::mojom::MemoryResult;
using cros_healthd::mojom::MemoryResultPtr;
using cros_healthd::mojom::NonInteractiveRoutineUpdate;
using cros_healthd::mojom::NonInteractiveRoutineUpdatePtr;
using cros_healthd::mojom::RoutineUpdate;
using cros_healthd::mojom::RoutineUpdateUnion;
using cros_healthd::mojom::RoutineUpdateUnionPtr;
using cros_healthd::mojom::SystemInfo;
using cros_healthd::mojom::SystemResult;
using cros_healthd::mojom::SystemResultPtr;
......@@ -88,5 +94,17 @@ const SystemInfo* GetSystemInfo(const TelemetryInfo& info) {
return system_result->get_system_info().get();
}
const NonInteractiveRoutineUpdate* GetNonInteractiveRoutineUpdate(
const RoutineUpdate& update) {
const RoutineUpdateUnionPtr& routine_update = update.routine_update_union;
switch (routine_update->which()) {
case RoutineUpdateUnion::Tag::INTERACTIVE_UPDATE:
return nullptr;
case RoutineUpdateUnion::Tag::NONINTERACTIVE_UPDATE:
return routine_update->get_noninteractive_update().get();
}
}
} // namespace diagnostics
} // namespace chromeos
......@@ -10,6 +10,8 @@ namespace mojom {
class BatteryInfo;
class CpuInfo;
class MemoryInfo;
class NonInteractiveRoutineUpdate;
class RoutineUpdate;
class SystemInfo;
class TelemetryInfo;
} // namespace mojom
......@@ -38,6 +40,10 @@ const cros_healthd::mojom::MemoryInfo* GetMemoryInfo(
const cros_healthd::mojom::SystemInfo* GetSystemInfo(
const cros_healthd::mojom::TelemetryInfo& info);
const cros_healthd::mojom::NonInteractiveRoutineUpdate*
GetNonInteractiveRoutineUpdate(
const cros_healthd::mojom::RoutineUpdate& update);
} // namespace diagnostics
} // namespace chromeos
......
......@@ -5,14 +5,194 @@
#include "chromeos/components/diagnostics_ui/backend/system_routine_controller.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromeos/components/diagnostics_ui/backend/cros_healthd_helpers.h"
#include "chromeos/services/cros_healthd/public/cpp/service_connection.h"
namespace chromeos {
namespace diagnostics {
namespace {
namespace healthd = cros_healthd::mojom;
constexpr uint32_t kCpuStressDurationInSeconds = 10;
constexpr uint32_t kRoutineResultRefreshIntervalInSeconds = 1;
mojom::RoutineResultInfoPtr ConstructStandardRoutineResultInfoPtr(
mojom::RoutineType type,
mojom::StandardRoutineResult result) {
auto routine_result = mojom::RoutineResult::NewSimpleResult(result);
return mojom::RoutineResultInfo::New(type, std::move(routine_result));
}
// Converts a cros_healthd::mojom::DiagnosticRoutineStatusEnum to a
// mojom::StandardRoutineResult. Should only be called to construct the final
// response. Should not be called for in-progess statuses.
mojom::StandardRoutineResult TestStatusToResult(
healthd::DiagnosticRoutineStatusEnum status) {
switch (status) {
case healthd::DiagnosticRoutineStatusEnum::kPassed:
return mojom::StandardRoutineResult::kTestPassed;
case healthd::DiagnosticRoutineStatusEnum::kFailed:
return mojom::StandardRoutineResult::kTestFailed;
case healthd::DiagnosticRoutineStatusEnum::kCancelled:
case healthd::DiagnosticRoutineStatusEnum::kError:
return mojom::StandardRoutineResult::kExecutionError;
case healthd::DiagnosticRoutineStatusEnum::kFailedToStart:
case healthd::DiagnosticRoutineStatusEnum::kUnsupported:
return mojom::StandardRoutineResult::kUnableToRun;
case healthd::DiagnosticRoutineStatusEnum::kReady:
case healthd::DiagnosticRoutineStatusEnum::kRunning:
case healthd::DiagnosticRoutineStatusEnum::kWaiting:
case healthd::DiagnosticRoutineStatusEnum::kRemoved:
case healthd::DiagnosticRoutineStatusEnum::kCancelling:
NOTREACHED();
return mojom::StandardRoutineResult::kExecutionError;
}
}
} // namespace
SystemRoutineController::SystemRoutineController() {
inflight_routine_timer_ = std::make_unique<base::OneShotTimer>();
}
SystemRoutineController::SystemRoutineController() = default;
SystemRoutineController::~SystemRoutineController() = default;
void SystemRoutineController::RunRoutine(
mojom::RoutineType type,
mojo::PendingRemote<mojom::RoutineRunner> runner) {
if (IsRoutineRunning()) {
// If a routine is already running, alert the caller that we were unable
// to start the routine.
mojo::Remote<mojom::RoutineRunner> routine_runner(std::move(runner));
auto result = ConstructStandardRoutineResultInfoPtr(
type, mojom::StandardRoutineResult::kUnableToRun);
routine_runner->OnRoutineResult(std::move(result));
return;
}
inflight_routine_runner_ =
mojo::Remote<mojom::RoutineRunner>(std::move(runner));
ExecuteRoutine(type);
}
void SystemRoutineController::ExecuteRoutine(mojom::RoutineType type) {
switch (type) {
case mojom::RoutineType::kCpuStress:
RunCpuStressRoutine();
return;
}
}
void SystemRoutineController::RunCpuStressRoutine() {
BindCrosHealthdDiagnosticsServiceIfNeccessary();
diagnostics_service_->RunCpuStressRoutine(
kCpuStressDurationInSeconds,
base::BindOnce(&SystemRoutineController::OnCpuStressRoutineStarted,
base::Unretained(this)));
}
void SystemRoutineController::OnCpuStressRoutineStarted(
healthd::RunRoutineResponsePtr response_ptr) {
// Check for error conditions.
// TODO(baileyberro): Handle additional statuses.
if (response_ptr->status ==
healthd::DiagnosticRoutineStatusEnum::kFailedToStart ||
response_ptr->id == healthd::kFailedToStartId) {
OnStandardRoutineResult(mojom::RoutineType::kCpuStress,
TestStatusToResult(response_ptr->status));
return;
}
DCHECK_EQ(healthd::DiagnosticRoutineStatusEnum::kRunning,
response_ptr->status);
const int32_t id = response_ptr->id;
// Sleep for the length of the test using a one-shot timer, then start
// querying again for status.
ScheduleCheckRoutineStatus(kCpuStressDurationInSeconds,
mojom::RoutineType::kCpuStress, id);
}
void SystemRoutineController::CheckRoutineStatus(
mojom::RoutineType routine_type,
int32_t id) {
BindCrosHealthdDiagnosticsServiceIfNeccessary();
diagnostics_service_->GetRoutineUpdate(
id, healthd::DiagnosticRoutineCommandEnum::kGetStatus,
/*include_output=*/false,
base::BindOnce(&SystemRoutineController::OnRoutineStatusUpdated,
base::Unretained(this), routine_type, id));
}
void SystemRoutineController::OnRoutineStatusUpdated(
mojom::RoutineType routine_type,
int32_t id,
healthd::RoutineUpdatePtr update_ptr) {
const healthd::NonInteractiveRoutineUpdate* update =
GetNonInteractiveRoutineUpdate(*update_ptr);
if (!update) {
DVLOG(2) << "Invalid routine update";
OnStandardRoutineResult(routine_type,
mojom::StandardRoutineResult::kExecutionError);
return;
}
const healthd::DiagnosticRoutineStatusEnum status = update->status;
// If still running, continue to repoll until it is finished.
// TODO(baileyberro): Consider adding a timeout mechanism.
if (status == healthd::DiagnosticRoutineStatusEnum::kRunning) {
ScheduleCheckRoutineStatus(kRoutineResultRefreshIntervalInSeconds,
routine_type, id);
return;
}
// If test passed, report result.
if (status == healthd::DiagnosticRoutineStatusEnum::kPassed) {
OnStandardRoutineResult(routine_type, TestStatusToResult(status));
return;
}
// If test failed, report result.
if (status == healthd::DiagnosticRoutineStatusEnum::kFailed) {
OnStandardRoutineResult(routine_type, TestStatusToResult(status));
return;
}
// Any other reason, report failure.
DVLOG(2) << "Routine failed: " << update->status_message;
OnStandardRoutineResult(routine_type, TestStatusToResult(status));
}
bool SystemRoutineController::IsRoutineRunning() const {
return inflight_routine_runner_.is_bound();
}
void SystemRoutineController::ScheduleCheckRoutineStatus(
uint32_t duration_in_seconds,
mojom::RoutineType routine_type,
int32_t id) {
inflight_routine_timer_->Start(
FROM_HERE, base::TimeDelta::FromSeconds(duration_in_seconds),
base::BindOnce(&SystemRoutineController::CheckRoutineStatus,
base::Unretained(this), routine_type, id));
}
void SystemRoutineController::OnStandardRoutineResult(
mojom::RoutineType routine_type,
mojom::StandardRoutineResult result) {
DCHECK(IsRoutineRunning());
auto result_info =
ConstructStandardRoutineResultInfoPtr(routine_type, result);
inflight_routine_runner_->OnRoutineResult(std::move(result_info));
inflight_routine_runner_.reset();
}
void SystemRoutineController::BindCrosHealthdDiagnosticsServiceIfNeccessary() {
if (!diagnostics_service_ || !diagnostics_service_.is_connected()) {
cros_healthd::ServiceConnection::GetInstance()->GetDiagnosticsService(
......@@ -27,5 +207,10 @@ void SystemRoutineController::OnDiagnosticsServiceDisconnected() {
diagnostics_service_.reset();
}
void SystemRoutineController::OnInflightRoutineRunnerDisconnected() {
inflight_routine_runner_.reset();
// TODO(baileyberro): Implement routine cancellation.
}
} // namespace diagnostics
} // namespace chromeos
......@@ -5,27 +5,75 @@
#ifndef CHROMEOS_COMPONENTS_DIAGNOSTICS_UI_BACKEND_SYSTEM_ROUTINE_CONTROLLER_H_
#define CHROMEOS_COMPONENTS_DIAGNOSTICS_UI_BACKEND_SYSTEM_ROUTINE_CONTROLLER_H_
#include <memory>
#include "chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace base {
class OneShotTimer;
} // namespace base
namespace cros_healthd {
namespace mojom {
class RunRoutineResponsePtr;
class RoutineUpdatePtr;
} // namespace mojom
} // namespace cros_healthd
namespace chromeos {
namespace diagnostics {
class SystemRoutineController {
class SystemRoutineController : public mojom::SystemRoutineController {
public:
SystemRoutineController();
~SystemRoutineController();
~SystemRoutineController() override;
SystemRoutineController(const SystemRoutineController&) = delete;
SystemRoutineController& operator=(const SystemRoutineController&) = delete;
// mojom::SystemRoutineController:
void RunRoutine(mojom::RoutineType type,
mojo::PendingRemote<mojom::RoutineRunner> runner) override;
private:
void ExecuteRoutine(mojom::RoutineType type);
void RunCpuStressRoutine();
void OnCpuStressRoutineStarted(
cros_healthd::mojom::RunRoutineResponsePtr response_ptr);
void CheckRoutineStatus(mojom::RoutineType routine_type, int32_t id);
void OnRoutineStatusUpdated(mojom::RoutineType routine_type,
int32_t id,
cros_healthd::mojom::RoutineUpdatePtr update_ptr);
bool IsRoutineRunning() const;
void ScheduleCheckRoutineStatus(uint32_t duration_in_seconds,
mojom::RoutineType routine_type,
int32_t id);
void OnStandardRoutineResult(mojom::RoutineType routine_type,
mojom::StandardRoutineResult result);
void BindCrosHealthdDiagnosticsServiceIfNeccessary();
void OnDiagnosticsServiceDisconnected();
void OnInflightRoutineRunnerDisconnected();
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};
};
} // namespace diagnostics
......
......@@ -5,7 +5,10 @@
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") {
sources = [ "system_data_provider.mojom" ]
sources = [
"system_data_provider.mojom",
"system_routine_controller.mojom",
]
public_deps = [ "//mojo/public/mojom/base" ]
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module chromeos.diagnostics.mojom;
enum RoutineType {
kCpuStress,
};
enum StandardRoutineResult {
kTestPassed,
kTestFailed,
kExecutionError,
kUnableToRun,
};
union RoutineResult {
StandardRoutineResult simple_result;
};
struct RoutineResultInfo {
RoutineType type;
RoutineResult result;
};
// Implemented by clients in order to receive the results of a requested
// routine.
interface RoutineRunner {
// OnRoutineResult is called once to return the result of the routine.
OnRoutineResult(RoutineResultInfo info);
};
// Enables clients to run diagnostic routines to test the status of various
// components on the system. This API is exposed to the Diagnostics SWA.
interface SystemRoutineController {
// Runs routine |type|. The result is returned via the RoutineRunner |runner|.
// If the client closes the |remote|, cancellation of the associated routine
// is attempted.
RunRoutine(RoutineType type, pending_remote<RoutineRunner> runner);
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment