OLD | NEW |
---|---|
(Empty) | |
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 "chrome/browser/mac/bluetooth_utility.h" | |
6 | |
7 #import <Foundation/Foundation.h> | |
8 #include <IOKit/IOKitLib.h> | |
9 | |
10 #include "base/mac/foundation_util.h" | |
11 #include "base/mac/mac_util.h" | |
12 #include "base/mac/scoped_ioobject.h" | |
13 #include "base/mac/sdk_forward_declarations.h" | |
14 | |
15 namespace { | |
16 | |
17 const char* kBluetoothServiceKey = "IOBluetoothHCIController"; | |
Mark Mentovai
2014/07/11 18:05:04
These constants don’t really need to exist outside
erikchen
2014/07/11 18:56:56
Done.
| |
18 NSString* kLMPVersionKey = @"LMPVersion"; | |
19 NSString* kSupportedFeaturesKey = @"HCISupportedFeatures"; | |
20 const int kSupportedFeaturesLEIndex = 3; | |
21 const int kSupportedFeaturesSize = 8; | |
22 | |
23 // The first LMP version that supports Bluetooth LE. | |
24 const int kFirstLELMPVersion = 6; | |
25 | |
26 } // namespace | |
27 | |
28 namespace bluetooth_utility { | |
29 | |
30 BluetoothAvailability GetBluetoothAvailability() { | |
31 base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict( | |
32 IOServiceMatching(kBluetoothServiceKey)); | |
33 if (!matching_dict) | |
34 return BLUETOOTH_AVAILABILITY_ERROR; | |
35 | |
36 // IOServiceGetMatchingServices takes ownership of matching_dict. | |
37 io_iterator_t iter; | |
38 int kr = IOServiceGetMatchingServices( | |
39 kIOMasterPortDefault, matching_dict.release(), &iter); | |
40 if (kr != KERN_SUCCESS) | |
41 return BLUETOOTH_NOT_AVAILABLE; | |
42 base::mac::ScopedIOObject<io_iterator_t> scoped_iter(iter); | |
43 | |
44 int bluetooth_available = false; | |
45 base::mac::ScopedIOObject<io_service_t> device; | |
46 while (device.reset(IOIteratorNext(scoped_iter.get())), device) { | |
47 bluetooth_available = true; | |
48 | |
49 CFMutableDictionaryRef dict; | |
50 kr = IORegistryEntryCreateCFProperties( | |
51 device, &dict, kCFAllocatorDefault, kNilOptions); | |
52 if (kr != KERN_SUCCESS) | |
53 continue; | |
54 base::ScopedCFTypeRef<CFMutableDictionaryRef> scoped_dict(dict); | |
55 | |
56 NSDictionary* objc_dict = base::mac::CFToNSCast(scoped_dict.get()); | |
57 NSNumber* lmp_version = | |
58 base::mac::ObjCCast<NSNumber>([objc_dict objectForKey:kLMPVersionKey]); | |
59 if (!lmp_version) | |
60 continue; | |
61 | |
62 if ([lmp_version intValue] < kFirstLELMPVersion) | |
63 continue; | |
64 | |
65 // Check the supported features registry entry for Bluetooth LE | |
66 // availability. The relevant bit has a different meaning on OSX 10.6, and | |
67 // could change again in the future. | |
68 if (base::mac::IsOSLionOrEarlier()) { | |
69 // All we know is that the LMP version supports LE. Assume that the | |
70 // bluetooth radio is LE compatible. | |
71 return BLUETOOTH_AVAILABLE_WITH_LE; | |
Mark Mentovai
2014/07/11 18:05:04
For histogramming purposes, I think you want to br
erikchen
2014/07/11 18:56:56
Done.
| |
72 } | |
73 | |
74 NSData* data = base::mac::ObjCCast<NSData>( | |
75 [objc_dict objectForKey:kSupportedFeaturesKey]); | |
76 if (!data || [data length] != kSupportedFeaturesSize) | |
Mark Mentovai
2014/07/11 18:05:04
Don’t check the size, there’s evidence in the head
erikchen
2014/07/11 18:56:56
Right, fixed.
| |
77 continue; | |
78 | |
79 // The result is a big endian unsigned long long. | |
80 // We want the fifth byte, which is at index 3. | |
Mark Mentovai
2014/07/11 18:05:04
Something doesn’t add up here, but it’s probably b
erikchen
2014/07/11 18:56:56
The index is interpreted in reverse order (or so w
| |
81 const unsigned char* bytes = | |
82 static_cast<const unsigned char*>([data bytes]); | |
83 const unsigned char byte = bytes[kSupportedFeaturesLEIndex]; | |
84 bool le_supported = byte & kBluetoothFeatureLESupportedController; | |
85 if (le_supported) | |
86 return BLUETOOTH_AVAILABLE_WITH_LE; | |
87 } | |
88 | |
89 return bluetooth_available ? BLUETOOTH_AVAILABLE_WITHOUT_LE | |
90 : BLUETOOTH_AVAILABILITY_ERROR; | |
91 } | |
92 | |
93 } // namespace bluetooth_utility | |
OLD | NEW |