xref: /aosp_15_r20/external/cronet/components/metrics/machine_id_provider_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 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.
4 
5 #include "components/metrics/machine_id_provider.h"
6 
7 #include <windows.h>
8 
9 #include <stdint.h>
10 #include <winioctl.h>
11 
12 #include "base/base_paths.h"
13 #include "base/files/file_path.h"
14 #include "base/notreached.h"
15 #include "base/path_service.h"
16 #include "base/threading/scoped_blocking_call.h"
17 #include "base/win/scoped_handle.h"
18 
19 namespace metrics {
20 
21 // static
HasId()22 bool MachineIdProvider::HasId() {
23   return true;
24 }
25 
26 // On windows, the machine id is based on the serial number of the drive Chrome
27 // is running from.
28 // static
GetMachineId()29 std::string MachineIdProvider::GetMachineId() {
30   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
31                                                 base::BlockingType::MAY_BLOCK);
32 
33   // Use the program's path to get the drive used for the machine id. This means
34   // that whenever the underlying drive changes, it's considered a new machine.
35   // This is fine as we do not support migrating Chrome installs to new drives.
36   base::FilePath executable_path;
37 
38   if (!base::PathService::Get(base::FILE_EXE, &executable_path)) {
39     NOTREACHED();
40     return std::string();
41   }
42 
43   std::vector<base::FilePath::StringType> path_components =
44       executable_path.GetComponents();
45   if (path_components.empty()) {
46     NOTREACHED();
47     return std::string();
48   }
49   base::FilePath::StringType drive_name = L"\\\\.\\" + path_components[0];
50 
51   base::win::ScopedHandle drive_handle(
52       CreateFile(drive_name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
53                  nullptr, OPEN_EXISTING, 0, nullptr));
54 
55   STORAGE_PROPERTY_QUERY query = {};
56   query.PropertyId = StorageDeviceProperty;
57   query.QueryType = PropertyStandardQuery;
58 
59   // Perform an initial query to get the number of bytes being returned.
60   DWORD bytes_returned;
61   STORAGE_DESCRIPTOR_HEADER header = {};
62   BOOL status = DeviceIoControl(
63       drive_handle.Get(), IOCTL_STORAGE_QUERY_PROPERTY, &query,
64       sizeof(STORAGE_PROPERTY_QUERY), &header,
65       sizeof(STORAGE_DESCRIPTOR_HEADER), &bytes_returned, nullptr);
66 
67   if (!status)
68     return std::string();
69 
70   // Query for the actual serial number.
71   std::vector<int8_t> output_buf(header.Size);
72   status =
73       DeviceIoControl(drive_handle.Get(), IOCTL_STORAGE_QUERY_PROPERTY, &query,
74                       sizeof(STORAGE_PROPERTY_QUERY), &output_buf[0],
75                       output_buf.size(), &bytes_returned, nullptr);
76 
77   if (!status)
78     return std::string();
79 
80   const STORAGE_DEVICE_DESCRIPTOR* device_descriptor =
81       reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(&output_buf[0]);
82 
83   // The serial number is stored in the |output_buf| as a null-terminated
84   // string starting at the specified offset.
85   const DWORD offset = device_descriptor->SerialNumberOffset;
86   if (offset >= output_buf.size())
87     return std::string();
88 
89   // Make sure that the null-terminator exists.
90   const std::vector<int8_t>::iterator serial_number_begin =
91       output_buf.begin() + offset;
92   const std::vector<int8_t>::iterator null_location =
93       std::find(serial_number_begin, output_buf.end(), '\0');
94   if (null_location == output_buf.end())
95     return std::string();
96 
97   const char* serial_number =
98       reinterpret_cast<const char*>(&output_buf[offset]);
99 
100   return std::string(serial_number);
101 }
102 }  //  namespace metrics
103