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