Home | History | Annotate | Download | only in metrics
      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.
      4 
      5 #include "components/metrics/machine_id_provider.h"
      6 
      7 #include <windows.h>
      8 #include <winioctl.h>
      9 
     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"
     15 
     16 namespace metrics {
     17 
     18 MachineIdProvider::MachineIdProvider() {
     19 }
     20 
     21 MachineIdProvider::~MachineIdProvider() {
     22 }
     23 
     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();
     28 
     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;
     33 
     34   if (!PathService::Get(base::FILE_EXE, &executable_path)) {
     35     NOTREACHED();
     36     return std::string();
     37   }
     38 
     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();
     44   }
     45   base::FilePath::StringType drive_name = L"\\\\.\\" + path_components[0];
     46 
     47   base::win::ScopedHandle drive_handle(
     48       CreateFile(drive_name.c_str(),
     49                  0,
     50                  FILE_SHARE_READ | FILE_SHARE_WRITE,
     51                  NULL,
     52                  OPEN_EXISTING,
     53                  0,
     54                  NULL));
     55 
     56   STORAGE_PROPERTY_QUERY query = {};
     57   query.PropertyId = StorageDeviceProperty;
     58   query.QueryType = PropertyStandardQuery;
     59 
     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,
     64                                 IOCTL_STORAGE_QUERY_PROPERTY,
     65                                 &query,
     66                                 sizeof(STORAGE_PROPERTY_QUERY),
     67                                 &header,
     68                                 sizeof(STORAGE_DESCRIPTOR_HEADER),
     69                                 &bytes_returned,
     70                                 NULL);
     71 
     72   if (!status)
     73     return std::string();
     74 
     75   // Query for the actual serial number.
     76   std::vector<int8> output_buf(header.Size);
     77   status = DeviceIoControl(drive_handle,
     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);
     85 
     86   if (!status)
     87     return std::string();
     88 
     89   const STORAGE_DEVICE_DESCRIPTOR* device_descriptor =
     90       reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(&output_buf[0]);
     91 
     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();
     97 
     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();
    105 
    106   const char* serial_number =
    107       reinterpret_cast<const char*>(&output_buf[offset]);
    108 
    109   return std::string(serial_number);
    110 }
    111 
    112 // static
    113 MachineIdProvider* MachineIdProvider::CreateInstance() {
    114   return new MachineIdProvider();
    115 }
    116 
    117 }  //  namespace metrics
    118