chromium/chrome/browser/lacros/cros_apps/api/diagnostics/cros_diagnostics_impl.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "chrome/browser/lacros/cros_apps/api/diagnostics/cros_diagnostics_impl.h"

#include "base/functional/bind.h"
#include "base/task/thread_pool.h"
#include "chromeos/lacros/lacros_service.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/render_frame_host.h"
#include "services/network/public/mojom/network_service.mojom.h"

CrosDiagnosticsImpl::~CrosDiagnosticsImpl() = default;

// static
void CrosDiagnosticsImpl::Create(
    content::RenderFrameHost* render_frame_host,
    mojo::PendingReceiver<blink::mojom::CrosDiagnostics> receiver) {
  CHECK(!CrosDiagnosticsImpl::GetForCurrentDocument(render_frame_host));
  CrosDiagnosticsImpl::CreateForCurrentDocument(render_frame_host,
                                                std::move(receiver));
}

CrosDiagnosticsImpl::CrosDiagnosticsImpl(
    content::RenderFrameHost* render_frame_host,
    mojo::PendingReceiver<blink::mojom::CrosDiagnostics> receiver)
    : content::DocumentUserData<CrosDiagnosticsImpl>(render_frame_host),
      cros_diagnostics_receiver_(this, std::move(receiver)) {}

void CrosDiagnosticsImpl::GetCpuInfo(GetCpuInfoCallback callback) {
  auto cpu_info_mojom = blink::mojom::CrosCpuInfo::New();

  chromeos::LacrosService* lacros_service = chromeos::LacrosService::Get();
  if (!lacros_service->IsAvailable<crosapi::mojom::TelemetryProbeService>()) {
    auto error =
        blink::mojom::GetCpuInfoError::kTelemetryProbeServiceUnavailable;
    std::move(callback).Run(
        blink::mojom::GetCpuInfoResult::NewError(std::move(error)));
    return;
  }

  lacros_service->GetRemote<crosapi::mojom::TelemetryProbeService>()
      ->ProbeTelemetryInfo(
          {crosapi::mojom::ProbeCategoryEnum::kCpu},
          base::BindOnce(
              &CrosDiagnosticsImpl::GetCpuInfoProbeTelemetryInfoCallback,
              weak_ptr_factory_.GetWeakPtr(), std::move(callback),
              std::move(cpu_info_mojom)));
}

void CrosDiagnosticsImpl::GetCpuInfoProbeTelemetryInfoCallback(
    GetCpuInfoCallback callback,
    blink::mojom::CrosCpuInfoPtr cpu_info_mojom,
    crosapi::mojom::ProbeTelemetryInfoPtr telemetry_info) {
  CHECK(telemetry_info->cpu_result);
  // TODO(b/298621530): Plumb the error from cpu_result through
  // to the `chromeos.diagnostics.getCpuInfo()` API.
  if (telemetry_info->cpu_result->is_error()) {
    auto error = blink::mojom::GetCpuInfoError::kCpuTelemetryInfoUnavailable;
    std::move(callback).Run(
        blink::mojom::GetCpuInfoResult::NewError(std::move(error)));
    return;
  }

  switch (telemetry_info->cpu_result->get_cpu_info()->architecture) {
    case crosapi::mojom::ProbeCpuArchitectureEnum::kUnknown:
      cpu_info_mojom->architecture =
          blink::mojom::CrosCpuArchitecture::kUnknown;
      break;
    case crosapi::mojom::ProbeCpuArchitectureEnum::kX86_64:
      cpu_info_mojom->architecture = blink::mojom::CrosCpuArchitecture::kX86_64;
      break;
    case crosapi::mojom::ProbeCpuArchitectureEnum::kArmv7l:
      cpu_info_mojom->architecture = blink::mojom::CrosCpuArchitecture::kArm;
      break;
    case crosapi::mojom::ProbeCpuArchitectureEnum::kAArch64:
      cpu_info_mojom->architecture = blink::mojom::CrosCpuArchitecture::kArm64;
      break;
  }

  std::vector<blink::mojom::CrosLogicalCpuInfoPtr> logical_cpu_infos_mojom;

  // Concatenate logical processor infos from each physical CPU.
  for (const auto& physical_cpu :
       telemetry_info->cpu_result->get_cpu_info()->physical_cpus) {
    if (physical_cpu->model_name) {
      // Assume that either only one `physical_cpu` exists, or each different
      // `physical_cpu` shares the same `model_name`.
      cpu_info_mojom->model_name = physical_cpu->model_name.value();
    }
    for (const auto& logical_cpu : physical_cpu->logical_cpus) {
      auto logical_cpu_info_mojom = blink::mojom::CrosLogicalCpuInfo::New();

      if (logical_cpu->core_id) {
        logical_cpu_info_mojom->core_id = logical_cpu->core_id->value;
      }
      if (logical_cpu->idle_time_ms) {
        logical_cpu_info_mojom->idle_time_ms = logical_cpu->idle_time_ms->value;
      }
      if (logical_cpu->max_clock_speed_khz) {
        logical_cpu_info_mojom->max_clock_speed_khz =
            logical_cpu->max_clock_speed_khz->value;
      }
      if (logical_cpu->scaling_current_frequency_khz) {
        logical_cpu_info_mojom->scaling_current_frequency_khz =
            logical_cpu->scaling_current_frequency_khz->value;
      }
      if (logical_cpu->scaling_max_frequency_khz) {
        logical_cpu_info_mojom->scaling_max_frequency_khz =
            logical_cpu->scaling_max_frequency_khz->value;
      }

      logical_cpu_infos_mojom.push_back(std::move(logical_cpu_info_mojom));
    }
  }

  cpu_info_mojom->logical_cpus = std::move(logical_cpu_infos_mojom);
  std::move(callback).Run(
      blink::mojom::GetCpuInfoResult::NewCpuInfo(std::move(cpu_info_mojom)));
}

void CrosDiagnosticsImpl::GetNetworkInterfaces(
    GetNetworkInterfacesCallback callback) {
  content::GetNetworkService()->GetNetworkList(
      net::INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES,
      base::BindOnce(
          &CrosDiagnosticsImpl::GetNetworkInterfacesGetNetworkListCallback,
          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void CrosDiagnosticsImpl::GetNetworkInterfacesGetNetworkListCallback(
    GetNetworkInterfacesCallback callback,
    const std::optional<net::NetworkInterfaceList>& interface_list) {
  if (!interface_list.has_value()) {
    auto error =
        blink::mojom::GetNetworkInterfacesError::kNetworkInterfaceLookupFailed;
    std::move(callback).Run(
        blink::mojom::GetNetworkInterfacesResult::NewError(std::move(error)));
    return;
  }

  std::vector<blink::mojom::CrosNetworkInterfacePtr> network_interfaces_mojom;
  for (const auto& interface : interface_list.value()) {
    auto network_interface_mojom = blink::mojom::CrosNetworkInterface::New();

    network_interface_mojom->address = interface.address.ToString();
    network_interface_mojom->name = interface.name;
    network_interface_mojom->prefix_length = interface.prefix_length;

    network_interfaces_mojom.push_back(std::move(network_interface_mojom));
  }

  std::move(callback).Run(
      blink::mojom::GetNetworkInterfacesResult::NewNetworkInterfaces(
          std::move(network_interfaces_mojom)));
}

DOCUMENT_USER_DATA_KEY_IMPL(CrosDiagnosticsImpl);