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