1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <sys/socket.h>  // Must be included before ifaddrs.h.
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <ifaddrs.h>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <net/if.h>
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <sys/ioctl.h>
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <map>
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/bind.h"
151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/files/file_enumerator.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_path.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_util.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using extensions::api::DeviceId;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef base::Callback<bool(const void* bytes, size_t size)>
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IsValidMacAddressCallback;
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const char kDiskByUuidDirectoryName[] = "/dev/disk/by-uuid";
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char* kDeviceNames[] = {
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  "sda1", "hda1", "dm-0", "xvda1", "sda2", "hda2", "dm-1", "xvda2",
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Fedora 15 uses biosdevname feature where Embedded ethernet uses the
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// "em" prefix and PCI cards use the p[0-9]c[0-9] format based on PCI
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// slot and card information.
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char* kNetDeviceNamePrefixes[] = {
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)   "eth", "em", "en", "wl", "ww", "p0", "p1", "p2", "p3", "p4", "p5", "p6",
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)   "p7", "p8", "p9", "wlan"
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Map from device name to disk uuid
431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)typedef std::map<base::FilePath, base::FilePath> DiskEntries;
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string GetDiskUuid() {
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DiskEntries disk_uuids;
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::FileEnumerator files(base::FilePath(kDiskByUuidDirectoryName),
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                             false,  // Recursive.
511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                             base::FileEnumerator::FILES);
521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  do {
531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::FilePath file_path = files.Next();
541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (file_path.empty())
551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::FilePath target_path;
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!base::ReadSymbolicLink(file_path, &target_path))
591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      continue;
601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::FilePath device_name = target_path.BaseName();
621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::FilePath disk_uuid = file_path.BaseName();
631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    disk_uuids[device_name] = disk_uuid;
641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } while (true);
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Look for first device name matching an entry of |kDeviceNames|.
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string result;
681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kDeviceNames); i++) {
691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    DiskEntries::iterator it =
701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        disk_uuids.find(base::FilePath(kDeviceNames[i]));
711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (it != disk_uuids.end()) {
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      DVLOG(1) << "Returning uuid: \"" << it->second.value()
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               << "\" for device \"" << it->first.value() << "\"";
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      result = it->second.value();
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      break;
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Log failure (at most once) for diagnostic purposes.
801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  static bool error_logged = false;
811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (result.empty() && !error_logged) {
821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    error_logged = true;
831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    LOG(ERROR) << "Could not find appropriate disk uuid.";
841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for (DiskEntries::iterator it = disk_uuids.begin();
851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        it != disk_uuids.end(); ++it) {
861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      LOG(ERROR) << "  DeviceID=" << it->first.value() << ", uuid="
871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                 << it->second.value();
881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class MacAddressProcessor {
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit MacAddressProcessor(
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const IsValidMacAddressCallback& is_valid_mac_address)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : is_valid_mac_address_(is_valid_mac_address) {
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool ProcessInterface(struct ifaddrs *ifaddr,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const char* prefixes[],
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        size_t prefixes_count) {
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const int MAC_LENGTH = 6;
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    struct ifreq ifinfo;
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    memset(&ifinfo, 0, sizeof(ifinfo));
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    strncpy(ifinfo.ifr_name, ifaddr->ifa_name, sizeof(ifinfo.ifr_name) - 1);
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int sd = socket(AF_INET, SOCK_DGRAM, 0);
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int result = ioctl(sd, SIOCGIFHWADDR, &ifinfo);
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    close(sd);
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (result != 0)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const char* mac_address =
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        static_cast<const char*>(ifinfo.ifr_hwaddr.sa_data);
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!is_valid_mac_address_.Run(mac_address, MAC_LENGTH))
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!IsValidPrefix(ifinfo.ifr_name, prefixes, prefixes_count))
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Got one!
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    found_mac_address_ =
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        base::StringToLowerASCII(base::HexEncode(mac_address, MAC_LENGTH));
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string mac_address() const { return found_mac_address_; }
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool IsValidPrefix(const char* name,
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     const char* prefixes[],
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     size_t prefixes_count) {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (size_t i = 0; i < prefixes_count; i++) {
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (strncmp(prefixes[i], name, strlen(prefixes[i])) == 0)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return true;
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const IsValidMacAddressCallback& is_valid_mac_address_;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string found_mac_address_;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string GetMacAddress(
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const IsValidMacAddressCallback& is_valid_mac_address) {
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  struct ifaddrs* ifaddrs;
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int rv = getifaddrs(&ifaddrs);
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (rv < 0) {
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PLOG(ERROR) << "getifaddrs failed " << rv;
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return "";
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MacAddressProcessor processor(is_valid_mac_address);
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (struct ifaddrs* ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool keep_going = processor.ProcessInterface(
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ifa, kNetDeviceNamePrefixes, arraysize(kNetDeviceNamePrefixes));
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!keep_going)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  freeifaddrs(ifaddrs);
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return processor.mac_address();
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GetRawDeviceIdImpl(const IsValidMacAddressCallback& is_valid_mac_address,
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const DeviceId::IdCallback& callback) {
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string disk_id = GetDiskUuid();
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string mac_address = GetMacAddress(is_valid_mac_address);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string raw_device_id;
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!mac_address.empty() && !disk_id.empty()) {
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    raw_device_id = mac_address + disk_id;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content::BrowserThread::PostTask(
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      content::BrowserThread::UI,
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      FROM_HERE,
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(callback, raw_device_id));
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}  // namespace
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace extensions {
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace api {
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DeviceId::GetRawDeviceId(const IdCallback& callback) {
195effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content::BrowserThread::PostTask(
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      content::BrowserThread::FILE,
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      FROM_HERE,
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(GetRawDeviceIdImpl,
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::Bind(DeviceId::IsValidMacAddress),
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          callback));
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace api
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace extensions
207