Roll src/third_party/WebKit c63b89c:29324ab (svn 202546:202547)
[chromium-blink-merge.git] / components / metrics / machine_id_provider_win.cc
blob8ec8a0c26b6e9592623a72fdd898c389878f38d7
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"
7 #include <windows.h>
8 #include <winioctl.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"
16 namespace metrics {
18 MachineIdProvider::MachineIdProvider() {
21 MachineIdProvider::~MachineIdProvider() {
24 // On windows, the machine id is based on the serial number of the drive Chrome
25 // is running from.
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)) {
35 NOTREACHED();
36 return std::string();
39 std::vector<base::FilePath::StringType> path_components;
40 executable_path.GetComponents(&path_components);
41 if (path_components.empty()) {
42 NOTREACHED();
43 return std::string();
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,
51 NULL,
52 OPEN_EXISTING,
54 NULL));
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.
61 DWORD bytes_returned;
62 STORAGE_DESCRIPTOR_HEADER header = {};
63 BOOL status = DeviceIoControl(drive_handle.Get(),
64 IOCTL_STORAGE_QUERY_PROPERTY,
65 &query,
66 sizeof(STORAGE_PROPERTY_QUERY),
67 &header,
68 sizeof(STORAGE_DESCRIPTOR_HEADER),
69 &bytes_returned,
70 NULL);
72 if (!status)
73 return std::string();
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,
79 &query,
80 sizeof(STORAGE_PROPERTY_QUERY),
81 &output_buf[0],
82 output_buf.size(),
83 &bytes_returned,
84 NULL);
86 if (!status)
87 return std::string();
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())
96 return std::string();
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);
112 // static
113 MachineIdProvider* MachineIdProvider::CreateInstance() {
114 return new MachineIdProvider();
117 } // namespace metrics