Skip to content

Commit

Permalink
Create SystemRoutineController Mojo Interface
Browse files Browse the repository at this point in the history
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: Dominick Ng <dominickn@chromium.org>
Reviewed-by: Zentaro Kavanagh <zentaro@chromium.org>
Cr-Commit-Position: refs/heads/master@{#823339}
  • Loading branch information
abaileyb authored and Commit Bot committed Nov 2, 2020
1 parent 32c0491 commit 476ebf3
Show file tree
Hide file tree
Showing 7 changed files with 611 additions and 6 deletions.
18 changes: 18 additions & 0 deletions chromeos/components/diagnostics_ui/backend/cros_healthd_helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace mojom {
class BatteryInfo;
class CpuInfo;
class MemoryInfo;
class NonInteractiveRoutineUpdate;
class RoutineUpdate;
class SystemInfo;
class TelemetryInfo;
} // namespace mojom
Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 476ebf3

Please sign in to comment.