Chromium Code Reviews| Index: device/hid/hid_service_mac.cc |
| diff --git a/device/hid/hid_service_mac.cc b/device/hid/hid_service_mac.cc |
| index 12da7cc2d0c46afb4ad152b423c553ef7388e4f8..472860ba81c4279f961fbe6b76aaf8e8a0322a75 100644 |
| --- a/device/hid/hid_service_mac.cc |
| +++ b/device/hid/hid_service_mac.cc |
| @@ -4,8 +4,9 @@ |
| #include "device/hid/hid_service_mac.h" |
| -#include <map> |
| -#include <set> |
| +#include <CoreFoundation/CoreFoundation.h> |
| +#include <IOKit/hid/IOHIDManager.h> |
| + |
| #include <string> |
| #include "base/bind.h" |
| @@ -21,138 +22,104 @@ |
| #include "device/hid/hid_utils_mac.h" |
| #include "net/base/io_buffer.h" |
| -#include <CoreFoundation/CoreFoundation.h> |
| -#include <IOKit/hid/IOHIDManager.h> |
| - |
| namespace device { |
| class HidServiceMac; |
| -HidServiceMac::HidServiceMac() : enumeration_runloop_init_(true, false) { |
| - base::ThreadRestrictions::AssertIOAllowed(); |
| +namespace { |
| - hid_manager_ref_.reset(IOHIDManagerCreate(kCFAllocatorDefault, |
| - kIOHIDOptionsTypeNone)); |
| - if (!hid_manager_ref_ || |
| - CFGetTypeID(hid_manager_ref_) != IOHIDManagerGetTypeID()) { |
| - LOG(ERROR) << "Failed to initialize HidManager"; |
| - return; |
| - } |
| - CFRetain(hid_manager_ref_); |
| +typedef std::vector<IOHIDDeviceRef> HidDeviceList; |
|
Mark Mentovai
2014/02/13 22:37:51
#include <vector> to use this.
Or you could use a
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done. I left it as a vector since the usage is iso
|
| - // Register for plug/unplug notifications. |
| - IOHIDManagerSetDeviceMatching(hid_manager_ref_.get(), NULL); |
| - IOHIDManagerRegisterDeviceMatchingCallback( |
| - hid_manager_ref_.get(), |
| - &HidServiceMac::AddDeviceCallback, |
| - this); |
| - IOHIDManagerRegisterDeviceRemovalCallback( |
| - hid_manager_ref_.get(), |
| - &HidServiceMac::RemoveDeviceCallback, |
| - this); |
| +HidServiceMac* HidServiceFromContext(void* context) { |
| + return reinterpret_cast<HidServiceMac*>(context); |
| +} |
| - // Blocking operation to enumerate all the pre-existing devices. |
| - Enumerate(); |
| +// Callback for CFSetApplyFunction as used by EnumerateHidDevices. |
| +void HidEnumerationBackInserter(const void* value, void* context) { |
| + HidDeviceList* devices = static_cast<HidDeviceList*>(context); |
| + IOHIDDeviceRef device = static_cast<IOHIDDeviceRef>(value); |
| + devices->push_back(device); |
| +} |
| - // Save the owner message loop. |
| - message_loop_ = base::MessageLoopProxy::current(); |
| +void EnumerateHidDevices(IOHIDManagerRef hid_manager, |
| + HidDeviceList* device_list) { |
| + base::ScopedCFTypeRef<CFSetRef> devices(IOHIDManagerCopyDevices(hid_manager)); |
| + CFSetApplyFunction(devices, HidEnumerationBackInserter, device_list); |
|
Mark Mentovai
2014/02/13 22:37:51
Great! This is so much better than allocating spac
|
| +} |
| - // Start a thread to monitor HID device changes. |
| - // The reason to create a new thread is that by default the only thread in the |
| - // browser process having a CFRunLoop is the UI thread. We do not want to |
| - // run potentially blocking routines on it. |
| - enumeration_runloop_thread_.reset( |
| - new base::Thread("HidService Device Enumeration Thread")); |
| +} // namespace |
| - base::Thread::Options options; |
| - options.message_loop_type = base::MessageLoop::TYPE_UI; |
| - enumeration_runloop_thread_->StartWithOptions(options); |
| - enumeration_runloop_thread_->message_loop()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&HidServiceMac::ScheduleRunLoop, base::Unretained(this))); |
| +HidServiceMac::HidServiceMac() { |
| + hid_manager_.reset(IOHIDManagerCreate(NULL, kIOHIDManagerOptionNone)); |
| + if (!hid_manager_ || CFGetTypeID(hid_manager_) != IOHIDManagerGetTypeID()) { |
|
Mark Mentovai
2014/02/13 22:37:51
Since the type-check portion of this is pretty che
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done.
|
| + LOG(ERROR) << "Failed to initialize HidManager"; |
| + return; |
| + } |
| - enumeration_runloop_init_.Wait(); |
| - initialized_ = true; |
| -} |
| + // Enumerate all the currently known devices. |
| + Enumerate(); |
| -HidServiceMac::~HidServiceMac() { |
| - enumeration_runloop_thread_->message_loop()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&HidServiceMac::UnscheduleRunLoop, base::Unretained(this))); |
| + // Register for plug/unplug notifications. |
| + StartWatchingDevices(); |
| - enumeration_runloop_thread_->Stop(); |
| + initialized_ = true; |
|
Mark Mentovai
2014/02/13 22:37:51
This is unused.
Well, OK, not exactly. It’s unuse
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Yes I absolutely hate this. Removed altogether. Th
|
| } |
| -void HidServiceMac::ScheduleRunLoop() { |
| - enumeration_runloop_ = CFRunLoopGetCurrent(); |
| +HidServiceMac::~HidServiceMac() { StopWatchingDevices(); } |
|
Mark Mentovai
2014/02/13 22:37:51
This may be dangerous if you hit the early return
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done.
|
| +void HidServiceMac::StartWatchingDevices() { |
| + IOHIDManagerSetDeviceMatching(hid_manager_, NULL); |
| + IOHIDManagerRegisterDeviceMatchingCallback( |
| + hid_manager_, &AddDeviceCallback, this); |
| + IOHIDManagerRegisterDeviceRemovalCallback( |
| + hid_manager_, &RemoveDeviceCallback, this); |
| IOHIDManagerScheduleWithRunLoop( |
| - hid_manager_ref_, |
| - enumeration_runloop_, |
| - kCFRunLoopDefaultMode); |
| - |
| - IOHIDManagerOpen(hid_manager_ref_, kIOHIDOptionsTypeNone); |
| - |
| - enumeration_runloop_init_.Signal(); |
| + hid_manager_, CFRunLoopGetMain(), kCFRunLoopDefaultMode); |
|
Mark Mentovai
2014/02/13 22:37:51
Now that this is expected to run on the main threa
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Thinking about it some more, I'd rather avoid the
|
| + IOHIDManagerOpen(hid_manager_, kIOHIDOptionsTypeNone); |
| } |
| -void HidServiceMac::UnscheduleRunLoop() { |
| +void HidServiceMac::StopWatchingDevices() { |
| IOHIDManagerUnscheduleFromRunLoop( |
| - hid_manager_ref_, |
| - enumeration_runloop_, |
| - kCFRunLoopDefaultMode); |
| - |
| - IOHIDManagerClose(hid_manager_ref_, kIOHIDOptionsTypeNone); |
| - |
| -} |
| - |
| -HidServiceMac* HidServiceMac::InstanceFromContext(void* context) { |
| - return reinterpret_cast<HidServiceMac*>(context); |
| + hid_manager_, CFRunLoopGetMain(), kCFRunLoopDefaultMode); |
| + IOHIDManagerClose(hid_manager_, kIOHIDOptionsTypeNone); |
| } |
| void HidServiceMac::AddDeviceCallback(void* context, |
| IOReturn result, |
| void* sender, |
| - IOHIDDeviceRef ref) { |
| - HidServiceMac* service = InstanceFromContext(context); |
| - |
| - // Takes ownership of ref. Will be released inside PlatformDeviceAdd. |
| - CFRetain(ref); |
| - service->message_loop_->PostTask( |
| - FROM_HERE, |
| - base::Bind(&HidServiceMac::PlatformAddDevice, |
| - base::Unretained(service), |
| - base::Unretained(ref))); |
| + IOHIDDeviceRef hid_device) { |
| + HidServiceMac* service = HidServiceFromContext(context); |
| + BrowserThread::PostTask(BrowserThread::FILE, |
|
Mark Mentovai
2014/02/13 22:37:51
To use this, you need to #include "content/public/
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
I decided to retain a handle to the current Messag
|
| + FROM_HERE, |
| + base::Bind(&PlatformAddDevice, |
| + base::Unretained(service), |
| + base::Unretained(hid_device))); |
| } |
| void HidServiceMac::RemoveDeviceCallback(void* context, |
| IOReturn result, |
| void* sender, |
| - IOHIDDeviceRef ref) { |
| - HidServiceMac* service = InstanceFromContext(context); |
| - |
| - // Takes ownership of ref. Will be released inside PlatformDeviceRemove. |
| - CFRetain(ref); |
| - service->message_loop_->PostTask( |
| - FROM_HERE, |
| - base::Bind(&HidServiceMac::PlatformRemoveDevice, |
| - base::Unretained(service), |
| - base::Unretained(ref))); |
| + IOHIDDeviceRef hid_device) { |
| + HidServiceMac* service = HidServiceFromContext(context); |
| + BrowserThread::PostTask(BrowserThread::FILE, |
| + FROM_HERE, |
| + base::Bind(&PlatformRemoveDevice, |
| + base::Unretained(service), |
| + base::Unretained(hid_device))); |
| } |
| -IOHIDDeviceRef HidServiceMac::FindDevice(std::string id) { |
| - base::ScopedCFTypeRef<CFSetRef> devices( |
| - IOHIDManagerCopyDevices(hid_manager_ref_)); |
| - CFIndex count = CFSetGetCount(devices); |
| - scoped_ptr<IOHIDDeviceRef[]> device_refs(new IOHIDDeviceRef[count]); |
| - CFSetGetValues(devices, (const void **)(device_refs.get())); |
| - |
| - for (CFIndex i = 0; i < count; i++) { |
| +IOHIDDeviceRef HidServiceMac::FindDevice(const std::string& device_id) { |
| + HidDeviceList devices; |
| + EnumerateHidDevices(hid_manager_, &devices); |
| + for (HidDeviceList::const_iterator iter = devices.begin(); |
| + iter != devices.end(); |
| + ++iter) { |
| int32_t int_property = 0; |
|
Mark Mentovai
2014/02/13 22:37:51
No need to initialize.
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done.
|
| - if (GetHidIntProperty(device_refs[i], CFSTR(kIOHIDLocationIDKey), |
| - &int_property)) { |
| + if (TryGetHidIntProperty(*iter, |
|
Mark Mentovai
2014/02/13 22:37:51
Since you’ve used *iter a couple of times in this
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done.
|
| + CFSTR(kIOHIDLocationIDKey), |
| + &int_property)) { |
| if (id == base::HexEncode(&int_property, sizeof(int_property))) { |
|
Mark Mentovai
2014/02/13 22:37:51
Stopping here. You obviously didn’t even compile t
|
| - return device_refs[i]; |
| + return *iter; |
| } |
| } |
| } |
| @@ -161,90 +128,66 @@ IOHIDDeviceRef HidServiceMac::FindDevice(std::string id) { |
| } |
| void HidServiceMac::Enumerate() { |
| - base::ScopedCFTypeRef<CFSetRef> devices( |
| - IOHIDManagerCopyDevices(hid_manager_ref_)); |
| - CFIndex count = CFSetGetCount(devices); |
| - scoped_ptr<IOHIDDeviceRef[]> device_refs(new IOHIDDeviceRef[count]); |
| - CFSetGetValues(devices, (const void **)(device_refs.get())); |
| - |
| - for (CFIndex i = 0; i < count; i++) { |
| - // Takes ownership. Will be released inside PlatformDeviceAdd. |
| - CFRetain(device_refs[i]); |
| - PlatformAddDevice(device_refs[i]); |
| + HidDeviceList devices; |
| + EnumerateHidDevices(hid_manager_, &devices); |
| + for (HidDeviceList::const_iterator iter = devices.begin(); |
| + iter != devices.end(); |
| + ++iter) { |
| + // Takes ownership. Will be released inside PlatformAddDevice. |
| + CFRetain(*iter); |
| + PlatformAddDevice(*iter); |
| } |
| } |
| -void HidServiceMac::PlatformAddDevice(IOHIDDeviceRef raw_ref) { |
| - HidDeviceInfo device; |
| - int32_t int_property = 0; |
| - std::string str_property; |
| - |
| - // Auto-release. |
| - base::ScopedCFTypeRef<IOHIDDeviceRef> ref(raw_ref); |
| +void HidServiceMac::PlatformAddDevice(IOHIDDeviceRef hid_device) { |
| + HidDeviceInfo device_info; |
|
Mark Mentovai
2014/02/13 22:37:51
Don’t declare stuff ’til you use it.
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done.
|
| + base::ScopedCFTypeRef<IOHIDDeviceRef> device(hid_device); |
|
Mark Mentovai
2014/02/13 22:37:51
The same discussion here applies to PlatformRemove
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
This appears to be correct, the manager does not r
|
| // Unique identifier for HID device. |
| - if (GetHidIntProperty(ref, CFSTR(kIOHIDLocationIDKey), &int_property)) { |
| - device.device_id = base::HexEncode(&int_property, sizeof(int_property)); |
| - } else { |
| - // Not an available device. |
| + int32_t location_id = 0; |
|
Mark Mentovai
2014/02/13 22:37:51
No need to initialize.
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done.
|
| + if (!TryGetHidIntProperty(device, CFSTR(kIOHIDLocationIDKey), &location_id)) |
|
Mark Mentovai
2014/02/13 22:37:51
Just a reminder that “is the location ID the right
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
I've looked into this and I'm pretty confident thi
|
| return; |
| - } |
| - if (GetHidIntProperty(ref, CFSTR(kIOHIDVendorIDKey), &int_property)) { |
| - device.vendor_id = int_property; |
| - } |
| - if (GetHidIntProperty(ref, CFSTR(kIOHIDProductIDKey), &int_property)) { |
| - device.product_id = int_property; |
| - } |
| - if (GetHidIntProperty(ref, CFSTR(kIOHIDPrimaryUsageKey), &int_property)) { |
| - device.usage = int_property; |
| - } |
| - if (GetHidIntProperty(ref, CFSTR(kIOHIDPrimaryUsagePageKey), &int_property)) { |
| - device.usage_page = int_property; |
| - } |
| - if (GetHidIntProperty(ref, CFSTR(kIOHIDMaxInputReportSizeKey), |
| - &int_property)) { |
| - device.input_report_size = int_property; |
| - } |
| - if (GetHidIntProperty(ref, CFSTR(kIOHIDMaxOutputReportSizeKey), |
| - &int_property)) { |
| - device.output_report_size = int_property; |
| - } |
| - if (GetHidIntProperty(ref, CFSTR(kIOHIDMaxFeatureReportSizeKey), |
| - &int_property)) { |
| - device.feature_report_size = int_property; |
| - } |
| - if (GetHidStringProperty(ref, CFSTR(kIOHIDProductKey), &str_property)) { |
| - device.product_name = str_property; |
| - } |
| - if (GetHidStringProperty(ref, CFSTR(kIOHIDSerialNumberKey), &str_property)) { |
| - device.serial_number = str_property; |
| - } |
| - HidService::AddDevice(device); |
| + device_info.device_id = base::HexEncode(&location_id, sizeof(location_id)); |
| + device_info.vendor_id = GetHidIntProperty(device, CFSTR(kIOHIDVendorIDKey)); |
| + device_info.product_id = GetHidIntProperty(device, CFSTR(kIOHIDProductIDKey)); |
| + device_info.usage = GetHidIntProperty(device, CFSTR(kIOHIDPrimaryUsageKey)); |
| + device_info.usage_page = |
| + GetHidIntProperty(device, CFSTR(kIOHIDPrimaryUsagePageKey)); |
| + device_info.input_report_size = |
| + GetHidIntProperty(device, CFSTR(kIOHIDMaxInputReportSizeKey)); |
| + device_info.output_report_size = |
| + GetHidIntProperty(device, CFSTR(kIOHIDMaxOutputReportSizeKey)); |
| + device_info.feature_report_size = |
| + GetHidIntProperty(device, CFSTR(kIOHIDMaxFeatureReportSizeKey)); |
| + device_info.product_name = |
| + GetHidStringProperty(device, CFSTR(kIOHIDProductKey)); |
| + device_info.serial_number = |
| + GetHidStringProperty(device, CFSTR(kIOHIDSerialNumberKey)); |
| + |
| + HidService::AddDevice(device_info); |
| } |
| -void HidServiceMac::PlatformRemoveDevice(IOHIDDeviceRef raw_ref) { |
| +void HidServiceMac::PlatformRemoveDevice(IOHIDDeviceRef hid_device) { |
| std::string device_id; |
|
Mark Mentovai
2014/02/13 22:37:51
Don’t declare until use. You save a line of code t
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done.
|
| int32_t int_property = 0; |
|
Mark Mentovai
2014/02/13 22:37:51
No need to initialize.
Ken Rockot(use gerrit already)
2014/02/18 19:43:09
Done.
|
| - // Auto-release. |
| - base::ScopedCFTypeRef<IOHIDDeviceRef> ref(raw_ref); |
| - if (!GetHidIntProperty(ref, CFSTR(kIOHIDLocationIDKey), &int_property)) { |
| + base::ScopedCFTypeRef<IOHIDDeviceRef> device(hid_device); |
| + if (!TryGetHidIntProperty(device, CFSTR(kIOHIDLocationIDKey), &int_property)) |
| return; |
| - } |
| device_id = base::HexEncode(&int_property, sizeof(int_property)); |
| HidService::RemoveDevice(device_id); |
| } |
| -scoped_refptr<HidConnection> |
| -HidServiceMac::Connect(std::string device_id) { |
| +scoped_refptr<HidConnection> HidServiceMac::Connect( |
| + const std::string& device_id) { |
| if (!ContainsKey(devices_, device_id)) |
| return NULL; |
| - IOHIDDeviceRef ref = FindDevice(device_id); |
| - if (ref == NULL) |
| + IOHIDDeviceRef hid_device = FindDevice(device_id); |
| + if (hid_device == NULL) |
| return NULL; |
| return scoped_refptr<HidConnection>( |
| - new HidConnectionMac(this, devices_[device_id], ref)); |
| + new HidConnectionMac(this, devices_[device_id], hid_device)); |
| } |
| } // namespace device |