blob: 7edee30dae754910884e12d4f770fd165d2ea7be [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "diagnostics/wilco_dtc_supportd/grpc_service.h"
#include <cstdint>
#include <iterator>
#include <utility>
#include <base/bind.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/strings/string_util.h>
#include "diagnostics/wilco_dtc_supportd/ec_constants.h"
#include "diagnostics/wilco_dtc_supportd/telemetry/system_files_service_impl.h"
#include "diagnostics/wilco_dtc_supportd/telemetry/system_info_service_impl.h"
#include "mojo/cros_healthd_probe.mojom.h"
namespace diagnostics {
// The total size of "string" and "bytes" fields in one
// PerformWebRequestParameter must not exceed 1MB.
const int kMaxPerformWebRequestParameterSizeInBytes = 1000 * 1000;
// The maximum number of header in PerformWebRequestParameter.
const int kMaxNumberOfHeadersInPerformWebRequestParameter = 1000 * 1000;
namespace {
using SendMessageToUiCallback = GrpcService::SendMessageToUiCallback;
using PerformWebRequestResponseCallback =
GrpcService::PerformWebRequestResponseCallback;
using DelegateWebRequestStatus = GrpcService::Delegate::WebRequestStatus;
using DelegateWebRequestHttpMethod =
GrpcService::Delegate::WebRequestHttpMethod;
using GetAvailableRoutinesCallback = GrpcService::GetAvailableRoutinesCallback;
using RunRoutineCallback = GrpcService::RunRoutineCallback;
using GetRoutineUpdateCallback = GrpcService::GetRoutineUpdateCallback;
using GetConfigurationDataCallback = GrpcService::GetConfigurationDataCallback;
using GetDriveSystemDataCallback = GrpcService::GetDriveSystemDataCallback;
using RequestBluetoothDataNotificationCallback =
GrpcService::RequestBluetoothDataNotificationCallback;
using GetStatefulPartitionAvailableCapacityCallback =
GrpcService::GetStatefulPartitionAvailableCapacityCallback;
// Https prefix expected to be a prefix of URL in PerformWebRequestParameter.
constexpr char kHttpsPrefix[] = "https://";
// Calculates the size of all "string" and "bytes" fields in the request.
// Must be updated if grpc_api::PerformWebRequestParameter proto is updated.
int64_t CalculateWebRequestParameterSize(
const std::unique_ptr<grpc_api::PerformWebRequestParameter>& parameter) {
int64_t size = parameter->url().length() + parameter->request_body().size();
for (const std::string& header : parameter->headers()) {
size += header.length();
}
return size;
}
// Forwards and wraps the result of a SendMessageToUi into gRPC response.
void ForwardSendMessageToUiResponse(const SendMessageToUiCallback& callback,
grpc::Status status,
base::StringPiece response_json_message) {
auto reply = std::make_unique<grpc_api::SendMessageToUiResponse>();
reply->set_response_json_message(response_json_message.as_string());
callback.Run(status, std::move(reply));
}
// Forwards and wraps status & HTTP status into gRPC PerformWebRequestResponse.
void ForwardWebGrpcResponse(const PerformWebRequestResponseCallback& callback,
DelegateWebRequestStatus status,
int http_status,
base::StringPiece response_body) {
auto reply = std::make_unique<grpc_api::PerformWebRequestResponse>();
switch (status) {
case DelegateWebRequestStatus::kOk:
reply->set_status(grpc_api::PerformWebRequestResponse::STATUS_OK);
reply->set_http_status(http_status);
reply->set_response_body(response_body.as_string());
break;
case DelegateWebRequestStatus::kNetworkError:
reply->set_status(
grpc_api::PerformWebRequestResponse::STATUS_NETWORK_ERROR);
break;
case DelegateWebRequestStatus::kHttpError:
reply->set_status(grpc_api::PerformWebRequestResponse::STATUS_HTTP_ERROR);
reply->set_http_status(http_status);
reply->set_response_body(response_body.as_string());
break;
case DelegateWebRequestStatus::kInternalError:
reply->set_status(
grpc_api::PerformWebRequestResponse::STATUS_INTERNAL_ERROR);
break;
}
callback.Run(grpc::Status::OK, std::move(reply));
}
// Converts gRPC HTTP method into GrpcService::Delegate's HTTP
// method, returns false if HTTP method is invalid.
bool GetDelegateWebRequestHttpMethod(
grpc_api::PerformWebRequestParameter::HttpMethod http_method,
DelegateWebRequestHttpMethod* delegate_http_method) {
switch (http_method) {
case grpc_api::PerformWebRequestParameter::HTTP_METHOD_GET:
*delegate_http_method = DelegateWebRequestHttpMethod::kGet;
return true;
case grpc_api::PerformWebRequestParameter::HTTP_METHOD_HEAD:
*delegate_http_method = DelegateWebRequestHttpMethod::kHead;
return true;
case grpc_api::PerformWebRequestParameter::HTTP_METHOD_POST:
*delegate_http_method = DelegateWebRequestHttpMethod::kPost;
return true;
case grpc_api::PerformWebRequestParameter::HTTP_METHOD_PUT:
*delegate_http_method = DelegateWebRequestHttpMethod::kPut;
return true;
case grpc_api::PerformWebRequestParameter::HTTP_METHOD_PATCH:
*delegate_http_method = DelegateWebRequestHttpMethod::kPatch;
return true;
default:
LOG(ERROR) << "The HTTP method is unset or invalid: "
<< static_cast<int>(http_method);
return false;
}
}
// Converts gRPC VPD field into SystemFilesService's VpdField, returns false if
// VPD field is invalid.
bool GetSystemFilesServiceVpdField(
grpc_api::GetVpdFieldRequest::VpdField vpd_field,
SystemFilesService::VpdField* out_vpd_field) {
switch (vpd_field) {
case grpc_api::GetVpdFieldRequest::FIELD_SERIAL_NUMBER:
*out_vpd_field = SystemFilesService::VpdField::kSerialNumber;
return true;
case grpc_api::GetVpdFieldRequest::FIELD_MODEL_NAME:
*out_vpd_field = SystemFilesService::VpdField::kModelName;
return true;
case grpc_api::GetVpdFieldRequest::FIELD_ASSET_ID:
*out_vpd_field = SystemFilesService::VpdField::kAssetId;
return true;
case grpc_api::GetVpdFieldRequest::FIELD_SKU_NUMBER:
*out_vpd_field = SystemFilesService::VpdField::kSkuNumber;
return true;
case grpc_api::GetVpdFieldRequest::FIELD_UUID_ID:
*out_vpd_field = SystemFilesService::VpdField::kUuid;
return true;
case grpc_api::GetVpdFieldRequest::FIELD_MANUFACTURE_DATE:
*out_vpd_field = SystemFilesService::VpdField::kMfgDate;
return true;
case grpc_api::GetVpdFieldRequest::FIELD_ACTIVATE_DATE:
*out_vpd_field = SystemFilesService::VpdField::kActivateDate;
return true;
case grpc_api::GetVpdFieldRequest::FIELD_SYSTEM_ID:
*out_vpd_field = SystemFilesService::VpdField::kSystemId;
return true;
case grpc_api::GetVpdFieldRequest::FIELD_UNSET:
default:
return false;
}
}
// Forwards and wraps available routines into a gRPC response.
void ForwardGetAvailableRoutinesResponse(
const GetAvailableRoutinesCallback& callback,
const std::vector<grpc_api::DiagnosticRoutine>& routines,
grpc_api::RoutineServiceStatus service_status) {
auto reply = std::make_unique<grpc_api::GetAvailableRoutinesResponse>();
for (auto routine : routines)
reply->add_routines(routine);
reply->set_service_status(service_status);
callback.Run(grpc::Status::OK, std::move(reply));
}
// Forwards and wraps the result of a RunRoutine command into a gRPC response.
void ForwardRunRoutineResponse(const RunRoutineCallback& callback,
int uuid,
grpc_api::DiagnosticRoutineStatus status,
grpc_api::RoutineServiceStatus service_status) {
auto reply = std::make_unique<grpc_api::RunRoutineResponse>();
reply->set_uuid(uuid);
reply->set_status(status);
reply->set_service_status(service_status);
callback.Run(grpc::Status::OK, std::move(reply));
}
// Forwards and wraps the results of a GetRoutineUpdate command into a gRPC
// response.
void ForwardGetRoutineUpdateResponse(
const GetRoutineUpdateCallback& callback,
int uuid,
grpc_api::DiagnosticRoutineStatus status,
int progress_percent,
grpc_api::DiagnosticRoutineUserMessage user_message,
const std::string& output,
const std::string& status_message,
grpc_api::RoutineServiceStatus service_status) {
auto reply = std::make_unique<grpc_api::GetRoutineUpdateResponse>();
reply->set_uuid(uuid);
reply->set_status(status);
reply->set_progress_percent(progress_percent);
reply->set_user_message(user_message);
reply->set_output(output);
reply->set_status_message(status_message);
reply->set_service_status(service_status);
callback.Run(grpc::Status::OK, std::move(reply));
}
// Forwards and wraps the result of a GetConfigurationDataFromBrowser into gRPC
// response.
void ForwardGetConfigurationDataResponse(
const GetConfigurationDataCallback& callback,
const std::string& json_configuration_data) {
auto reply = std::make_unique<grpc_api::GetConfigurationDataResponse>();
reply->set_json_configuration_data(json_configuration_data);
callback.Run(grpc::Status::OK, std::move(reply));
}
// Forwards and wraps the result of a GetDriveSystemData into gRPC
// response.
void ForwardGetDriveSystemDataResponse(
const GetDriveSystemDataCallback& callback,
const std::string& payload,
bool success) {
auto reply = std::make_unique<grpc_api::GetDriveSystemDataResponse>();
if (success) {
reply->set_status(grpc_api::GetDriveSystemDataResponse::STATUS_OK);
reply->set_payload(payload);
} else {
reply->set_status(
grpc_api::GetDriveSystemDataResponse::STATUS_ERROR_REQUEST_PROCESSING);
}
callback.Run(grpc::Status::OK, std::move(reply));
}
// Extracts stateful partition info from cros_healthd's TelemetryInfo
// and moves it into a gRPC response.
void ForwardGetStatefulPartitionAvailableCapacity(
const GetStatefulPartitionAvailableCapacityCallback& callback,
chromeos::cros_healthd::mojom::TelemetryInfoPtr info) {
auto reply = std::make_unique<
grpc_api::GetStatefulPartitionAvailableCapacityResponse>();
if (!info || !info->stateful_partition_result ||
!info->stateful_partition_result->is_partition_info()) {
reply->set_status(grpc_api::GetStatefulPartitionAvailableCapacityResponse::
STATUS_ERROR_REQUEST_PROCESSING);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
reply->set_status(
grpc_api::GetStatefulPartitionAvailableCapacityResponse::STATUS_OK);
// Reduce to MiB and round down to multiple of 100MiB.
uint64_t available_space =
info->stateful_partition_result->get_partition_info()->available_space;
reply->set_available_capacity_mb((available_space / 1024 / 1024 / 100) * 100);
callback.Run(grpc::Status::OK, std::move(reply));
}
// Maps GetEcTelemetryResponse::Status in EcService to
// grpc_api::GetEcTelemetryResponse::Status. This is 1:1 mapping.
grpc_api::GetEcTelemetryResponse::Status GetGrpcEcTelemetryStatus(
EcService::GetEcTelemetryResponse::Status status) {
switch (status) {
case (EcService::GetEcTelemetryResponse::STATUS_UNSET):
return grpc_api::GetEcTelemetryResponse::STATUS_UNSET;
case (EcService::GetEcTelemetryResponse::STATUS_OK):
return grpc_api::GetEcTelemetryResponse::STATUS_OK;
case (EcService::GetEcTelemetryResponse::STATUS_ERROR_INPUT_PAYLOAD_EMPTY):
return grpc_api::GetEcTelemetryResponse::STATUS_ERROR_INPUT_PAYLOAD_EMPTY;
case (EcService::GetEcTelemetryResponse::
STATUS_ERROR_INPUT_PAYLOAD_MAX_SIZE_EXCEEDED):
return grpc_api::GetEcTelemetryResponse::
STATUS_ERROR_INPUT_PAYLOAD_MAX_SIZE_EXCEEDED;
case (EcService::GetEcTelemetryResponse::STATUS_ERROR_ACCESSING_DRIVER):
return grpc_api::GetEcTelemetryResponse::STATUS_ERROR_ACCESSING_DRIVER;
}
}
} // namespace
GrpcService::GrpcService(Delegate* delegate)
: delegate_(delegate),
system_files_service_(new SystemFilesServiceImpl()),
system_info_service_(new SystemInfoServiceImpl()) {
DCHECK(delegate_);
}
GrpcService::~GrpcService() = default;
// Overrides the file system root directory for file operations in tests.
void GrpcService::set_root_dir_for_testing(const base::FilePath& root_dir) {
root_dir_ = root_dir;
auto system_files_service = std::make_unique<SystemFilesServiceImpl>();
system_files_service->set_root_dir_for_testing(root_dir);
set_system_files_service_for_testing(std::move(system_files_service));
}
// Overrides the system files service for operations in tests.
void GrpcService::set_system_files_service_for_testing(
std::unique_ptr<SystemFilesService> service) {
system_files_service_ = std::move(service);
}
void GrpcService::set_system_info_service_for_testing(
std::unique_ptr<SystemInfoService> service) {
system_info_service_ = std::move(service);
}
void GrpcService::SendMessageToUi(
std::unique_ptr<grpc_api::SendMessageToUiRequest> request,
const SendMessageToUiCallback& callback) {
delegate_->SendWilcoDtcMessageToUi(
request->json_message(),
base::Bind(&ForwardSendMessageToUiResponse, callback));
}
void GrpcService::GetProcData(
std::unique_ptr<grpc_api::GetProcDataRequest> request,
const GetProcDataCallback& callback) {
DCHECK(request);
auto reply = std::make_unique<grpc_api::GetProcDataResponse>();
switch (request->type()) {
case grpc_api::GetProcDataRequest::FILE_UPTIME:
AddFileDump(SystemFilesService::File::kProcUptime,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::FILE_MEMINFO:
AddFileDump(SystemFilesService::File::kProcMeminfo,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::FILE_LOADAVG:
AddFileDump(SystemFilesService::File::kProcLoadavg,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::FILE_STAT:
AddFileDump(SystemFilesService::File::kProcStat,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::DIRECTORY_ACPI_BUTTON:
AddDirectoryDump(SystemFilesService::Directory::kProcAcpiButton,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::FILE_NET_NETSTAT:
AddFileDump(SystemFilesService::File::kProcNetNetstat,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::FILE_NET_DEV:
AddFileDump(SystemFilesService::File::kProcNetDev,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::FILE_DISKSTATS:
AddFileDump(SystemFilesService::File::kProcDiskstats,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::FILE_CPUINFO:
AddFileDump(SystemFilesService::File::kProcCpuinfo,
reply->mutable_file_dump());
break;
case grpc_api::GetProcDataRequest::FILE_VMSTAT:
AddFileDump(SystemFilesService::File::kProcVmstat,
reply->mutable_file_dump());
break;
default:
LOG(ERROR) << "GetProcData gRPC request type unset or invalid: "
<< request->type();
// Error is designated by a reply with the empty list of entries.
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
VLOG(1) << "Completing GetProcData gRPC request of type " << request->type()
<< ", returning " << reply->file_dump_size() << " items";
callback.Run(grpc::Status::OK, std::move(reply));
}
void GrpcService::GetSysfsData(
std::unique_ptr<grpc_api::GetSysfsDataRequest> request,
const GetSysfsDataCallback& callback) {
DCHECK(request);
auto reply = std::make_unique<grpc_api::GetSysfsDataResponse>();
switch (request->type()) {
case grpc_api::GetSysfsDataRequest::CLASS_HWMON:
AddDirectoryDump(SystemFilesService::Directory::kSysClassHwmon,
reply->mutable_file_dump());
break;
case grpc_api::GetSysfsDataRequest::CLASS_THERMAL:
AddDirectoryDump(SystemFilesService::Directory::kSysClassThermal,
reply->mutable_file_dump());
break;
case grpc_api::GetSysfsDataRequest::FIRMWARE_DMI_TABLES:
AddDirectoryDump(SystemFilesService::Directory::kSysFirmwareDmiTables,
reply->mutable_file_dump());
break;
case grpc_api::GetSysfsDataRequest::CLASS_POWER_SUPPLY:
AddDirectoryDump(SystemFilesService::Directory::kSysClassPowerSupply,
reply->mutable_file_dump());
break;
case grpc_api::GetSysfsDataRequest::CLASS_BACKLIGHT:
AddDirectoryDump(SystemFilesService::Directory::kSysClassBacklight,
reply->mutable_file_dump());
break;
case grpc_api::GetSysfsDataRequest::CLASS_NETWORK:
AddDirectoryDump(SystemFilesService::Directory::kSysClassNetwork,
reply->mutable_file_dump());
break;
case grpc_api::GetSysfsDataRequest::DEVICES_SYSTEM_CPU:
AddDirectoryDump(SystemFilesService::Directory::kSysDevicesSystemCpu,
reply->mutable_file_dump());
break;
default:
LOG(ERROR) << "GetSysfsData gRPC request type unset or invalid: "
<< request->type();
// Error is designated by a reply with the empty list of entries.
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
VLOG(1) << "Completing GetSysfsData gRPC request of type " << request->type()
<< ", returning " << reply->file_dump_size() << " items";
callback.Run(grpc::Status::OK, std::move(reply));
}
void GrpcService::GetEcTelemetry(
std::unique_ptr<grpc_api::GetEcTelemetryRequest> request,
const GetEcTelemetryCallback& callback) {
DCHECK(request);
auto response =
delegate_->GetEcService()->GetEcTelemetry(std::move(request->payload()));
auto reply = std::make_unique<grpc_api::GetEcTelemetryResponse>();
reply->set_status(GetGrpcEcTelemetryStatus(response.status));
reply->set_payload(std::move(response.payload));
callback.Run(grpc::Status::OK, std::move(reply));
}
void GrpcService::PerformWebRequest(
std::unique_ptr<grpc_api::PerformWebRequestParameter> parameter,
const PerformWebRequestResponseCallback& callback) {
DCHECK(parameter);
auto reply = std::make_unique<grpc_api::PerformWebRequestResponse>();
if (parameter->url().empty()) {
LOG(ERROR) << "PerformWebRequest URL is empty.";
reply->set_status(
grpc_api::PerformWebRequestResponse::STATUS_ERROR_INVALID_URL);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
if (!base::StartsWith(parameter->url(), kHttpsPrefix,
base::CompareCase::INSENSITIVE_ASCII)) {
LOG(ERROR) << "PerformWebRequest URL must be an HTTPS URL.";
reply->set_status(
grpc_api::PerformWebRequestResponse::STATUS_ERROR_INVALID_URL);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
if (parameter->headers().size() >
kMaxNumberOfHeadersInPerformWebRequestParameter) {
LOG(ERROR) << "PerformWebRequest number of headers is too large.";
reply->set_status(
grpc_api::PerformWebRequestResponse::STATUS_ERROR_MAX_SIZE_EXCEEDED);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
if (CalculateWebRequestParameterSize(parameter) >
kMaxPerformWebRequestParameterSizeInBytes) {
LOG(ERROR) << "PerformWebRequest request is too large.";
reply->set_status(
grpc_api::PerformWebRequestResponse::STATUS_ERROR_MAX_SIZE_EXCEEDED);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
DelegateWebRequestHttpMethod delegate_http_method;
if (!GetDelegateWebRequestHttpMethod(parameter->http_method(),
&delegate_http_method)) {
reply->set_status(grpc_api::PerformWebRequestResponse ::
STATUS_ERROR_REQUIRED_FIELD_MISSING);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
delegate_->PerformWebRequestToBrowser(
delegate_http_method, parameter->url(),
std::vector<std::string>(
std::make_move_iterator(parameter->mutable_headers()->begin()),
std::make_move_iterator(parameter->mutable_headers()->end())),
parameter->request_body(), base::Bind(&ForwardWebGrpcResponse, callback));
}
void GrpcService::GetAvailableRoutines(
std::unique_ptr<grpc_api::GetAvailableRoutinesRequest> request,
const GetAvailableRoutinesCallback& callback) {
DCHECK(request);
delegate_->GetAvailableRoutinesToService(
base::Bind(&ForwardGetAvailableRoutinesResponse, callback));
}
void GrpcService::RunRoutine(
std::unique_ptr<grpc_api::RunRoutineRequest> request,
const RunRoutineCallback& callback) {
DCHECK(request);
// Make sure the RunRoutineRequest is superficially valid.
switch (request->routine()) {
case grpc_api::ROUTINE_BATTERY:
if (!request->has_battery_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type BATTERY has no "
"battery parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_BATTERY_SYSFS:
if (!request->has_battery_sysfs_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type BATTERY_SYSFS has "
"no battery_sysfs parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_URANDOM:
if (!request->has_urandom_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type URANDOM has no "
"urandom parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_SMARTCTL_CHECK:
if (!request->has_smartctl_check_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type SMARTCTL_CHECK "
"has no smartctl_check parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_CPU_CACHE:
if (!request->has_cpu_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type CPU CACHE "
"has no cpu parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_CPU_STRESS:
if (!request->has_cpu_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type CPU STRESS "
"has no cpu parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_FLOATING_POINT_ACCURACY:
if (!request->has_floating_point_accuracy_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type "
"FLOATING_POINT_ACCURACY has no "
"floating_point_accuracy parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_NVME_WEAR_LEVEL:
if (!request->has_nvme_wear_level_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type "
"ROUTINE_NVME_WEAR_LEVEL has no nvme_wear_level "
"parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_NVME_SHORT_SELF_TEST:
if (!request->has_nvme_short_self_test_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type "
"ROUTINE_NVME_SHORT_SELF_TEST has no "
"nvme_short_self_test parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_NVME_LONG_SELF_TEST:
if (!request->has_nvme_long_self_test_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type "
"ROUTINE_NVME_LONG_SELF_TEST has no "
"nvme_long_self_test parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_DISK_LINEAR_READ:
if (!request->has_disk_linear_read_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type LINEAR_READ "
"has no linear_read parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_DISK_RANDOM_READ:
if (!request->has_disk_random_read_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type RANDOM_READ "
"has no random_read parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
case grpc_api::ROUTINE_PRIME_SEARCH:
if (!request->has_prime_search_params()) {
LOG(ERROR) << "RunRoutineRequest with routine type PRIME_SEARCH "
"has no prime_search parameters.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
break;
default:
LOG(ERROR) << "RunRoutineRequest routine type invalid or unset.";
ForwardRunRoutineResponse(callback, 0 /* uuid */,
grpc_api::ROUTINE_STATUS_INVALID_FIELD,
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
delegate_->RunRoutineToService(
*request, base::Bind(&ForwardRunRoutineResponse, callback));
}
void GrpcService::GetRoutineUpdate(
std::unique_ptr<grpc_api::GetRoutineUpdateRequest> request,
const GetRoutineUpdateCallback& callback) {
DCHECK(request);
if (request->command() == grpc_api::GetRoutineUpdateRequest::COMMAND_UNSET) {
ForwardGetRoutineUpdateResponse(
callback, request->uuid(), grpc_api::ROUTINE_STATUS_INVALID_FIELD,
0 /* progress_percent */, grpc_api::ROUTINE_USER_MESSAGE_UNSET,
"" /* output */, "No command specified.",
grpc_api::ROUTINE_SERVICE_STATUS_OK);
return;
}
delegate_->GetRoutineUpdateRequestToService(
request->uuid(), request->command(), request->include_output(),
base::Bind(&ForwardGetRoutineUpdateResponse, callback));
}
void GrpcService::GetOsVersion(
std::unique_ptr<grpc_api::GetOsVersionRequest> request,
const GetOsVersionCallback& callback) {
DCHECK(request);
auto reply = std::make_unique<grpc_api::GetOsVersionResponse>();
std::string version;
if (system_info_service_->GetOsVersion(&version)) {
reply->set_version(version);
}
int milestone = 0;
if (system_info_service_->GetOsMilestone(&milestone)) {
reply->set_milestone(milestone);
}
callback.Run(grpc::Status::OK, std::move(reply));
}
void GrpcService::GetConfigurationData(
std::unique_ptr<grpc_api::GetConfigurationDataRequest> request,
const GetConfigurationDataCallback& callback) {
DCHECK(request);
delegate_->GetConfigurationDataFromBrowser(
base::Bind(&ForwardGetConfigurationDataResponse, callback));
}
void GrpcService::GetVpdField(
std::unique_ptr<grpc_api::GetVpdFieldRequest> request,
const GetVpdFieldCallback& callback) {
DCHECK(request);
auto reply = std::make_unique<grpc_api::GetVpdFieldResponse>();
SystemFilesService::VpdField vpd_field;
if (!GetSystemFilesServiceVpdField(request->vpd_field(), &vpd_field)) {
VLOG(1) << "The VPD field is unspecified or invalid: "
<< static_cast<int>(request->vpd_field());
reply->set_status(
grpc_api::GetVpdFieldResponse::STATUS_ERROR_VPD_FIELD_UNKNOWN);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
auto result = system_files_service_->GetVpdField(vpd_field);
if (!result.has_value()) {
VPLOG(2) << "Failed to read VPD field "
<< static_cast<int>(request->vpd_field());
reply->set_status(grpc_api::GetVpdFieldResponse::STATUS_ERROR_INTERNAL);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
reply->set_status(grpc_api::GetVpdFieldResponse::STATUS_OK);
reply->set_vpd_field_value(std::move(result.value()));
callback.Run(grpc::Status::OK, std::move(reply));
}
void GrpcService::GetDriveSystemData(
std::unique_ptr<grpc_api::GetDriveSystemDataRequest> request,
const GetDriveSystemDataCallback& callback) {
DCHECK(request);
Delegate::DriveSystemDataType data_type;
switch (request->type()) {
case grpc_api::GetDriveSystemDataRequest::SMART_ATTRIBUTES:
data_type = Delegate::DriveSystemDataType::kSmartAttributes;
break;
case grpc_api::GetDriveSystemDataRequest::IDENTITY_ATTRIBUTES:
data_type = Delegate::DriveSystemDataType::kIdentityAttributes;
break;
default:
LOG(ERROR) << "The GetDriveSystemDataRequest::Type is unset or invalid: "
<< static_cast<int>(request->type());
auto reply = std::make_unique<grpc_api::GetDriveSystemDataResponse>();
reply->set_status(grpc_api::GetDriveSystemDataResponse::
STATUS_ERROR_REQUEST_TYPE_UNKNOWN);
callback.Run(grpc::Status::OK, std::move(reply));
return;
}
delegate_->GetDriveSystemData(
data_type, base::Bind(&ForwardGetDriveSystemDataResponse, callback));
}
void GrpcService::RequestBluetoothDataNotification(
std::unique_ptr<grpc_api::RequestBluetoothDataNotificationRequest> request,
const RequestBluetoothDataNotificationCallback& callback) {
delegate_->RequestBluetoothDataNotification();
callback.Run(
grpc::Status::OK,
std::make_unique<grpc_api::RequestBluetoothDataNotificationResponse>());
}
void GrpcService::GetStatefulPartitionAvailableCapacity(
std::unique_ptr<grpc_api::GetStatefulPartitionAvailableCapacityRequest>
request,
const GetStatefulPartitionAvailableCapacityCallback& callback) {
DCHECK(request);
std::vector<chromeos::cros_healthd::mojom::ProbeCategoryEnum> categories{
chromeos::cros_healthd::mojom::ProbeCategoryEnum::kStatefulPartition};
delegate_->ProbeTelemetryInfo(
std::move(categories),
base::Bind(&ForwardGetStatefulPartitionAvailableCapacity, callback));
}
void GrpcService::AddFileDump(
SystemFilesService::File location,
google::protobuf::RepeatedPtrField<grpc_api::FileDump>* file_dumps) {
auto file_dump = system_files_service_->GetFileDump(location);
if (!file_dump)
return;
grpc_api::FileDump grpc_dump;
grpc_dump.set_path(file_dump.value().path.value());
grpc_dump.set_canonical_path(file_dump.value().canonical_path.value());
grpc_dump.set_contents(std::move(file_dump.value().contents));
file_dumps->Add()->Swap(&grpc_dump);
}
void GrpcService::AddDirectoryDump(
SystemFilesService::Directory location,
google::protobuf::RepeatedPtrField<grpc_api::FileDump>* grpc_dumps) {
auto dumps = system_files_service_->GetDirectoryDump(location);
if (!dumps)
return;
for (auto& dump : dumps.value()) {
grpc_api::FileDump grpc_dump;
grpc_dump.set_path(dump->path.value());
grpc_dump.set_canonical_path(dump->canonical_path.value());
grpc_dump.set_contents(std::move(dump->contents));
grpc_dumps->Add()->Swap(&grpc_dump);
}
}
} // namespace diagnostics