Skip to content

Commit

Permalink
Update MacOS implementation DeviceId::GetDeviceId.
Browse files Browse the repository at this point in the history
Append the MAC address (as string) to the existing DeviceId string
to improve id "uniqueness".

BUG=334348

Review URL: https://codereview.chromium.org/141383002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@246562 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
rpaquay@chromium.org committed Jan 23, 2014
1 parent d515042 commit 8aaf0f5
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 9 deletions.
142 changes: 138 additions & 4 deletions chrome/browser/extensions/api/music_manager_private/device_id_mac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,31 @@
#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DASession.h>
#include <DiskArbitration/DADisk.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetController.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IONetworkInterface.h>
#include <sys/mount.h>

#include "base/bind.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_ioobject.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_thread.h"

namespace {

using extensions::api::DeviceId;

const char kRootDirectory[] = "/";

typedef base::Callback<bool(const void* bytes, size_t size)>
IsValidMacAddressCallback;

// Return the BSD name (e.g. '/dev/disk1') of the root directory by enumerating
// through the mounted volumes .
// Return "" if an error occured.
Expand Down Expand Up @@ -86,7 +98,7 @@ std::string GetVolumeUUIDFromBSDName(const std::string& bsd_name) {
}

// Return Volume UUID property of disk mounted as "/".
void GetVolumeUUID(const extensions::api::DeviceId::IdCallback& callback) {
std::string GetVolumeUUID() {
base::ThreadRestrictions::AssertIOAllowed();

std::string result;
Expand All @@ -95,13 +107,133 @@ void GetVolumeUUID(const extensions::api::DeviceId::IdCallback& callback) {
VLOG(4) << "BSD name of root directory: '" << bsd_name << "'";
result = GetVolumeUUIDFromBSDName(bsd_name);
}
return result;
}

class MacAddressProcessor {
public:
MacAddressProcessor(const IsValidMacAddressCallback& is_valid_mac_address)
: is_valid_mac_address_(is_valid_mac_address) {
}

bool ProcessNetworkController(io_object_t network_controller) {
// Use the MAC address of the first network interface.
bool keep_going = true;
base::ScopedCFTypeRef<CFDataRef> mac_address_data(
static_cast<CFDataRef>(
IORegistryEntryCreateCFProperty(network_controller,
CFSTR(kIOMACAddress),
kCFAllocatorDefault,
0)));
if (!mac_address_data)
return keep_going;

const UInt8* mac_address = CFDataGetBytePtr(mac_address_data);
size_t mac_address_size = CFDataGetLength(mac_address_data);
if (!is_valid_mac_address_.Run(mac_address, mac_address_size))
return keep_going;

std::string mac_address_string =
StringToLowerASCII(base::HexEncode(mac_address, mac_address_size));

base::ScopedCFTypeRef<CFStringRef> provider_class(
static_cast<CFStringRef>(
IORegistryEntryCreateCFProperty(network_controller,
CFSTR(kIOProviderClassKey),
kCFAllocatorDefault,
0)));
if (provider_class) {
if (CFStringCompare(provider_class, CFSTR("IOPCIDevice"), 0) ==
kCFCompareEqualTo) {
// MAC address from built-in network card is always best choice.
found_mac_address_ = mac_address_string;
keep_going = false;
return keep_going;
}
}

// Fall back to using non built-in card MAC address, but keep looking.
found_mac_address_ = mac_address_string;
return keep_going;
}

std::string mac_address() const { return found_mac_address_; }

private:
const IsValidMacAddressCallback& is_valid_mac_address_;
std::string found_mac_address_;
};

std::string GetMacAddress(
const IsValidMacAddressCallback& is_valid_mac_address) {
base::ThreadRestrictions::AssertIOAllowed();

mach_port_t master_port;
kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &master_port);
if (kr != KERN_SUCCESS) {
LOG(ERROR) << "IOMasterPort failed: " << kr;
return "";
}

CFMutableDictionaryRef match_classes =
IOServiceMatching(kIOEthernetInterfaceClass);
if (!match_classes) {
LOG(ERROR) << "IOServiceMatching returned a NULL dictionary";
return "";
}

io_iterator_t iterator_ref;
kr = IOServiceGetMatchingServices(master_port,
match_classes,
&iterator_ref);
if (kr != KERN_SUCCESS) {
LOG(ERROR) << "IOServiceGetMatchingServices failed: " << kr;
return "";
}
base::mac::ScopedIOObject<io_iterator_t> iterator(iterator_ref);

MacAddressProcessor processor(is_valid_mac_address);
while (true) {
// Note: interface_service should not be released.
io_object_t interface_service = IOIteratorNext(iterator);
if (!interface_service)
break;

io_object_t controller_service_ref;
kr = IORegistryEntryGetParentEntry(interface_service,
kIOServicePlane,
&controller_service_ref);
if (kr != KERN_SUCCESS) {
LOG(ERROR) << "IORegistryEntryGetParentEntry failed: " << kr;
} else {
base::mac::ScopedIOObject<io_object_t> controller_service(
controller_service_ref);
bool keep_going = processor.ProcessNetworkController(controller_service);
if (!keep_going) {
break;
}
}
}
return processor.mac_address();
}

void GetRawDeviceIdImpl(const IsValidMacAddressCallback& is_valid_mac_address,
const DeviceId::IdCallback& callback) {
base::ThreadRestrictions::AssertIOAllowed();

std::string raw_device_id;
std::string mac_address = GetMacAddress(is_valid_mac_address);
std::string disk_id = GetVolumeUUID();
if (!mac_address.empty() && !disk_id.empty()) {
raw_device_id = mac_address + disk_id;
}
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(callback, result));
base::Bind(callback, raw_device_id));
}

}
} // namespace

namespace extensions {
namespace api {
Expand All @@ -113,7 +245,9 @@ void DeviceId::GetRawDeviceId(const IdCallback& callback) {
content::BrowserThread::PostTask(
content::BrowserThread::FILE,
FROM_HERE,
base::Bind(GetVolumeUUID, callback));
base::Bind(GetRawDeviceIdImpl,
base::Bind(DeviceId::IsValidMacAddress),
callback));
}

} // namespace api
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,17 @@ class MusicManagerPrivateTest : public extensions::PlatformAppBrowserTest {
};

IN_PROC_BROWSER_TEST_F(MusicManagerPrivateTest, DeviceIdValueReturned) {
ASSERT_TRUE(RunPlatformAppTest(
"platform_apps/music_manager_private/device_id_value_returned"))
#if defined(OS_MACOSX)
// Note: Some MacOS trybots seem to run under VMware, which assigns
// MAC addresses that are blacklisted. We still want the test
// to succeed in that case.
const char* custom_arg = "device_id_may_be_undefined";
#else
const char* custom_arg = NULL;
#endif
ASSERT_TRUE(RunPlatformAppTestWithArg(
"platform_apps/music_manager_private/device_id_value_returned",
custom_arg))
<< message_;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var deviceIdMaybeUndefined;

function runTests() {
chrome.test.runTests([
function test() {
chrome.musicManagerPrivate.getDeviceId(function(id) {
console.log("Device ID=" + id);
chrome.test.assertEq("string", typeof id);
chrome.test.assertTrue(id.length >= 8);
console.log('Device ID=' + id);
if (!id) {
chrome.test.assertEq(true, deviceIdMaybeUndefined)
} else {
chrome.test.assertEq('string', typeof id);
chrome.test.assertTrue(id.length >= 8);
}
chrome.test.succeed();
});
}
Expand All @@ -17,6 +23,9 @@ function runTests() {

window.onload = function() {
chrome.test.getConfig(function(config) {
console.log('customArg=' + config.customArg);
deviceIdMaybeUndefined =
(config.customArg === 'device_id_may_be_undefined');
runTests();
});
}

0 comments on commit 8aaf0f5

Please sign in to comment.