1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/metrics/motherboard.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/strings/string_util.h"
13 #include "build/build_config.h"
14 #include "third_party/abseil-cpp/absl/types/optional.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/scoped_blocking_call.h"
19 #include "base/win/scoped_bstr.h"
20 #include "base/win/scoped_com_initializer.h"
21 #include "base/win/scoped_variant.h"
22 #include "base/win/wmi.h"
28 struct MotherboardDetails {
29 absl::optional<std::string> manufacturer;
30 absl::optional<std::string> model;
31 absl::optional<std::string> bios_manufacturer;
32 absl::optional<std::string> bios_version;
33 absl::optional<Motherboard::BiosType> bios_type;
36 #if BUILDFLAG(IS_LINUX)
38 using base::PathExists;
39 using base::ReadFileToString;
40 using base::TrimWhitespaceASCII;
41 using base::TRIM_TRAILING;
43 MotherboardDetails ReadMotherboardDetails() {
44 constexpr FilePath::CharType kDmiPath[] = "/sys/devices/virtual/dmi/id";
45 constexpr FilePath::CharType kEfiPath[] = "/sys/firmware/efi";
46 const FilePath dmi_path(kDmiPath);
47 MotherboardDetails details;
49 if (ReadFileToString(dmi_path.Append("board_vendor"), &temp)) {
50 details.manufacturer =
51 std::string(TrimWhitespaceASCII(temp, TRIM_TRAILING));
53 if (ReadFileToString(dmi_path.Append("board_name"), &temp)) {
54 details.model = std::string(TrimWhitespaceASCII(temp, TRIM_TRAILING));
56 if (ReadFileToString(dmi_path.Append("bios_vendor"), &temp)) {
57 details.bios_manufacturer =
58 std::string(TrimWhitespaceASCII(temp, TRIM_TRAILING));
60 if (ReadFileToString(dmi_path.Append("bios_version"), &temp)) {
61 details.bios_version =
62 std::string(TrimWhitespaceASCII(temp, TRIM_TRAILING));
64 if (PathExists(FilePath(kEfiPath))) {
65 details.bios_type = Motherboard::BiosType::kUefi;
67 details.bios_type = Motherboard::BiosType::kLegacy;
74 using Microsoft::WRL::ComPtr;
75 using base::win::ScopedBstr;
76 using base::win::ScopedVariant;
78 absl::optional<std::string> ReadStringMember(
79 ComPtr<IWbemClassObject> class_object, const wchar_t* key) {
80 ScopedVariant variant;
81 HRESULT hr = class_object->Get(key, 0, variant.Receive(), 0, 0);
82 if (SUCCEEDED(hr) && variant.type() == VT_BSTR) {
83 const auto len = ::SysStringLen(V_BSTR(variant.ptr()));
84 std::wstring wstr(V_BSTR(variant.ptr()), len);
85 return base::WideToUTF8(wstr);
90 void ReadWin32BaseBoard(const ComPtr<IWbemServices>& services,
91 absl::optional<std::string>* manufacturer,
92 absl::optional<std::string>* model) {
93 static constexpr wchar_t kManufacturer[] = L"Manufacturer";
94 static constexpr wchar_t kProduct[] = L"Product";
95 static constexpr wchar_t kQueryProcessor[] =
96 L"SELECT Manufacturer,Product FROM Win32_BaseBoard";
98 ComPtr<IEnumWbemClassObject> enumerator_base_board;
99 HRESULT hr = services->ExecQuery(
100 ScopedBstr(L"WQL").Get(), ScopedBstr(kQueryProcessor).Get(),
101 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
102 &enumerator_base_board);
103 if (FAILED(hr) || !enumerator_base_board.Get())
106 ComPtr<IWbemClassObject> class_object;
107 ULONG items_returned = 0;
108 hr = enumerator_base_board->Next(WBEM_INFINITE, 1, &class_object,
110 if (FAILED(hr) || !items_returned)
112 *manufacturer = ReadStringMember(class_object, kManufacturer);
113 *model = ReadStringMember(class_object, kProduct);
116 void ReadWin32Bios(const ComPtr<IWbemServices>& services,
117 absl::optional<std::string>* bios_manufacturer,
118 absl::optional<std::string>* bios_version) {
119 static constexpr wchar_t kManufacturer[] = L"Manufacturer";
120 static constexpr wchar_t kVersion[] = L"Version";
121 static constexpr wchar_t kQueryProcessor[] =
122 L"SELECT Manufacturer,Version FROM Win32_BIOS";
124 ComPtr<IEnumWbemClassObject> enumerator_base_board;
125 HRESULT hr = services->ExecQuery(
126 ScopedBstr(L"WQL").Get(), ScopedBstr(kQueryProcessor).Get(),
127 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
128 &enumerator_base_board);
129 if (FAILED(hr) || !enumerator_base_board.Get())
132 ComPtr<IWbemClassObject> class_object;
133 ULONG items_returned = 0;
134 hr = enumerator_base_board->Next(WBEM_INFINITE, 1, &class_object,
136 if (FAILED(hr) || !items_returned)
138 *bios_manufacturer = ReadStringMember(class_object, kManufacturer);
139 *bios_version = ReadStringMember(class_object, kVersion);
142 MotherboardDetails ReadMotherboardDetails() {
143 base::win::ScopedCOMInitializer scoped_com_initializer;
144 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
145 base::BlockingType::MAY_BLOCK);
146 ComPtr<IWbemServices> services;
147 MotherboardDetails details;
148 if (!base::win::CreateLocalWmiConnection(true, &services))
150 ReadWin32BaseBoard(services, &details.manufacturer, &details.model);
151 ReadWin32Bios(services, &details.bios_manufacturer, &details.bios_version);
157 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
158 Motherboard::Motherboard() {
159 const auto details = ReadMotherboardDetails();
160 manufacturer_ = std::move(details.manufacturer),
161 model_ = std::move(details.model),
162 bios_manufacturer_ = std::move(details.bios_manufacturer),
163 bios_version_ = std::move(details.bios_version),
164 bios_type_ = std::move(details.bios_type);
167 Motherboard::Motherboard() = default;
170 Motherboard::~Motherboard() = default;
172 } // namespace metrics