1 // Copyright 2014 The Chromium Authors. All rights reserved.
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/machine_id_provider.h"
10 #include "base/base_paths.h"
11 #include "base/files/file_path.h"
12 #include "base/path_service.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "base/win/scoped_handle.h"
18 MachineIdProvider::MachineIdProvider() {
21 MachineIdProvider::~MachineIdProvider() {
24 // On windows, the machine id is based on the serial number of the drive Chrome
26 std::string
MachineIdProvider::GetMachineId() {
27 base::ThreadRestrictions::AssertIOAllowed();
29 // Use the program's path to get the drive used for the machine id. This means
30 // that whenever the underlying drive changes, it's considered a new machine.
31 // This is fine as we do not support migrating Chrome installs to new drives.
32 base::FilePath executable_path
;
34 if (!PathService::Get(base::FILE_EXE
, &executable_path
)) {
39 std::vector
<base::FilePath::StringType
> path_components
;
40 executable_path
.GetComponents(&path_components
);
41 if (path_components
.empty()) {
45 base::FilePath::StringType drive_name
= L
"\\\\.\\" + path_components
[0];
47 base::win::ScopedHandle
drive_handle(
48 CreateFile(drive_name
.c_str(),
50 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
56 STORAGE_PROPERTY_QUERY query
= {};
57 query
.PropertyId
= StorageDeviceProperty
;
58 query
.QueryType
= PropertyStandardQuery
;
60 // Perform an initial query to get the number of bytes being returned.
62 STORAGE_DESCRIPTOR_HEADER header
= {};
63 BOOL status
= DeviceIoControl(drive_handle
.Get(),
64 IOCTL_STORAGE_QUERY_PROPERTY
,
66 sizeof(STORAGE_PROPERTY_QUERY
),
68 sizeof(STORAGE_DESCRIPTOR_HEADER
),
75 // Query for the actual serial number.
76 std::vector
<int8
> output_buf(header
.Size
);
77 status
= DeviceIoControl(drive_handle
.Get(),
78 IOCTL_STORAGE_QUERY_PROPERTY
,
80 sizeof(STORAGE_PROPERTY_QUERY
),
89 const STORAGE_DEVICE_DESCRIPTOR
* device_descriptor
=
90 reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR
*>(&output_buf
[0]);
92 // The serial number is stored in the |output_buf| as a null-terminated
93 // string starting at the specified offset.
94 const DWORD offset
= device_descriptor
->SerialNumberOffset
;
95 if (offset
>= output_buf
.size())
98 // Make sure that the null-terminator exists.
99 const std::vector
<int8
>::iterator serial_number_begin
=
100 output_buf
.begin() + offset
;
101 const std::vector
<int8
>::iterator null_location
=
102 std::find(serial_number_begin
, output_buf
.end(), '\0');
103 if (null_location
== output_buf
.end())
104 return std::string();
106 const char* serial_number
=
107 reinterpret_cast<const char*>(&output_buf
[offset
]);
109 return std::string(serial_number
);
113 MachineIdProvider
* MachineIdProvider::CreateInstance() {
114 return new MachineIdProvider();
117 } // namespace metrics