Commit 191960b6 authored by Chris Davis (EDGE)'s avatar Chris Davis (EDGE) Committed by Chromium LUCI CQ

Replace WMI call in GetHardwareInfoSync with simple registry read

During early startup a call is made to GetHardwareInfoSync which
queries WMI for the model, manufacturer and serial number.  Querying
WMI is an outbound call that can hang.  I have looked at traces
showing 100-500ms outbound hangs.  The model and manufacturer strings
can be read from the registry for windows in a known location.  This
isn't the case for the bios serial number, but it turns out nobody is
using that anyways (at least through GetHardwareInfoSync) so I am
removing it.

Bug: 1164623

Change-Id: Iabb414f42f75008730440529b055d5951ce37dcc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2619419Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Reviewed-by: default avatarOwen Min <zmin@chromium.org>
Commit-Queue: Chris Davis <chrdavis@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#842638}
parent 37254def
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task/task_traits.h" #include "base/task/task_traits.h"
#include "base/task/thread_pool.h" #include "base/task/thread_pool.h"
#include "base/task_runner_util.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h" #include "build/chromeos_buildflags.h"
...@@ -92,16 +91,7 @@ std::string SysInfo::HardwareModelName() { ...@@ -92,16 +91,7 @@ std::string SysInfo::HardwareModelName() {
#endif #endif
void SysInfo::GetHardwareInfo(base::OnceCallback<void(HardwareInfo)> callback) { void SysInfo::GetHardwareInfo(base::OnceCallback<void(HardwareInfo)> callback) {
#if defined(OS_WIN) #if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_APPLE)
// On Windows the calls to GetHardwareInfoSync can take a really long time to
// complete as they depend on WMI, using the CONTINUE_ON_SHUTDOWN traits will
// prevent this task from blocking shutdown.
base::PostTaskAndReplyWithResult(
base::ThreadPool::CreateCOMSTATaskRunner(
{TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})
.get(),
FROM_HERE, base::BindOnce(&GetHardwareInfoSync), std::move(callback));
#elif defined(OS_ANDROID) || defined(OS_APPLE)
base::ThreadPool::PostTaskAndReplyWithResult( base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {}, base::BindOnce(&GetHardwareInfoSync), std::move(callback)); FROM_HERE, {}, base::BindOnce(&GetHardwareInfoSync), std::move(callback));
#elif defined(OS_LINUX) || defined(OS_CHROMEOS) #elif defined(OS_LINUX) || defined(OS_CHROMEOS)
......
...@@ -85,16 +85,6 @@ class BASE_EXPORT SysInfo { ...@@ -85,16 +85,6 @@ class BASE_EXPORT SysInfo {
struct HardwareInfo { struct HardwareInfo {
std::string manufacturer; std::string manufacturer;
std::string model; std::string model;
// On Windows, this is the BIOS serial number. Unsupported platforms will be
// set to an empty string.
// Note: validate any new usage with the privacy team.
// TODO(crbug.com/907518): Implement support on other platforms.
std::string serial_number;
bool operator==(const HardwareInfo& rhs) const {
return manufacturer == rhs.manufacturer && model == rhs.model &&
serial_number == rhs.serial_number;
}
}; };
// Returns via |callback| a struct containing descriptive UTF-8 strings for // Returns via |callback| a struct containing descriptive UTF-8 strings for
// the current machine manufacturer and model, or empty strings if the // the current machine manufacturer and model, or empty strings if the
......
...@@ -16,12 +16,22 @@ ...@@ -16,12 +16,22 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/test/scoped_chromeos_version_info.h" #include "base/test/scoped_chromeos_version_info.h"
#include "base/test/scoped_running_on_chromeos.h" #include "base/test/scoped_running_on_chromeos.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h" #include "base/time/time.h"
#if defined(OS_WIN)
#include "base/win/com_init_util.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_variant.h"
#include "base/win/wmi.h"
#endif // defined(OS_WIN)
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromeos_buildflags.h" #include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest-death-test.h" #include "testing/gtest/include/gtest/gtest-death-test.h"
...@@ -207,14 +217,63 @@ TEST_F(SysInfoTest, GetHardwareInfo) { ...@@ -207,14 +217,63 @@ TEST_F(SysInfoTest, GetHardwareInfo) {
#endif #endif
EXPECT_EQ(hardware_info->manufacturer.empty(), empty_result_expected); EXPECT_EQ(hardware_info->manufacturer.empty(), empty_result_expected);
EXPECT_EQ(hardware_info->model.empty(), empty_result_expected); EXPECT_EQ(hardware_info->model.empty(), empty_result_expected);
}
#if defined(OS_WIN) #if defined(OS_WIN)
EXPECT_FALSE(hardware_info->serial_number.empty()); TEST_F(SysInfoTest, GetHardwareInfoWMIMatchRegistry) {
#else base::win::ScopedCOMInitializer com_initializer;
// TODO(crbug.com/907518): Implement support on other platforms. test::TaskEnvironment task_environment;
EXPECT_EQ(hardware_info->serial_number, std::string()); base::Optional<SysInfo::HardwareInfo> hardware_info;
#endif
auto callback = base::BindOnce(
[](base::Optional<SysInfo::HardwareInfo>* target_info,
SysInfo::HardwareInfo info) { *target_info = std::move(info); },
&hardware_info);
SysInfo::GetHardwareInfo(std::move(callback));
task_environment.RunUntilIdle();
ASSERT_TRUE(hardware_info.has_value());
Microsoft::WRL::ComPtr<IWbemServices> wmi_services;
EXPECT_TRUE(base::win::CreateLocalWmiConnection(true, &wmi_services));
static constexpr wchar_t query_computer_system[] =
L"SELECT Manufacturer,Model FROM Win32_ComputerSystem";
Microsoft::WRL::ComPtr<IEnumWbemClassObject> enumerator_computer_system;
HRESULT hr = wmi_services->ExecQuery(
base::win::ScopedBstr(L"WQL").Get(),
base::win::ScopedBstr(query_computer_system).Get(),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
&enumerator_computer_system);
EXPECT_FALSE(FAILED(hr) || !enumerator_computer_system.Get());
Microsoft::WRL::ComPtr<IWbemClassObject> class_object;
ULONG items_returned = 0;
hr = enumerator_computer_system->Next(WBEM_INFINITE, 1, &class_object,
&items_returned);
EXPECT_FALSE(FAILED(hr) || !items_returned);
base::win::ScopedVariant manufacturerVar;
std::wstring manufacturer;
hr = class_object->Get(L"Manufacturer", 0, manufacturerVar.Receive(), nullptr,
nullptr);
if (SUCCEEDED(hr) && manufacturerVar.type() == VT_BSTR) {
manufacturer.assign(V_BSTR(manufacturerVar.ptr()),
::SysStringLen(V_BSTR(manufacturerVar.ptr())));
}
base::win::ScopedVariant modelVar;
std::wstring model;
hr = class_object->Get(L"Model", 0, modelVar.Receive(), nullptr, nullptr);
if (SUCCEEDED(hr) && modelVar.type() == VT_BSTR) {
model.assign(V_BSTR(modelVar.ptr()),
::SysStringLen(V_BSTR(modelVar.ptr())));
}
EXPECT_TRUE(hardware_info->manufacturer == base::SysWideToUTF8(manufacturer));
EXPECT_TRUE(hardware_info->model == base::SysWideToUTF8(model));
} }
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
......
...@@ -16,10 +16,11 @@ ...@@ -16,10 +16,11 @@
#include "base/process/process_metrics.h" #include "base/process/process_metrics.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/threading/scoped_blocking_call.h" #include "base/threading/scoped_blocking_call.h"
#include "base/win/registry.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "base/win/wmi.h"
namespace { namespace {
...@@ -168,15 +169,26 @@ void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version, ...@@ -168,15 +169,26 @@ void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
// static // static
SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() { SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() {
win::WmiComputerSystemInfo wmi_info = win::WmiComputerSystemInfo::Get(); constexpr base::char16 kSystemBiosInformationRegKey[] =
L"HARDWARE\\DESCRIPTION\\System\\BIOS";
HardwareInfo info; HardwareInfo info;
info.manufacturer = WideToUTF8(wmi_info.manufacturer()); base::win::RegKey system_information_key;
info.model = WideToUTF8(wmi_info.model()); if (system_information_key.Open(HKEY_LOCAL_MACHINE,
info.serial_number = WideToUTF8(wmi_info.serial_number()); kSystemBiosInformationRegKey,
DCHECK(IsStringUTF8(info.manufacturer)); KEY_READ) == ERROR_SUCCESS) {
DCHECK(IsStringUTF8(info.model)); base::string16 value16;
DCHECK(IsStringUTF8(info.serial_number)); if (system_information_key.ReadValue(L"SystemManufacturer", &value16) ==
ERROR_SUCCESS) {
info.manufacturer = base::SysWideToUTF8(value16);
}
if (system_information_key.ReadValue(L"SystemProductName", &value16) ==
ERROR_SUCCESS) {
info.model = base::SysWideToUTF8(value16);
}
}
return info; return info;
} }
......
...@@ -143,46 +143,11 @@ WmiComputerSystemInfo WmiComputerSystemInfo::Get() { ...@@ -143,46 +143,11 @@ WmiComputerSystemInfo WmiComputerSystemInfo::Get() {
if (!CreateLocalWmiConnection(true, &services)) if (!CreateLocalWmiConnection(true, &services))
return info; return info;
info.PopulateModelAndManufacturer(services);
info.PopulateSerialNumber(services); info.PopulateSerialNumber(services);
return info; return info;
} }
void WmiComputerSystemInfo::PopulateModelAndManufacturer(
const ComPtr<IWbemServices>& services) {
static constexpr WStringPiece query_computer_system =
L"SELECT Manufacturer,Model FROM Win32_ComputerSystem";
ComPtr<IEnumWbemClassObject> enumerator_computer_system;
HRESULT hr = services->ExecQuery(
ScopedBstr(L"WQL").Get(), ScopedBstr(query_computer_system).Get(),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
&enumerator_computer_system);
if (FAILED(hr) || !enumerator_computer_system.Get())
return;
ComPtr<IWbemClassObject> class_object;
ULONG items_returned = 0;
hr = enumerator_computer_system->Next(WBEM_INFINITE, 1, &class_object,
&items_returned);
if (FAILED(hr) || !items_returned)
return;
ScopedVariant manufacturer;
hr = class_object->Get(L"Manufacturer", 0, manufacturer.Receive(), nullptr,
nullptr);
if (SUCCEEDED(hr) && manufacturer.type() == VT_BSTR) {
manufacturer_.assign(V_BSTR(manufacturer.ptr()),
::SysStringLen(V_BSTR(manufacturer.ptr())));
}
ScopedVariant model;
hr = class_object->Get(L"Model", 0, model.Receive(), nullptr, nullptr);
if (SUCCEEDED(hr) && model.type() == VT_BSTR) {
model_.assign(V_BSTR(model.ptr()), ::SysStringLen(V_BSTR(model.ptr())));
}
}
void WmiComputerSystemInfo::PopulateSerialNumber( void WmiComputerSystemInfo::PopulateSerialNumber(
const ComPtr<IWbemServices>& services) { const ComPtr<IWbemServices>& services) {
static constexpr WStringPiece query_bios = static constexpr WStringPiece query_bios =
......
...@@ -67,22 +67,19 @@ BASE_EXPORT bool WmiLaunchProcess(const std::wstring& command_line, ...@@ -67,22 +67,19 @@ BASE_EXPORT bool WmiLaunchProcess(const std::wstring& command_line,
// 'Win32_Bios' WMI classes; see : // 'Win32_Bios' WMI classes; see :
// https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-computersystem // https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-computersystem
// https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-systembios // https://docs.microsoft.com/en-us/windows/desktop/CIMWin32Prov/win32-systembios
// Note that while model and manufacturer can be obtained through WMI, it is
// more efficient to obtain them via SysInfo::GetHardwareInfo() which uses the
// registry.
class BASE_EXPORT WmiComputerSystemInfo { class BASE_EXPORT WmiComputerSystemInfo {
public: public:
static WmiComputerSystemInfo Get(); static WmiComputerSystemInfo Get();
const std::wstring& manufacturer() const { return manufacturer_; }
const std::wstring& model() const { return model_; }
const std::wstring& serial_number() const { return serial_number_; } const std::wstring& serial_number() const { return serial_number_; }
private: private:
void PopulateModelAndManufacturer(
const Microsoft::WRL::ComPtr<IWbemServices>& services);
void PopulateSerialNumber( void PopulateSerialNumber(
const Microsoft::WRL::ComPtr<IWbemServices>& services); const Microsoft::WRL::ComPtr<IWbemServices>& services);
std::wstring manufacturer_;
std::wstring model_;
std::wstring serial_number_; std::wstring serial_number_;
}; };
......
...@@ -59,8 +59,7 @@ TEST_F(WMITest, TestLaunchProcess) { ...@@ -59,8 +59,7 @@ TEST_F(WMITest, TestLaunchProcess) {
TEST_F(WMITest, TestComputerSystemInfo) { TEST_F(WMITest, TestComputerSystemInfo) {
WmiComputerSystemInfo info = WmiComputerSystemInfo::Get(); WmiComputerSystemInfo info = WmiComputerSystemInfo::Get();
EXPECT_FALSE(info.manufacturer().empty()); EXPECT_FALSE(info.serial_number().empty());
EXPECT_FALSE(info.model().empty());
} }
} // namespace win } // namespace win
......
...@@ -15,10 +15,8 @@ ...@@ -15,10 +15,8 @@
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/run_loop.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task_runner_util.h" #include "base/task_runner_util.h"
#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/sequenced_task_runner_handle.h"
...@@ -31,13 +29,6 @@ namespace { ...@@ -31,13 +29,6 @@ namespace {
constexpr char kInvalidTokenValue[] = "INVALID_DM_TOKEN"; constexpr char kInvalidTokenValue[] = "INVALID_DM_TOKEN";
void OnHardwarePlatformInfo(base::OnceClosure quit_closure,
std::string* out,
base::SysInfo::HardwareInfo info) {
*out = info.serial_number;
std::move(quit_closure).Run();
}
DMToken CreateValidToken(const std::string& dm_token) { DMToken CreateValidToken(const std::string& dm_token) {
DCHECK_NE(dm_token, kInvalidTokenValue); DCHECK_NE(dm_token, kInvalidTokenValue);
DCHECK(!dm_token.empty()); DCHECK(!dm_token.empty());
...@@ -96,17 +87,6 @@ std::string BrowserDMTokenStorage::RetrieveClientId() { ...@@ -96,17 +87,6 @@ std::string BrowserDMTokenStorage::RetrieveClientId() {
return client_id_; return client_id_;
} }
std::string BrowserDMTokenStorage::RetrieveSerialNumber() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!serial_number_) {
serial_number_ = InitSerialNumber();
DVLOG(1) << "Serial number= " << serial_number_.value();
}
return serial_number_.value();
}
std::string BrowserDMTokenStorage::RetrieveEnrollmentToken() { std::string BrowserDMTokenStorage::RetrieveEnrollmentToken() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
...@@ -209,20 +189,4 @@ void BrowserDMTokenStorage::SaveDMToken(const std::string& token) { ...@@ -209,20 +189,4 @@ void BrowserDMTokenStorage::SaveDMToken(const std::string& token) {
std::move(reply)); std::move(reply));
} }
std::string BrowserDMTokenStorage::InitSerialNumber() {
// GetHardwareInfo is asynchronous, but we need this synchronously. This call
// will only happens once, as we cache the value. This will eventually be
// moved earlier in Chrome's startup as it will be needed by the registration
// as well.
// TODO(crbug.com/907518): Move this earlier and make it async.
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
std::string serial_number;
base::SysInfo::GetHardwareInfo(base::BindOnce(
&OnHardwarePlatformInfo, run_loop.QuitClosure(), &serial_number));
run_loop.Run();
return serial_number;
}
} // namespace policy } // namespace policy
...@@ -69,8 +69,6 @@ class BrowserDMTokenStorage { ...@@ -69,8 +69,6 @@ class BrowserDMTokenStorage {
// Returns a client ID unique to the machine. // Returns a client ID unique to the machine.
std::string RetrieveClientId(); std::string RetrieveClientId();
// Returns the serial number of the machine.
std::string RetrieveSerialNumber();
// Returns the enrollment token, or an empty string if there is none. // Returns the enrollment token, or an empty string if there is none.
std::string RetrieveEnrollmentToken(); std::string RetrieveEnrollmentToken();
// Asynchronously stores |dm_token| and calls |callback| with a boolean to // Asynchronously stores |dm_token| and calls |callback| with a boolean to
...@@ -120,10 +118,6 @@ class BrowserDMTokenStorage { ...@@ -120,10 +118,6 @@ class BrowserDMTokenStorage {
// is called the first time the BrowserDMTokenStorage is interacted with. // is called the first time the BrowserDMTokenStorage is interacted with.
void InitIfNeeded(); void InitIfNeeded();
// Gets the client ID and returns it. This implementation is shared by all
// platforms.
std::string InitSerialNumber();
// Saves the DM token. // Saves the DM token.
void SaveDMToken(const std::string& token); void SaveDMToken(const std::string& token);
...@@ -133,7 +127,6 @@ class BrowserDMTokenStorage { ...@@ -133,7 +127,6 @@ class BrowserDMTokenStorage {
bool is_initialized_; bool is_initialized_;
std::string client_id_; std::string client_id_;
base::Optional<std::string> serial_number_;
std::string enrollment_token_; std::string enrollment_token_;
DMToken dm_token_; DMToken dm_token_;
bool should_display_error_message_on_failure_; bool should_display_error_message_on_failure_;
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h" #include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment