1*6777b538SAndroid Build Coastguard Worker // Copyright 2022 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "components/metrics/motherboard.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <optional>
8*6777b538SAndroid Build Coastguard Worker #include <string>
9*6777b538SAndroid Build Coastguard Worker #include <utility>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
14*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
17*6777b538SAndroid Build Coastguard Worker #include <windows.h>
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_bstr.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_variant.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/win/wmi.h"
24*6777b538SAndroid Build Coastguard Worker #endif
25*6777b538SAndroid Build Coastguard Worker
26*6777b538SAndroid Build Coastguard Worker namespace metrics {
27*6777b538SAndroid Build Coastguard Worker namespace {
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker struct MotherboardDetails {
30*6777b538SAndroid Build Coastguard Worker std::optional<std::string> manufacturer;
31*6777b538SAndroid Build Coastguard Worker std::optional<std::string> model;
32*6777b538SAndroid Build Coastguard Worker std::optional<std::string> bios_manufacturer;
33*6777b538SAndroid Build Coastguard Worker std::optional<std::string> bios_version;
34*6777b538SAndroid Build Coastguard Worker std::optional<Motherboard::BiosType> bios_type;
35*6777b538SAndroid Build Coastguard Worker };
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_LINUX)
38*6777b538SAndroid Build Coastguard Worker using base::FilePath;
39*6777b538SAndroid Build Coastguard Worker using base::PathExists;
40*6777b538SAndroid Build Coastguard Worker using base::ReadFileToString;
41*6777b538SAndroid Build Coastguard Worker using base::TrimWhitespaceASCII;
42*6777b538SAndroid Build Coastguard Worker using base::TRIM_TRAILING;
43*6777b538SAndroid Build Coastguard Worker
ReadMotherboardDetails()44*6777b538SAndroid Build Coastguard Worker MotherboardDetails ReadMotherboardDetails() {
45*6777b538SAndroid Build Coastguard Worker constexpr FilePath::CharType kDmiPath[] = "/sys/devices/virtual/dmi/id";
46*6777b538SAndroid Build Coastguard Worker constexpr FilePath::CharType kEfiPath[] = "/sys/firmware/efi";
47*6777b538SAndroid Build Coastguard Worker const FilePath dmi_path(kDmiPath);
48*6777b538SAndroid Build Coastguard Worker MotherboardDetails details;
49*6777b538SAndroid Build Coastguard Worker std::string temp;
50*6777b538SAndroid Build Coastguard Worker if (ReadFileToString(dmi_path.Append("board_vendor"), &temp)) {
51*6777b538SAndroid Build Coastguard Worker details.manufacturer =
52*6777b538SAndroid Build Coastguard Worker std::string(TrimWhitespaceASCII(temp, TRIM_TRAILING));
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker if (ReadFileToString(dmi_path.Append("board_name"), &temp)) {
55*6777b538SAndroid Build Coastguard Worker details.model = std::string(TrimWhitespaceASCII(temp, TRIM_TRAILING));
56*6777b538SAndroid Build Coastguard Worker }
57*6777b538SAndroid Build Coastguard Worker if (ReadFileToString(dmi_path.Append("bios_vendor"), &temp)) {
58*6777b538SAndroid Build Coastguard Worker details.bios_manufacturer =
59*6777b538SAndroid Build Coastguard Worker std::string(TrimWhitespaceASCII(temp, TRIM_TRAILING));
60*6777b538SAndroid Build Coastguard Worker }
61*6777b538SAndroid Build Coastguard Worker if (ReadFileToString(dmi_path.Append("bios_version"), &temp)) {
62*6777b538SAndroid Build Coastguard Worker details.bios_version =
63*6777b538SAndroid Build Coastguard Worker std::string(TrimWhitespaceASCII(temp, TRIM_TRAILING));
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker if (PathExists(FilePath(kEfiPath))) {
66*6777b538SAndroid Build Coastguard Worker details.bios_type = Motherboard::BiosType::kUefi;
67*6777b538SAndroid Build Coastguard Worker } else {
68*6777b538SAndroid Build Coastguard Worker details.bios_type = Motherboard::BiosType::kLegacy;
69*6777b538SAndroid Build Coastguard Worker }
70*6777b538SAndroid Build Coastguard Worker return details;
71*6777b538SAndroid Build Coastguard Worker }
72*6777b538SAndroid Build Coastguard Worker #endif
73*6777b538SAndroid Build Coastguard Worker
74*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
75*6777b538SAndroid Build Coastguard Worker using Microsoft::WRL::ComPtr;
76*6777b538SAndroid Build Coastguard Worker using base::win::ScopedBstr;
77*6777b538SAndroid Build Coastguard Worker using base::win::ScopedVariant;
78*6777b538SAndroid Build Coastguard Worker
ReadStringMember(ComPtr<IWbemClassObject> class_object,const wchar_t * key)79*6777b538SAndroid Build Coastguard Worker std::optional<std::string> ReadStringMember(
80*6777b538SAndroid Build Coastguard Worker ComPtr<IWbemClassObject> class_object,
81*6777b538SAndroid Build Coastguard Worker const wchar_t* key) {
82*6777b538SAndroid Build Coastguard Worker ScopedVariant variant;
83*6777b538SAndroid Build Coastguard Worker HRESULT hr = class_object->Get(key, 0, variant.Receive(), 0, 0);
84*6777b538SAndroid Build Coastguard Worker if (SUCCEEDED(hr) && variant.type() == VT_BSTR) {
85*6777b538SAndroid Build Coastguard Worker const auto len = ::SysStringLen(V_BSTR(variant.ptr()));
86*6777b538SAndroid Build Coastguard Worker std::wstring wstr(V_BSTR(variant.ptr()), len);
87*6777b538SAndroid Build Coastguard Worker return base::WideToUTF8(wstr);
88*6777b538SAndroid Build Coastguard Worker }
89*6777b538SAndroid Build Coastguard Worker return {};
90*6777b538SAndroid Build Coastguard Worker }
91*6777b538SAndroid Build Coastguard Worker
ReadWin32BaseBoard(const ComPtr<IWbemServices> & services,std::optional<std::string> * manufacturer,std::optional<std::string> * model)92*6777b538SAndroid Build Coastguard Worker void ReadWin32BaseBoard(const ComPtr<IWbemServices>& services,
93*6777b538SAndroid Build Coastguard Worker std::optional<std::string>* manufacturer,
94*6777b538SAndroid Build Coastguard Worker std::optional<std::string>* model) {
95*6777b538SAndroid Build Coastguard Worker static constexpr wchar_t kManufacturer[] = L"Manufacturer";
96*6777b538SAndroid Build Coastguard Worker static constexpr wchar_t kProduct[] = L"Product";
97*6777b538SAndroid Build Coastguard Worker static constexpr wchar_t kQueryProcessor[] =
98*6777b538SAndroid Build Coastguard Worker L"SELECT Manufacturer,Product FROM Win32_BaseBoard";
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard Worker ComPtr<IEnumWbemClassObject> enumerator_base_board;
101*6777b538SAndroid Build Coastguard Worker HRESULT hr = services->ExecQuery(
102*6777b538SAndroid Build Coastguard Worker ScopedBstr(L"WQL").Get(), ScopedBstr(kQueryProcessor).Get(),
103*6777b538SAndroid Build Coastguard Worker WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
104*6777b538SAndroid Build Coastguard Worker &enumerator_base_board);
105*6777b538SAndroid Build Coastguard Worker if (FAILED(hr) || !enumerator_base_board.Get())
106*6777b538SAndroid Build Coastguard Worker return;
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker ComPtr<IWbemClassObject> class_object;
109*6777b538SAndroid Build Coastguard Worker ULONG items_returned = 0;
110*6777b538SAndroid Build Coastguard Worker hr = enumerator_base_board->Next(WBEM_INFINITE, 1, &class_object,
111*6777b538SAndroid Build Coastguard Worker &items_returned);
112*6777b538SAndroid Build Coastguard Worker if (FAILED(hr) || !items_returned)
113*6777b538SAndroid Build Coastguard Worker return;
114*6777b538SAndroid Build Coastguard Worker *manufacturer = ReadStringMember(class_object, kManufacturer);
115*6777b538SAndroid Build Coastguard Worker *model = ReadStringMember(class_object, kProduct);
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker
ReadWin32Bios(const ComPtr<IWbemServices> & services,std::optional<std::string> * bios_manufacturer,std::optional<std::string> * bios_version)118*6777b538SAndroid Build Coastguard Worker void ReadWin32Bios(const ComPtr<IWbemServices>& services,
119*6777b538SAndroid Build Coastguard Worker std::optional<std::string>* bios_manufacturer,
120*6777b538SAndroid Build Coastguard Worker std::optional<std::string>* bios_version) {
121*6777b538SAndroid Build Coastguard Worker static constexpr wchar_t kManufacturer[] = L"Manufacturer";
122*6777b538SAndroid Build Coastguard Worker static constexpr wchar_t kVersion[] = L"Version";
123*6777b538SAndroid Build Coastguard Worker static constexpr wchar_t kQueryProcessor[] =
124*6777b538SAndroid Build Coastguard Worker L"SELECT Manufacturer,Version FROM Win32_BIOS";
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker ComPtr<IEnumWbemClassObject> enumerator_base_board;
127*6777b538SAndroid Build Coastguard Worker HRESULT hr = services->ExecQuery(
128*6777b538SAndroid Build Coastguard Worker ScopedBstr(L"WQL").Get(), ScopedBstr(kQueryProcessor).Get(),
129*6777b538SAndroid Build Coastguard Worker WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
130*6777b538SAndroid Build Coastguard Worker &enumerator_base_board);
131*6777b538SAndroid Build Coastguard Worker if (FAILED(hr) || !enumerator_base_board.Get())
132*6777b538SAndroid Build Coastguard Worker return;
133*6777b538SAndroid Build Coastguard Worker
134*6777b538SAndroid Build Coastguard Worker ComPtr<IWbemClassObject> class_object;
135*6777b538SAndroid Build Coastguard Worker ULONG items_returned = 0;
136*6777b538SAndroid Build Coastguard Worker hr = enumerator_base_board->Next(WBEM_INFINITE, 1, &class_object,
137*6777b538SAndroid Build Coastguard Worker &items_returned);
138*6777b538SAndroid Build Coastguard Worker if (FAILED(hr) || !items_returned)
139*6777b538SAndroid Build Coastguard Worker return;
140*6777b538SAndroid Build Coastguard Worker *bios_manufacturer = ReadStringMember(class_object, kManufacturer);
141*6777b538SAndroid Build Coastguard Worker *bios_version = ReadStringMember(class_object, kVersion);
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker
ReadFirmwareType(std::optional<Motherboard::BiosType> * bios_type)144*6777b538SAndroid Build Coastguard Worker void ReadFirmwareType(std::optional<Motherboard::BiosType>* bios_type) {
145*6777b538SAndroid Build Coastguard Worker FIRMWARE_TYPE firmware_type = FirmwareTypeUnknown;
146*6777b538SAndroid Build Coastguard Worker if (::GetFirmwareType(&firmware_type)) {
147*6777b538SAndroid Build Coastguard Worker if (firmware_type == FirmwareTypeBios) {
148*6777b538SAndroid Build Coastguard Worker *bios_type = Motherboard::BiosType::kLegacy;
149*6777b538SAndroid Build Coastguard Worker } else if (firmware_type == FirmwareTypeUefi) {
150*6777b538SAndroid Build Coastguard Worker *bios_type = Motherboard::BiosType::kUefi;
151*6777b538SAndroid Build Coastguard Worker } else {
152*6777b538SAndroid Build Coastguard Worker *bios_type = std::nullopt;
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker }
155*6777b538SAndroid Build Coastguard Worker }
156*6777b538SAndroid Build Coastguard Worker
ReadMotherboardDetails()157*6777b538SAndroid Build Coastguard Worker MotherboardDetails ReadMotherboardDetails() {
158*6777b538SAndroid Build Coastguard Worker base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
159*6777b538SAndroid Build Coastguard Worker base::BlockingType::MAY_BLOCK);
160*6777b538SAndroid Build Coastguard Worker ComPtr<IWbemServices> services;
161*6777b538SAndroid Build Coastguard Worker MotherboardDetails details;
162*6777b538SAndroid Build Coastguard Worker if (!base::win::CreateLocalWmiConnection(true, &services))
163*6777b538SAndroid Build Coastguard Worker return details;
164*6777b538SAndroid Build Coastguard Worker ReadWin32BaseBoard(services, &details.manufacturer, &details.model);
165*6777b538SAndroid Build Coastguard Worker ReadWin32Bios(services, &details.bios_manufacturer, &details.bios_version);
166*6777b538SAndroid Build Coastguard Worker ReadFirmwareType(&details.bios_type);
167*6777b538SAndroid Build Coastguard Worker return details;
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker #endif
170*6777b538SAndroid Build Coastguard Worker } // namespace
171*6777b538SAndroid Build Coastguard Worker
172*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
Motherboard()173*6777b538SAndroid Build Coastguard Worker Motherboard::Motherboard() {
174*6777b538SAndroid Build Coastguard Worker const auto details = ReadMotherboardDetails();
175*6777b538SAndroid Build Coastguard Worker manufacturer_ = std::move(details.manufacturer),
176*6777b538SAndroid Build Coastguard Worker model_ = std::move(details.model),
177*6777b538SAndroid Build Coastguard Worker bios_manufacturer_ = std::move(details.bios_manufacturer),
178*6777b538SAndroid Build Coastguard Worker bios_version_ = std::move(details.bios_version),
179*6777b538SAndroid Build Coastguard Worker bios_type_ = std::move(details.bios_type);
180*6777b538SAndroid Build Coastguard Worker }
181*6777b538SAndroid Build Coastguard Worker #else
182*6777b538SAndroid Build Coastguard Worker Motherboard::Motherboard() = default;
183*6777b538SAndroid Build Coastguard Worker #endif
184*6777b538SAndroid Build Coastguard Worker
185*6777b538SAndroid Build Coastguard Worker Motherboard::~Motherboard() = default;
186*6777b538SAndroid Build Coastguard Worker
187*6777b538SAndroid Build Coastguard Worker } // namespace metrics
188