chromium/components/metrics/motherboard.cc

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

#include "components/metrics/motherboard.h"

#include <optional>
#include <string>
#include <utility>

#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"

#if BUILDFLAG(IS_WIN)
#include <windows.h>

#include "base/strings/utf_string_conversions.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.h"
#include "base/win/wmi.h"
#endif

namespace metrics {
namespace {

struct MotherboardDetails {};

#if BUILDFLAG(IS_LINUX)
FilePath;
PathExists;
ReadFileToString;
TrimWhitespaceASCII;
TRIM_TRAILING;

MotherboardDetails ReadMotherboardDetails() {}
#endif

#if BUILDFLAG(IS_WIN)
using Microsoft::WRL::ComPtr;
using base::win::ScopedBstr;
using base::win::ScopedVariant;

std::optional<std::string> ReadStringMember(
    ComPtr<IWbemClassObject> class_object,
    const wchar_t* key) {
  ScopedVariant variant;
  HRESULT hr = class_object->Get(key, 0, variant.Receive(), 0, 0);
  if (SUCCEEDED(hr) && variant.type() == VT_BSTR) {
    const auto len = ::SysStringLen(V_BSTR(variant.ptr()));
    std::wstring wstr(V_BSTR(variant.ptr()), len);
    return base::WideToUTF8(wstr);
  }
  return {};
}

void ReadWin32BaseBoard(const ComPtr<IWbemServices>& services,
                        std::optional<std::string>* manufacturer,
                        std::optional<std::string>* model) {
  static constexpr wchar_t kManufacturer[] = L"Manufacturer";
  static constexpr wchar_t kProduct[] = L"Product";
  static constexpr wchar_t kQueryProcessor[] =
      L"SELECT Manufacturer,Product FROM Win32_BaseBoard";

  ComPtr<IEnumWbemClassObject> enumerator_base_board;
  HRESULT hr = services->ExecQuery(
      ScopedBstr(L"WQL").Get(), ScopedBstr(kQueryProcessor).Get(),
      WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
      &enumerator_base_board);
  if (FAILED(hr) || !enumerator_base_board.Get())
    return;

  ComPtr<IWbemClassObject> class_object;
  ULONG items_returned = 0;
  hr = enumerator_base_board->Next(WBEM_INFINITE, 1, &class_object,
                                   &items_returned);
  if (FAILED(hr) || !items_returned)
    return;
  *manufacturer = ReadStringMember(class_object, kManufacturer);
  *model = ReadStringMember(class_object, kProduct);
}

void ReadWin32Bios(const ComPtr<IWbemServices>& services,
                   std::optional<std::string>* bios_manufacturer,
                   std::optional<std::string>* bios_version) {
  static constexpr wchar_t kManufacturer[] = L"Manufacturer";
  static constexpr wchar_t kVersion[] = L"Version";
  static constexpr wchar_t kQueryProcessor[] =
      L"SELECT Manufacturer,Version FROM Win32_BIOS";

  ComPtr<IEnumWbemClassObject> enumerator_base_board;
  HRESULT hr = services->ExecQuery(
      ScopedBstr(L"WQL").Get(), ScopedBstr(kQueryProcessor).Get(),
      WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
      &enumerator_base_board);
  if (FAILED(hr) || !enumerator_base_board.Get())
    return;

  ComPtr<IWbemClassObject> class_object;
  ULONG items_returned = 0;
  hr = enumerator_base_board->Next(WBEM_INFINITE, 1, &class_object,
                                   &items_returned);
  if (FAILED(hr) || !items_returned)
    return;
  *bios_manufacturer = ReadStringMember(class_object, kManufacturer);
  *bios_version = ReadStringMember(class_object, kVersion);
}

void ReadFirmwareType(std::optional<Motherboard::BiosType>* bios_type) {
  FIRMWARE_TYPE firmware_type = FirmwareTypeUnknown;
  if (::GetFirmwareType(&firmware_type)) {
    if (firmware_type == FirmwareTypeBios) {
      *bios_type = Motherboard::BiosType::kLegacy;
    } else if (firmware_type == FirmwareTypeUefi) {
      *bios_type = Motherboard::BiosType::kUefi;
    } else {
      *bios_type = std::nullopt;
    }
  }
}

MotherboardDetails ReadMotherboardDetails() {
  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                base::BlockingType::MAY_BLOCK);
  ComPtr<IWbemServices> services;
  MotherboardDetails details;
  if (!base::win::CreateLocalWmiConnection(true, &services))
    return details;
  ReadWin32BaseBoard(services, &details.manufacturer, &details.model);
  ReadWin32Bios(services, &details.bios_manufacturer, &details.bios_version);
  ReadFirmwareType(&details.bios_type);
  return details;
}
#endif
}  // namespace

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
Motherboard::Motherboard() {}
#else
Motherboard::Motherboard() = default;
#endif

Motherboard::~Motherboard() = default;

}  // namespace metrics