| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api.h" |
| |
| #include <cstddef> |
| #include <string> |
| #include <utility> |
| |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/notreached.h" |
| #include "base/time/time.h" |
| #include "base/types/expected.h" |
| #include "base/uuid.h" |
| #include "base/values.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.h" |
| #include "chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_metrics.h" |
| #include "chrome/browser/chromeos/extensions/telemetry/api/diagnostics/remote_diagnostics_service_strategy.h" |
| #include "chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_manager.h" |
| #include "chrome/common/chromeos/extensions/api/diagnostics.h" |
| #include "chromeos/crosapi/mojom/diagnostics_service.mojom.h" |
| #include "chromeos/crosapi/mojom/nullable_primitives.mojom.h" |
| #include "chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom.h" |
| #include "chromeos/crosapi/mojom/telemetry_extension_exception.mojom.h" |
| #include "extensions/common/extension_features.h" |
| #include "extensions/common/permissions/permissions_data.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| #include "base/strings/stringprintf.h" |
| #include "chromeos/lacros/lacros_service.h" |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| namespace cx_diag = api::os_diagnostics; |
| |
| base::expected<cx_diag::RoutineSupportStatusInfo, std::string> |
| ParseRoutineArgumentSupportResult( |
| crosapi::mojom::TelemetryExtensionSupportStatusPtr result) { |
| switch (result->which()) { |
| case crosapi::mojom::TelemetryExtensionSupportStatus::Tag:: |
| kUnmappedUnionField: |
| return base::unexpected("API internal error."); |
| case crosapi::mojom::TelemetryExtensionSupportStatus::Tag::kException: |
| return base::unexpected(result->get_exception()->debug_message); |
| case crosapi::mojom::TelemetryExtensionSupportStatus::Tag::kSupported: { |
| cx_diag::RoutineSupportStatusInfo info; |
| info.status = cx_diag::RoutineSupportStatus::kSupported; |
| |
| return base::ok(std::move(info)); |
| } |
| case crosapi::mojom::TelemetryExtensionSupportStatus::Tag::kUnsupported: { |
| cx_diag::RoutineSupportStatusInfo info; |
| info.status = cx_diag::RoutineSupportStatus::kUnsupported; |
| |
| return base::ok(std::move(info)); |
| } |
| } |
| NOTREACHED(); |
| } |
| |
| bool IsPendingApprovalRoutine( |
| const crosapi::mojom::TelemetryDiagnosticRoutineArgumentPtr& arg) { |
| return false; |
| } |
| |
| } // namespace |
| |
| // DiagnosticsApiFunctionV1AndV2Base ------------------------------------------- |
| |
| template <class Params> |
| std::optional<Params> DiagnosticsApiFunctionV1AndV2Base::GetParams() { |
| auto params = Params::Create(args()); |
| if (!params) { |
| SetBadMessage(); |
| Respond(BadMessage()); |
| } |
| |
| return params; |
| } |
| |
| // DiagnosticsApiFunctionBase -------------------------------------------------- |
| |
| DiagnosticsApiFunctionBase::DiagnosticsApiFunctionBase() |
| : remote_diagnostics_service_strategy_( |
| RemoteDiagnosticsServiceStrategy::Create()) {} |
| |
| DiagnosticsApiFunctionBase::~DiagnosticsApiFunctionBase() = default; |
| |
| mojo::Remote<crosapi::mojom::DiagnosticsService>& |
| DiagnosticsApiFunctionBase::GetRemoteService() { |
| DCHECK(remote_diagnostics_service_strategy_); |
| return remote_diagnostics_service_strategy_->GetRemoteService(); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| bool DiagnosticsApiFunctionBase::IsCrosApiAvailable() { |
| return remote_diagnostics_service_strategy_ != nullptr; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| |
| // DiagnosticsApiFunctionBaseV2 ------------------------------------------------ |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| bool DiagnosticsApiFunctionBaseV2::IsCrosApiAvailable() { |
| return LacrosService::Get() && |
| LacrosService::Get() |
| ->IsAvailable< |
| crosapi::mojom::TelemetryDiagnosticRoutinesService>(); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| |
| // OsDiagnosticsGetAvailableRoutinesFunction ----------------------------------- |
| |
| void OsDiagnosticsGetAvailableRoutinesFunction::RunIfAllowed() { |
| auto cb = base::BindOnce(&OsDiagnosticsGetAvailableRoutinesFunction::OnResult, |
| this); |
| |
| GetRemoteService()->GetAvailableRoutines(std::move(cb)); |
| } |
| |
| void OsDiagnosticsGetAvailableRoutinesFunction::OnResult( |
| const std::vector<crosapi::mojom::DiagnosticsRoutineEnum>& routines) { |
| cx_diag::GetAvailableRoutinesResponse result; |
| for (const auto in : routines) { |
| cx_diag::RoutineType out; |
| if (converters::diagnostics::ConvertMojoRoutine(in, &out)) { |
| result.routines.push_back(out); |
| } |
| } |
| |
| Respond(ArgumentList(cx_diag::GetAvailableRoutines::Results::Create(result))); |
| } |
| |
| // OsDiagnosticsGetRoutineUpdateFunction --------------------------------------- |
| |
| void OsDiagnosticsGetRoutineUpdateFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::GetRoutineUpdate::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| auto cb = |
| base::BindOnce(&OsDiagnosticsGetRoutineUpdateFunction::OnResult, this); |
| |
| GetRemoteService()->GetRoutineUpdate( |
| params->request.id, |
| converters::diagnostics::ConvertRoutineCommand(params->request.command), |
| /* include_output= */ true, std::move(cb)); |
| } |
| |
| void OsDiagnosticsGetRoutineUpdateFunction::OnResult( |
| crosapi::mojom::DiagnosticsRoutineUpdatePtr ptr) { |
| if (!ptr) { |
| // |ptr| should never be null, otherwise Mojo validation will fail. |
| // However it's safer to handle it in case of API changes. |
| Respond(Error("API internal error")); |
| return; |
| } |
| |
| cx_diag::GetRoutineUpdateResponse result; |
| result.progress_percent = ptr->progress_percent; |
| |
| if (ptr->output.has_value() && !ptr->output.value().empty()) { |
| result.output = std::move(ptr->output); |
| } |
| |
| switch (ptr->routine_update_union->which()) { |
| case crosapi::mojom::DiagnosticsRoutineUpdateUnion::Tag:: |
| kNoninteractiveUpdate: { |
| auto& routine_update = |
| ptr->routine_update_union->get_noninteractive_update(); |
| result.status = |
| converters::diagnostics::ConvertRoutineStatus(routine_update->status); |
| result.status_message = std::move(routine_update->status_message); |
| break; |
| } |
| case crosapi::mojom::DiagnosticsRoutineUpdateUnion::Tag::kInteractiveUpdate: |
| // Routine is waiting for user action. Set the status to waiting. |
| result.status = cx_diag::RoutineStatus::kWaitingUserAction; |
| result.status_message = "Waiting for user action. See user_message"; |
| result.user_message = converters::diagnostics::ConvertRoutineUserMessage( |
| ptr->routine_update_union->get_interactive_update()->user_message); |
| break; |
| } |
| |
| Respond(ArgumentList(cx_diag::GetRoutineUpdate::Results::Create(result))); |
| } |
| |
| // DiagnosticsApiRunRoutineFunctionBase ---------------------------------------- |
| |
| void DiagnosticsApiRunRoutineFunctionBase::OnResult( |
| crosapi::mojom::DiagnosticsRunRoutineResponsePtr ptr) { |
| if (!ptr) { |
| // |ptr| should never be null, otherwise Mojo validation will fail. |
| // However it's safer to handle it in case of API changes. |
| Respond(Error("API internal error")); |
| return; |
| } |
| |
| cx_diag::RunRoutineResponse result; |
| result.id = ptr->id; |
| result.status = converters::diagnostics::ConvertRoutineStatus(ptr->status); |
| Respond(WithArguments(result.ToValue())); |
| } |
| |
| base::OnceCallback<void(crosapi::mojom::DiagnosticsRunRoutineResponsePtr)> |
| DiagnosticsApiRunRoutineFunctionBase::GetOnResult() { |
| return base::BindOnce(&DiagnosticsApiRunRoutineFunctionBase::OnResult, this); |
| } |
| |
| // OsDiagnosticsRunAcPowerRoutineFunction ------------------------------ |
| |
| void OsDiagnosticsRunAcPowerRoutineFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::RunAcPowerRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunAcPowerRoutine( |
| converters::diagnostics::ConvertAcPowerStatusRoutineType( |
| params->request.expected_status), |
| params->request.expected_power_type, GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunBatteryCapacityRoutineFunction ------------------------------ |
| void OsDiagnosticsRunBatteryCapacityRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunBatteryCapacityRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunBatteryChargeRoutineFunction -------------------------------- |
| |
| void OsDiagnosticsRunBatteryChargeRoutineFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::RunBatteryChargeRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunBatteryChargeRoutine( |
| params->request.length_seconds, |
| params->request.minimum_charge_percent_required, GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunBatteryDischargeRoutineFunction ----------------------------- |
| |
| void OsDiagnosticsRunBatteryDischargeRoutineFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::RunBatteryDischargeRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunBatteryDischargeRoutine( |
| params->request.length_seconds, |
| params->request.maximum_discharge_percent_allowed, GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunBatteryHealthRoutineFunction -------------------------------- |
| |
| void OsDiagnosticsRunBatteryHealthRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunBatteryHealthRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunBluetoothDiscoveryRoutineFunction --------------------------- |
| |
| void OsDiagnosticsRunBluetoothDiscoveryRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunBluetoothDiscoveryRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunBluetoothPairingRoutineFunction ----------------------------- |
| |
| void OsDiagnosticsRunBluetoothPairingRoutineFunction::RunIfAllowed() { |
| // Pairing Routine is guarded by `os.bluetooth_peripherals_info` permission. |
| if (!extension()->permissions_data()->HasAPIPermission( |
| extensions::mojom::APIPermissionID:: |
| kChromeOSBluetoothPeripheralsInfo)) { |
| Respond( |
| Error("Unauthorized access to " |
| "chrome.os.diagnostics.runBluetoothPairingRoutine. Extension " |
| "doesn't have the permission.")); |
| return; |
| } |
| |
| const auto params = GetParams<cx_diag::RunBluetoothPairingRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| GetRemoteService()->RunBluetoothPairingRoutine(params->request.peripheral_id, |
| GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunBluetoothPowerRoutineFunction ------------------------------- |
| |
| void OsDiagnosticsRunBluetoothPowerRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunBluetoothPowerRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunBluetoothScanningRoutineFunction ---------------------------- |
| |
| void OsDiagnosticsRunBluetoothScanningRoutineFunction::RunIfAllowed() { |
| // Scanning Routine is guarded by `os.bluetooth_peripherals_info` permission. |
| if (!extension()->permissions_data()->HasAPIPermission( |
| extensions::mojom::APIPermissionID:: |
| kChromeOSBluetoothPeripheralsInfo)) { |
| Respond( |
| Error("Unauthorized access to " |
| "chrome.os.diagnostics.runBluetoothScanningRoutine. Extension" |
| " doesn't have the permission.")); |
| return; |
| } |
| |
| const auto params = GetParams<cx_diag::RunBluetoothScanningRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunBluetoothScanningRoutine( |
| params->request.length_seconds, GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunCpuCacheRoutineFunction ------------------------------------- |
| |
| void OsDiagnosticsRunCpuCacheRoutineFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::RunCpuCacheRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunCpuCacheRoutine(params->request.length_seconds, |
| GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunCpuFloatingPointAccuracyRoutineFunction --------------------- |
| |
| void OsDiagnosticsRunCpuFloatingPointAccuracyRoutineFunction::RunIfAllowed() { |
| const auto params = |
| GetParams<cx_diag::RunCpuFloatingPointAccuracyRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunFloatingPointAccuracyRoutine( |
| params->request.length_seconds, GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunCpuPrimeSearchRoutineFunction ------------------------------- |
| |
| void OsDiagnosticsRunCpuPrimeSearchRoutineFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::RunCpuPrimeSearchRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunPrimeSearchRoutine(params->request.length_seconds, |
| GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunCpuStressRoutineFunction ------------------------------------ |
| |
| void OsDiagnosticsRunCpuStressRoutineFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::RunCpuStressRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunCpuStressRoutine(params->request.length_seconds, |
| GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunDiskReadRoutineFunction ------------------------------------- |
| |
| void OsDiagnosticsRunDiskReadRoutineFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::RunDiskReadRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunDiskReadRoutine( |
| converters::diagnostics::ConvertDiskReadRoutineType(params->request.type), |
| params->request.length_seconds, params->request.file_size_mb, |
| GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunDnsResolutionRoutineFunction -------------------------------- |
| |
| void OsDiagnosticsRunDnsResolutionRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunDnsResolutionRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunDnsResolverPresentRoutineFunction --------------------------- |
| void OsDiagnosticsRunDnsResolverPresentRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunDnsResolverPresentRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunEmmcLifetimeRoutineFunction --------------------------- |
| |
| void OsDiagnosticsRunEmmcLifetimeRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunEmmcLifetimeRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunGatewayCanBePingedRoutineFunction --------------------------- |
| |
| void OsDiagnosticsRunGatewayCanBePingedRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunGatewayCanBePingedRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunFingerprintAliveRoutineFunction ----------------------------- |
| |
| void OsDiagnosticsRunFingerprintAliveRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunFingerprintAliveRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunLanConnectivityRoutineFunction ------------------------------ |
| |
| void OsDiagnosticsRunLanConnectivityRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunLanConnectivityRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunMemoryRoutineFunction --------------------------------------- |
| |
| void OsDiagnosticsRunMemoryRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunMemoryRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunNvmeSelfTestRoutineFunction --------------------------------- |
| |
| void OsDiagnosticsRunNvmeSelfTestRoutineFunction::RunIfAllowed() { |
| auto params = GetParams<cx_diag::RunNvmeSelfTestRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunNvmeSelfTestRoutine( |
| converters::diagnostics::ConvertNvmeSelfTestRoutineType( |
| std::move(params->request)), |
| GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunSensitiveSensorRoutineFunction ----------------------------- |
| |
| void OsDiagnosticsRunSensitiveSensorRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunSensitiveSensorRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunSignalStrengthRoutineFunction ------------------------------- |
| |
| void OsDiagnosticsRunSignalStrengthRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunSignalStrengthRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunSmartctlCheckRoutineFunction -------------------------------- |
| |
| void OsDiagnosticsRunSmartctlCheckRoutineFunction::RunIfAllowed() { |
| std::optional<cx_diag::RunSmartctlCheckRoutine::Params> params( |
| cx_diag::RunSmartctlCheckRoutine::Params::Create(args())); |
| |
| crosapi::mojom::UInt32ValuePtr percentage_used; |
| if (params && params->request && params->request->percentage_used_threshold) { |
| percentage_used = crosapi::mojom::UInt32Value::New( |
| params->request->percentage_used_threshold.value()); |
| } |
| |
| // Backwards compatibility: Calling the routine with an null parameter |
| // results in the same behaviour as the former `RunSmartctlCheckRoutine` |
| // without any parameters. |
| GetRemoteService()->RunSmartctlCheckRoutine(std::move(percentage_used), |
| GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunUfsLifetimeRoutineFunction ------------------------------- |
| |
| void OsDiagnosticsRunUfsLifetimeRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunUfsLifetimeRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunPowerButtonRoutineFunction ----------------------------- |
| |
| void OsDiagnosticsRunPowerButtonRoutineFunction::RunIfAllowed() { |
| const auto params = GetParams<cx_diag::RunPowerButtonRoutine::Params>(); |
| if (!params) { |
| return; |
| } |
| |
| GetRemoteService()->RunPowerButtonRoutine(params->request.timeout_seconds, |
| GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunAudioDriverRoutineFunction ------------------------------- |
| |
| void OsDiagnosticsRunAudioDriverRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunAudioDriverRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsRunFanRoutineFunction ------------------------------- |
| |
| void OsDiagnosticsRunFanRoutineFunction::RunIfAllowed() { |
| GetRemoteService()->RunFanRoutine(GetOnResult()); |
| } |
| |
| // OsDiagnosticsCreateRoutineFunction ------------------------------------ |
| |
| void OsDiagnosticsCreateRoutineFunction::RunIfAllowed() { |
| std::optional<cx_diag::CreateRoutine::Params> params( |
| cx_diag::CreateRoutine::Params::Create(args())); |
| if (!params.has_value()) { |
| Respond(BadMessage()); |
| return; |
| } |
| |
| std::optional<crosapi::mojom::TelemetryDiagnosticRoutineArgumentPtr> |
| mojo_arg = converters::diagnostics::ConvertRoutineArgumentsUnion( |
| std::move(params->args)); |
| if (!mojo_arg.has_value()) { |
| RespondWithError("Routine arguments are invalid."); |
| return; |
| } |
| |
| // Block unreleased features behind the feature flag. |
| if (IsPendingApprovalRoutine(mojo_arg.value()) && |
| !base::FeatureList::IsEnabled( |
| extensions_features::kTelemetryExtensionPendingApprovalApi)) { |
| mojo_arg = crosapi::mojom::TelemetryDiagnosticRoutineArgument:: |
| NewUnrecognizedArgument(false); |
| } |
| |
| RecordRoutineCreation(mojo_arg.value()->which()); |
| |
| // Network bandwidth routine is guarded by `os.diagnostics.network_info_mlab` |
| // permission. |
| if (mojo_arg.value()->is_network_bandwidth() && |
| !extension()->permissions_data()->HasAPIPermission( |
| extensions::mojom::APIPermissionID:: |
| kChromeOSDiagnosticsNetworkInfoForMlab)) { |
| RespondWithError( |
| "Unauthorized access to chrome.os.diagnostics.CreateRoutine with " |
| "networkBandwidth argument. Extension doesn't have the permission."); |
| return; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| auto result = routines_manager->CreateRoutine(extension_id(), |
| std::move(mojo_arg.value())); |
| |
| if (!result.has_value()) { |
| switch (result.error()) { |
| case DiagnosticRoutineManager::kAppUiClosed: |
| Respond(Error("Companion app UI is not open.")); |
| break; |
| case DiagnosticRoutineManager::kExtensionUnloaded: |
| Respond(Error("Extension has been unloaded.")); |
| break; |
| } |
| return; |
| } |
| |
| cx_diag::CreateRoutineResponse response; |
| response.uuid = result->AsLowercaseString(); |
| Respond(ArgumentList(cx_diag::CreateRoutine::Results::Create(response))); |
| } |
| |
| // OsDiagnosticsCreateMemoryRoutineFunction ------------------------------------ |
| |
| void OsDiagnosticsCreateMemoryRoutineFunction::RunIfAllowed() { |
| std::optional<cx_diag::CreateMemoryRoutine::Params> params( |
| cx_diag::CreateMemoryRoutine::Params::Create(args())); |
| |
| if (!params.has_value() || |
| (params.value().args.max_testing_mem_kib.has_value() && |
| params.value().args.max_testing_mem_kib < 0)) { |
| SetBadMessage(); |
| Respond(BadMessage()); |
| return; |
| } |
| |
| auto memory_arg = |
| crosapi::mojom::TelemetryDiagnosticMemoryRoutineArgument::New(); |
| if (params.value().args.max_testing_mem_kib.has_value()) { |
| memory_arg->max_testing_mem_kib = params.value().args.max_testing_mem_kib; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| auto result = routines_manager->CreateRoutine( |
| extension_id(), |
| crosapi::mojom::TelemetryDiagnosticRoutineArgument::NewMemory( |
| std::move(memory_arg))); |
| |
| if (!result.has_value()) { |
| switch (result.error()) { |
| case DiagnosticRoutineManager::kAppUiClosed: |
| Respond(Error("Companion app UI is not open.")); |
| break; |
| case DiagnosticRoutineManager::kExtensionUnloaded: |
| Respond(Error("Extension has been unloaded.")); |
| break; |
| } |
| return; |
| } |
| |
| cx_diag::CreateRoutineResponse response; |
| response.uuid = result->AsLowercaseString(); |
| Respond( |
| ArgumentList(cx_diag::CreateMemoryRoutine::Results::Create(response))); |
| } |
| |
| // OsDiagnosticsCreateVolumeButtonRoutineFunction |
| // ------------------------------------ |
| |
| void OsDiagnosticsCreateVolumeButtonRoutineFunction::RunIfAllowed() { |
| std::optional<cx_diag::CreateVolumeButtonRoutine::Params> params( |
| cx_diag::CreateVolumeButtonRoutine::Params::Create(args())); |
| |
| if (!params.has_value() || params.value().args.timeout_seconds <= 0 || |
| params.value().args.button_type == cx_diag::VolumeButtonType::kNone) { |
| SetBadMessage(); |
| Respond(BadMessage()); |
| return; |
| } |
| |
| auto volume_button_arg = |
| crosapi::mojom::TelemetryDiagnosticVolumeButtonRoutineArgument::New(); |
| volume_button_arg->type = |
| converters::diagnostics::ConvertVolumeButtonRoutineButtonType( |
| params.value().args.button_type); |
| volume_button_arg->timeout = |
| base::Seconds(params.value().args.timeout_seconds); |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| auto result = routines_manager->CreateRoutine( |
| extension_id(), |
| crosapi::mojom::TelemetryDiagnosticRoutineArgument::NewVolumeButton( |
| std::move(volume_button_arg))); |
| |
| if (!result.has_value()) { |
| switch (result.error()) { |
| case DiagnosticRoutineManager::kAppUiClosed: |
| Respond(Error("Companion app UI is not open.")); |
| break; |
| case DiagnosticRoutineManager::kExtensionUnloaded: |
| Respond(Error("Extension has been unloaded.")); |
| break; |
| } |
| return; |
| } |
| |
| cx_diag::CreateRoutineResponse response; |
| response.uuid = result->AsLowercaseString(); |
| Respond(ArgumentList( |
| cx_diag::CreateVolumeButtonRoutine::Results::Create(response))); |
| } |
| |
| // OsDiagnosticsCreateFanRoutineFunction ------------------------------------ |
| |
| void OsDiagnosticsCreateFanRoutineFunction::RunIfAllowed() { |
| std::optional<cx_diag::CreateFanRoutine::Params> params( |
| cx_diag::CreateFanRoutine::Params::Create(args())); |
| |
| if (!params.has_value()) { |
| SetBadMessage(); |
| Respond(BadMessage()); |
| return; |
| } |
| |
| auto fan_arg = crosapi::mojom::TelemetryDiagnosticFanRoutineArgument::New(); |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| auto result = routines_manager->CreateRoutine( |
| extension_id(), |
| crosapi::mojom::TelemetryDiagnosticRoutineArgument::NewFan( |
| std::move(fan_arg))); |
| |
| if (!result.has_value()) { |
| switch (result.error()) { |
| case DiagnosticRoutineManager::kAppUiClosed: |
| Respond(Error("Companion app UI is not open.")); |
| break; |
| case DiagnosticRoutineManager::kExtensionUnloaded: |
| Respond(Error("Extension has been unloaded.")); |
| break; |
| } |
| return; |
| } |
| |
| cx_diag::CreateRoutineResponse response; |
| response.uuid = result->AsLowercaseString(); |
| Respond(ArgumentList(cx_diag::CreateFanRoutine::Results::Create(response))); |
| } |
| |
| // OsDiagnosticsStartRoutineFunction ------------------------------------------- |
| |
| void OsDiagnosticsStartRoutineFunction::RunIfAllowed() { |
| auto params = GetParams<cx_diag::StartRoutine::Params>(); |
| if (!params.has_value()) { |
| return; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| bool result = routines_manager->StartRoutineForExtension( |
| extension_id(), base::Uuid::ParseLowercase(params.value().request.uuid)); |
| |
| if (!result) { |
| RespondWithError("Unknown routine id."); |
| return; |
| } |
| |
| Respond(NoArguments()); |
| } |
| |
| // OsDiagnosticsCancelRoutineFunction ------------------------------------------ |
| |
| void OsDiagnosticsCancelRoutineFunction::RunIfAllowed() { |
| auto params = GetParams<cx_diag::CancelRoutine::Params>(); |
| if (!params.has_value()) { |
| return; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| routines_manager->CancelRoutineForExtension( |
| extension_id(), base::Uuid::ParseLowercase(params.value().request.uuid)); |
| |
| Respond(NoArguments()); |
| } |
| |
| // OsDiagnosticsReplyToRoutineInquiryFunction ---------------------------------- |
| |
| void OsDiagnosticsReplyToRoutineInquiryFunction::RunIfAllowed() { |
| auto params = cx_diag::ReplyToRoutineInquiry::Params::Create(args()); |
| if (!params.has_value()) { |
| Respond(BadMessage()); |
| return; |
| } |
| |
| std::optional<crosapi::mojom::TelemetryDiagnosticRoutineInquiryReplyPtr> |
| mojo_reply = converters::diagnostics::ConvertRoutineInquiryReplyUnion( |
| std::move(params->request.reply)); |
| if (!mojo_reply.has_value()) { |
| RespondWithError("Inquiry reply is invalid."); |
| return; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| bool result = routines_manager->ReplyToRoutineInquiryForExtension( |
| extension_id(), base::Uuid::ParseLowercase(params.value().request.uuid), |
| std::move(mojo_reply.value())); |
| |
| if (!result) { |
| RespondWithError("Unknown routine id."); |
| return; |
| } |
| |
| Respond(NoArguments()); |
| } |
| |
| // OsDiagnosticsIsRoutineArgumentSupportedFunction ----------------------- |
| |
| void OsDiagnosticsIsRoutineArgumentSupportedFunction::RunIfAllowed() { |
| auto params = GetParams<cx_diag::IsRoutineArgumentSupported::Params>(); |
| if (!params.has_value()) { |
| return; |
| } |
| |
| std::optional<crosapi::mojom::TelemetryDiagnosticRoutineArgumentPtr> |
| mojo_arg = converters::diagnostics::ConvertRoutineArgumentsUnion( |
| std::move(params->args)); |
| if (!mojo_arg.has_value()) { |
| RespondWithError("Routine arguments are invalid."); |
| return; |
| } |
| |
| // Block unreleased features behind the feature flag. |
| if (IsPendingApprovalRoutine(mojo_arg.value()) && |
| !base::FeatureList::IsEnabled( |
| extensions_features::kTelemetryExtensionPendingApprovalApi)) { |
| mojo_arg = crosapi::mojom::TelemetryDiagnosticRoutineArgument:: |
| NewUnrecognizedArgument(false); |
| } |
| |
| RecordRoutineSupportedStatusQuery(mojo_arg.value()->which()); |
| |
| // Network bandwidth routine is guarded by `os.diagnostics.network_info_mlab` |
| // permission. |
| if (mojo_arg.value()->is_network_bandwidth() && |
| !extension()->permissions_data()->HasAPIPermission( |
| extensions::mojom::APIPermissionID:: |
| kChromeOSDiagnosticsNetworkInfoForMlab)) { |
| RespondWithError( |
| "Unauthorized access to " |
| "chrome.os.diagnostics.isRoutineArgumentSupported with " |
| "networkBandwidth argument. Extension doesn't have the permission."); |
| return; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| routines_manager->IsRoutineArgumentSupported( |
| std::move(mojo_arg.value()), |
| base::BindOnce(&OsDiagnosticsIsRoutineArgumentSupportedFunction::OnResult, |
| this)); |
| } |
| |
| void OsDiagnosticsIsRoutineArgumentSupportedFunction::OnResult( |
| crosapi::mojom::TelemetryExtensionSupportStatusPtr result) { |
| if (result.is_null()) { |
| RespondWithError("API internal error."); |
| return; |
| } |
| |
| auto response = ParseRoutineArgumentSupportResult(std::move(result)); |
| |
| if (!response.has_value()) { |
| RespondWithError(response.error()); |
| return; |
| } |
| |
| Respond(ArgumentList( |
| cx_diag::IsRoutineArgumentSupported::Results::Create(response.value()))); |
| } |
| |
| // OsDiagnosticsIsMemoryRoutineArgumentSupportedFunction ----------------------- |
| |
| void OsDiagnosticsIsMemoryRoutineArgumentSupportedFunction::RunIfAllowed() { |
| auto params = GetParams<cx_diag::IsMemoryRoutineArgumentSupported::Params>(); |
| if (!params.has_value()) { |
| return; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| auto mem_args = |
| crosapi::mojom::TelemetryDiagnosticMemoryRoutineArgument::New(); |
| mem_args->max_testing_mem_kib = params.value().args.max_testing_mem_kib; |
| |
| auto args = crosapi::mojom::TelemetryDiagnosticRoutineArgument::NewMemory( |
| std::move(mem_args)); |
| routines_manager->IsRoutineArgumentSupported( |
| std::move(args), |
| base::BindOnce( |
| &OsDiagnosticsIsMemoryRoutineArgumentSupportedFunction::OnResult, |
| this)); |
| } |
| |
| void OsDiagnosticsIsMemoryRoutineArgumentSupportedFunction::OnResult( |
| crosapi::mojom::TelemetryExtensionSupportStatusPtr result) { |
| if (result.is_null()) { |
| RespondWithError("API internal error."); |
| return; |
| } |
| |
| auto response = ParseRoutineArgumentSupportResult(std::move(result)); |
| |
| if (!response.has_value()) { |
| RespondWithError(response.error()); |
| return; |
| } |
| |
| Respond( |
| ArgumentList(cx_diag::IsMemoryRoutineArgumentSupported::Results::Create( |
| response.value()))); |
| } |
| |
| // OsDiagnosticsIsVolumeButtonRoutineArgumentSupportedFunction |
| // ----------------------- |
| |
| void OsDiagnosticsIsVolumeButtonRoutineArgumentSupportedFunction:: |
| RunIfAllowed() { |
| auto params = |
| GetParams<cx_diag::IsVolumeButtonRoutineArgumentSupported::Params>(); |
| if (!params.has_value() || params.value().args.timeout_seconds <= 0 || |
| params.value().args.button_type == cx_diag::VolumeButtonType::kNone) { |
| return; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| auto volume_button_args = |
| crosapi::mojom::TelemetryDiagnosticVolumeButtonRoutineArgument::New(); |
| volume_button_args->type = |
| converters::diagnostics::ConvertVolumeButtonRoutineButtonType( |
| params.value().args.button_type); |
| volume_button_args->timeout = |
| base::Seconds(params.value().args.timeout_seconds); |
| |
| auto args = |
| crosapi::mojom::TelemetryDiagnosticRoutineArgument::NewVolumeButton( |
| std::move(volume_button_args)); |
| routines_manager->IsRoutineArgumentSupported( |
| std::move(args), |
| base::BindOnce( |
| &OsDiagnosticsIsVolumeButtonRoutineArgumentSupportedFunction:: |
| OnResult, |
| this)); |
| } |
| |
| void OsDiagnosticsIsVolumeButtonRoutineArgumentSupportedFunction::OnResult( |
| crosapi::mojom::TelemetryExtensionSupportStatusPtr result) { |
| if (result.is_null()) { |
| RespondWithError("API internal error."); |
| return; |
| } |
| |
| auto response = ParseRoutineArgumentSupportResult(std::move(result)); |
| |
| if (!response.has_value()) { |
| RespondWithError(response.error()); |
| return; |
| } |
| |
| Respond(ArgumentList( |
| cx_diag::IsVolumeButtonRoutineArgumentSupported::Results::Create( |
| response.value()))); |
| } |
| |
| // OsDiagnosticsIsFanRoutineArgumentSupportedFunction ----------------------- |
| |
| void OsDiagnosticsIsFanRoutineArgumentSupportedFunction::RunIfAllowed() { |
| auto params = GetParams<cx_diag::IsFanRoutineArgumentSupported::Params>(); |
| if (!params.has_value()) { |
| return; |
| } |
| |
| auto* routines_manager = DiagnosticRoutineManager::Get(browser_context()); |
| auto fan_args = crosapi::mojom::TelemetryDiagnosticFanRoutineArgument::New(); |
| |
| auto args = crosapi::mojom::TelemetryDiagnosticRoutineArgument::NewFan( |
| std::move(fan_args)); |
| routines_manager->IsRoutineArgumentSupported( |
| std::move(args), |
| base::BindOnce( |
| &OsDiagnosticsIsFanRoutineArgumentSupportedFunction::OnResult, this)); |
| } |
| |
| void OsDiagnosticsIsFanRoutineArgumentSupportedFunction::OnResult( |
| crosapi::mojom::TelemetryExtensionSupportStatusPtr result) { |
| if (result.is_null()) { |
| RespondWithError("API internal error."); |
| return; |
| } |
| |
| auto response = ParseRoutineArgumentSupportResult(std::move(result)); |
| |
| if (!response.has_value()) { |
| RespondWithError(response.error()); |
| return; |
| } |
| |
| Respond(ArgumentList(cx_diag::IsFanRoutineArgumentSupported::Results::Create( |
| response.value()))); |
| } |
| |
| } // namespace chromeos |