summaryrefslogtreecommitdiff
path: root/chromium/device/hid
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-12 14:07:37 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 10:29:26 +0000
commitec02ee4181c49b61fce1c8fb99292dbb8139cc90 (patch)
tree25cde714b2b71eb639d1cd53f5a22e9ba76e14ef /chromium/device/hid
parentbb09965444b5bb20b096a291445170876225268d (diff)
downloadqtwebengine-chromium-ec02ee4181c49b61fce1c8fb99292dbb8139cc90.tar.gz
BASELINE: Update Chromium to 59.0.3071.134
Change-Id: Id02ef6fb2204c5fd21668a1c3e6911c83b17585a Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/device/hid')
-rw-r--r--chromium/device/hid/hid_connection.cc14
-rw-r--r--chromium/device/hid/hid_connection.h11
-rw-r--r--chromium/device/hid/hid_connection_linux.cc264
-rw-r--r--chromium/device/hid/hid_connection_linux.h51
-rw-r--r--chromium/device/hid/hid_connection_mac.cc19
-rw-r--r--chromium/device/hid/hid_connection_mac.h4
-rw-r--r--chromium/device/hid/hid_connection_win.cc37
-rw-r--r--chromium/device/hid/hid_service_linux.cc67
-rw-r--r--chromium/device/hid/hid_service_linux.h7
-rw-r--r--chromium/device/hid/hid_service_mac.cc181
-rw-r--r--chromium/device/hid/hid_service_mac.h16
-rw-r--r--chromium/device/hid/hid_service_win.cc39
-rw-r--r--chromium/device/hid/hid_service_win.h18
13 files changed, 320 insertions, 408 deletions
diff --git a/chromium/device/hid/hid_connection.cc b/chromium/device/hid/hid_connection.cc
index 5a904fe7cfa..9d5ee20f20b 100644
--- a/chromium/device/hid/hid_connection.cc
+++ b/chromium/device/hid/hid_connection.cc
@@ -170,20 +170,6 @@ void HidConnection::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
PlatformSendFeatureReport(buffer, size, callback);
}
-bool HidConnection::CompleteRead(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const ReadCallback& callback) {
- DCHECK_GE(size, 1u);
- uint8_t report_id = buffer->data()[0];
- if (IsReportIdProtected(report_id)) {
- HID_LOG(EVENT) << "Filtered a protected input report.";
- return false;
- }
-
- callback.Run(true, buffer, size);
- return true;
-}
-
bool HidConnection::IsReportIdProtected(uint8_t report_id) {
HidCollectionInfo collection_info;
if (FindCollectionByReportId(device_info_->collections(), report_id,
diff --git a/chromium/device/hid/hid_connection.h b/chromium/device/hid/hid_connection.h
index 1bf8d2e3c2d..dbff1caf093 100644
--- a/chromium/device/hid/hid_connection.h
+++ b/chromium/device/hid/hid_connection.h
@@ -75,18 +75,9 @@ class HidConnection : public base::RefCountedThreadSafe<HidConnection> {
size_t size,
const WriteCallback& callback) = 0;
- // PlatformRead implementation must call this method on read
- // success, rather than directly running the callback.
- // In case incoming buffer is empty or protected, it is filtered
- // and this method returns false. Otherwise it runs the callback
- // and returns true.
- bool CompleteRead(scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const ReadCallback& callback);
-
- private:
bool IsReportIdProtected(uint8_t report_id);
+ private:
scoped_refptr<HidDeviceInfo> device_info_;
bool has_protected_collection_;
base::ThreadChecker thread_checker_;
diff --git a/chromium/device/hid/hid_connection_linux.cc b/chromium/device/hid/hid_connection_linux.cc
index 5172b0b39ea..62d06c35d6a 100644
--- a/chromium/device/hid/hid_connection_linux.cc
+++ b/chromium/device/hid/hid_connection_linux.cc
@@ -14,9 +14,8 @@
#include "base/bind.h"
#include "base/files/file_descriptor_watcher_posix.h"
-#include "base/files/file_path.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/memory/ptr_util.h"
#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -33,44 +32,91 @@
namespace device {
-class HidConnectionLinux::FileThreadHelper
- : public base::MessageLoop::DestructionObserver {
+class HidConnectionLinux::FileThreadHelper {
public:
- FileThreadHelper(base::PlatformFile platform_file,
+ FileThreadHelper(base::ScopedFD fd,
scoped_refptr<HidDeviceInfo> device_info,
- base::WeakPtr<HidConnectionLinux> connection,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : platform_file_(platform_file),
+ base::WeakPtr<HidConnectionLinux> connection)
+ : fd_(std::move(fd)),
connection_(connection),
- task_runner_(task_runner) {
+ origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ sequence_checker_.DetachFromSequence();
// Report buffers must always have room for the report ID.
report_buffer_size_ = device_info->max_input_report_size() + 1;
has_report_id_ = device_info->has_report_id();
}
- ~FileThreadHelper() override {
- DCHECK(thread_checker_.CalledOnValidThread());
- base::MessageLoop::current()->RemoveDestructionObserver(this);
- }
+ ~FileThreadHelper() { DCHECK(sequence_checker_.CalledOnValidSequence()); }
// Starts the FileDescriptorWatcher that reads input events from the device.
// Must be called on a thread that has a base::MessageLoopForIO.
- static void Start(std::unique_ptr<FileThreadHelper> self) {
+ void Start() {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
base::ThreadRestrictions::AssertIOAllowed();
- self->thread_checker_.DetachFromThread();
- self->file_watcher_ = base::FileDescriptorWatcher::WatchReadable(
- self->platform_file_,
- base::Bind(&FileThreadHelper::OnFileCanReadWithoutBlocking,
- base::Unretained(self.get())));
+ file_watcher_ = base::FileDescriptorWatcher::WatchReadable(
+ fd_.get(), base::Bind(&FileThreadHelper::OnFileCanReadWithoutBlocking,
+ base::Unretained(this)));
+ }
+
+ void Write(scoped_refptr<net::IOBuffer> buffer,
+ size_t size,
+ const WriteCallback& callback) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ ssize_t result = HANDLE_EINTR(write(fd_.get(), buffer->data(), size));
+ if (result < 0) {
+ HID_PLOG(EVENT) << "Write failed";
+ origin_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
+ } else {
+ if (static_cast<size_t>(result) != size)
+ HID_LOG(EVENT) << "Incomplete HID write: " << result << " != " << size;
+ origin_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
+ }
+ }
+
+ void GetFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const ReadCallback& callback) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ int result = HANDLE_EINTR(
+ ioctl(fd_.get(), HIDIOCGFEATURE(buffer->size()), buffer->data()));
+ if (result < 0) {
+ HID_PLOG(EVENT) << "Failed to get feature report";
+ origin_task_runner_->PostTask(FROM_HERE,
+ base::Bind(callback, false, nullptr, 0));
+ } else if (result == 0) {
+ HID_LOG(EVENT) << "Get feature result too short.";
+ origin_task_runner_->PostTask(FROM_HERE,
+ base::Bind(callback, false, nullptr, 0));
+ } else if (report_id == 0) {
+ // Linux adds a 0 to the beginning of the data received from the device.
+ scoped_refptr<net::IOBuffer> copied_buffer(new net::IOBuffer(result - 1));
+ memcpy(copied_buffer->data(), buffer->data() + 1, result - 1);
+ origin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(callback, true, copied_buffer, result - 1));
+ } else {
+ origin_task_runner_->PostTask(FROM_HERE,
+ base::Bind(callback, true, buffer, result));
+ }
+ }
- // |self| is now owned by the current message loop.
- base::MessageLoop::current()->AddDestructionObserver(self.release());
+ void SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
+ size_t size,
+ const WriteCallback& callback) {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+ int result =
+ HANDLE_EINTR(ioctl(fd_.get(), HIDIOCSFEATURE(size), buffer->data()));
+ if (result < 0) {
+ HID_PLOG(EVENT) << "Failed to send feature report";
+ origin_task_runner_->PostTask(FROM_HERE, base::Bind(callback, false));
+ } else {
+ origin_task_runner_->PostTask(FROM_HERE, base::Bind(callback, true));
+ }
}
private:
void OnFileCanReadWithoutBlocking() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequence());
scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(report_buffer_size_));
char* data = buffer->data();
@@ -82,7 +128,7 @@ class HidConnectionLinux::FileThreadHelper
length--;
}
- ssize_t bytes_read = HANDLE_EINTR(read(platform_file_, data, length));
+ ssize_t bytes_read = HANDLE_EINTR(read(fd_.get(), data, length));
if (bytes_read < 0) {
if (errno != EAGAIN) {
HID_PLOG(EVENT) << "Read failed";
@@ -100,23 +146,17 @@ class HidConnectionLinux::FileThreadHelper
bytes_read++;
}
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&HidConnectionLinux::ProcessInputReport,
- connection_, buffer, bytes_read));
+ origin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HidConnectionLinux::ProcessInputReport,
+ connection_, buffer, bytes_read));
}
- // base::MessageLoop::DestructionObserver:
- void WillDestroyCurrentMessageLoop() override {
- DCHECK(thread_checker_.CalledOnValidThread());
- delete this;
- }
-
- base::ThreadChecker thread_checker_;
- base::PlatformFile platform_file_;
+ base::SequenceChecker sequence_checker_;
+ base::ScopedFD fd_;
size_t report_buffer_size_;
bool has_report_id_;
base::WeakPtr<HidConnectionLinux> connection_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ const scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
std::unique_ptr<base::FileDescriptorWatcher::Controller> file_watcher_;
DISALLOW_COPY_AND_ASSIGN(FileThreadHelper);
@@ -124,38 +164,28 @@ class HidConnectionLinux::FileThreadHelper
HidConnectionLinux::HidConnectionLinux(
scoped_refptr<HidDeviceInfo> device_info,
- base::File device_file,
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
+ base::ScopedFD fd,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
: HidConnection(device_info),
- file_task_runner_(file_task_runner),
+ blocking_task_runner_(std::move(blocking_task_runner)),
weak_factory_(this) {
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
- device_file_ = std::move(device_file);
-
- // The helper is passed a weak pointer to this connection so that it can be
- // cleaned up after the connection is closed.
- std::unique_ptr<FileThreadHelper> helper(
- new FileThreadHelper(device_file_.GetPlatformFile(), device_info,
- weak_factory_.GetWeakPtr(), task_runner_));
- helper_ = helper.get();
- file_task_runner_->PostTask(
- FROM_HERE, base::Bind(&FileThreadHelper::Start, base::Passed(&helper)));
+ helper_ = base::MakeUnique<FileThreadHelper>(std::move(fd), device_info,
+ weak_factory_.GetWeakPtr());
+ blocking_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get())));
}
HidConnectionLinux::~HidConnectionLinux() {
- DCHECK(helper_ == nullptr);
+ DCHECK(sequence_checker_.CalledOnValidSequence());
}
void HidConnectionLinux::PlatformClose() {
- // By closing the device file on the FILE thread (1) the requirement that
- // base::File::Close is called on a thread where I/O is allowed is satisfied
- // and (2) any tasks posted to this task runner that refer to this file will
+ // By closing the device on the blocking task runner 1) the requirement that
+ // base::ScopedFD is destroyed on a thread where I/O is allowed is satisfied
+ // and 2) any tasks posted to this task runner that refer to this file will
// complete before it is closed.
- file_task_runner_->DeleteSoon(FROM_HERE, helper_);
- helper_ = nullptr;
- file_task_runner_->PostTask(FROM_HERE,
- base::Bind(&HidConnectionLinux::CloseDevice,
- base::Passed(&device_file_)));
+ blocking_task_runner_->DeleteSoon(FROM_HERE, helper_.release());
while (!pending_reads_.empty()) {
pending_reads_.front().callback.Run(false, NULL, 0);
@@ -175,13 +205,10 @@ void HidConnectionLinux::PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
const WriteCallback& callback) {
// Linux expects the first byte of the buffer to always be a report ID so the
// buffer can be used directly.
- file_task_runner_->PostTask(
+ blocking_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&HidConnectionLinux::BlockingWrite,
- device_file_.GetPlatformFile(), buffer, size,
- base::Bind(&HidConnectionLinux::FinishWrite,
- weak_factory_.GetWeakPtr(), size, callback),
- task_runner_));
+ base::Bind(&FileThreadHelper::Write, base::Unretained(helper_.get()),
+ buffer, size, callback));
}
void HidConnectionLinux::PlatformGetFeatureReport(
@@ -194,14 +221,10 @@ void HidConnectionLinux::PlatformGetFeatureReport(
new net::IOBufferWithSize(device_info()->max_feature_report_size() + 1));
buffer->data()[0] = report_id;
- file_task_runner_->PostTask(
+ blocking_task_runner_->PostTask(
FROM_HERE,
- base::Bind(
- &HidConnectionLinux::BlockingIoctl, device_file_.GetPlatformFile(),
- HIDIOCGFEATURE(buffer->size()), buffer,
- base::Bind(&HidConnectionLinux::FinishGetFeatureReport,
- weak_factory_.GetWeakPtr(), report_id, buffer, callback),
- task_runner_));
+ base::Bind(&FileThreadHelper::GetFeatureReport,
+ base::Unretained(helper_.get()), report_id, buffer, callback));
}
void HidConnectionLinux::PlatformSendFeatureReport(
@@ -210,93 +233,21 @@ void HidConnectionLinux::PlatformSendFeatureReport(
const WriteCallback& callback) {
// Linux expects the first byte of the buffer to always be a report ID so the
// buffer can be used directly.
- file_task_runner_->PostTask(
+ blocking_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&HidConnectionLinux::BlockingIoctl,
- device_file_.GetPlatformFile(), HIDIOCSFEATURE(size), buffer,
- base::Bind(&HidConnectionLinux::FinishSendFeatureReport,
- weak_factory_.GetWeakPtr(), callback),
- task_runner_));
-}
-
-void HidConnectionLinux::FinishWrite(size_t expected_size,
- const WriteCallback& callback,
- ssize_t result) {
- if (result < 0) {
- HID_PLOG(EVENT) << "Write failed";
- callback.Run(false);
- } else {
- if (static_cast<size_t>(result) != expected_size) {
- HID_LOG(EVENT) << "Incomplete HID write: " << result
- << " != " << expected_size;
- }
- callback.Run(true);
- }
-}
-
-void HidConnectionLinux::FinishGetFeatureReport(
- uint8_t report_id,
- scoped_refptr<net::IOBuffer> buffer,
- const ReadCallback& callback,
- int result) {
- if (result < 0) {
- HID_PLOG(EVENT) << "Failed to get feature report";
- callback.Run(false, NULL, 0);
- } else if (result == 0) {
- HID_LOG(EVENT) << "Get feature result too short.";
- callback.Run(false, NULL, 0);
- } else if (report_id == 0) {
- // Linux adds a 0 to the beginning of the data received from the device.
- scoped_refptr<net::IOBuffer> copied_buffer(new net::IOBuffer(result - 1));
- memcpy(copied_buffer->data(), buffer->data() + 1, result - 1);
- callback.Run(true, copied_buffer, result - 1);
- } else {
- callback.Run(true, buffer, result);
- }
-}
-
-void HidConnectionLinux::FinishSendFeatureReport(const WriteCallback& callback,
- int result) {
- if (result < 0) {
- HID_PLOG(EVENT) << "Failed to send feature report";
- callback.Run(false);
- } else {
- callback.Run(true);
- }
-}
-
-// static
-void HidConnectionLinux::BlockingWrite(
- base::PlatformFile platform_file,
- scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const InternalWriteCallback& callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- base::ThreadRestrictions::AssertIOAllowed();
- ssize_t result = HANDLE_EINTR(write(platform_file, buffer->data(), size));
- task_runner->PostTask(FROM_HERE, base::Bind(callback, result));
-}
-
-// static
-void HidConnectionLinux::BlockingIoctl(
- base::PlatformFile platform_file,
- int request,
- scoped_refptr<net::IOBuffer> buffer,
- const IoctlCallback& callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- base::ThreadRestrictions::AssertIOAllowed();
- int result = ioctl(platform_file, request, buffer->data());
- task_runner->PostTask(FROM_HERE, base::Bind(callback, result));
-}
-
-// static
-void HidConnectionLinux::CloseDevice(base::File device_file) {
- device_file.Close();
+ base::Bind(&FileThreadHelper::SendFeatureReport,
+ base::Unretained(helper_.get()), buffer, size, callback));
}
void HidConnectionLinux::ProcessInputReport(scoped_refptr<net::IOBuffer> buffer,
size_t size) {
DCHECK(thread_checker().CalledOnValidThread());
+ DCHECK_GE(size, 1u);
+
+ uint8_t report_id = buffer->data()[0];
+ if (IsReportIdProtected(report_id))
+ return;
+
PendingHidReport report;
report.buffer = buffer;
report.size = size;
@@ -306,14 +257,17 @@ void HidConnectionLinux::ProcessInputReport(scoped_refptr<net::IOBuffer> buffer,
void HidConnectionLinux::ProcessReadQueue() {
DCHECK(thread_checker().CalledOnValidThread());
+
+ // Hold a reference to |this| to prevent a callback from freeing this object
+ // during the loop.
+ scoped_refptr<HidConnectionLinux> self(this);
while (pending_reads_.size() && pending_reports_.size()) {
PendingHidRead read = pending_reads_.front();
PendingHidReport report = pending_reports_.front();
+ pending_reads_.pop();
pending_reports_.pop();
- if (CompleteRead(report.buffer, report.size, read.callback)) {
- pending_reads_.pop();
- }
+ read.callback.Run(true, report.buffer, report.size);
}
}
diff --git a/chromium/device/hid/hid_connection_linux.h b/chromium/device/hid/hid_connection_linux.h
index bcdb99c1cc7..574c732638b 100644
--- a/chromium/device/hid/hid_connection_linux.h
+++ b/chromium/device/hid/hid_connection_linux.h
@@ -10,13 +10,14 @@
#include <queue>
-#include "base/files/file.h"
+#include "base/files/scoped_file.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
#include "device/hid/hid_connection.h"
namespace base {
-class SingleThreadTaskRunner;
+class SequencedTaskRunner;
}
namespace device {
@@ -25,16 +26,13 @@ class HidConnectionLinux : public HidConnection {
public:
HidConnectionLinux(
scoped_refptr<HidDeviceInfo> device_info,
- base::File device_file,
- scoped_refptr<base::SingleThreadTaskRunner> file_thread_runner);
+ base::ScopedFD fd,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
private:
friend class base::RefCountedThreadSafe<HidConnectionLinux>;
class FileThreadHelper;
- typedef base::Callback<void(ssize_t)> InternalWriteCallback;
- typedef base::Callback<void(int)> IoctlCallback;
-
~HidConnectionLinux() override;
// HidConnection implementation.
@@ -49,46 +47,21 @@ class HidConnectionLinux : public HidConnection {
size_t size,
const WriteCallback& callback) override;
- // Callbacks for blocking operations run on the FILE thread.
- void FinishWrite(size_t expected_size,
- const WriteCallback& callback,
- ssize_t result);
- void FinishGetFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBuffer> buffer,
- const ReadCallback& callback,
- int result);
- void FinishSendFeatureReport(const WriteCallback& callback, int result);
-
- // Writes to the device. This operation may block.
- static void BlockingWrite(
- base::PlatformFile platform_file,
- scoped_refptr<net::IOBuffer> buffer,
- size_t size,
- const InternalWriteCallback& callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- // Performs an ioctl on the device. This operation may block.
- static void BlockingIoctl(
- base::PlatformFile platform_file,
- int request,
- scoped_refptr<net::IOBuffer> buffer,
- const IoctlCallback& callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
- // Closes the device file descriptor. Must be called on the FILE thread.
- static void CloseDevice(base::File device_file);
-
void ProcessInputReport(scoped_refptr<net::IOBuffer> buffer, size_t size);
void ProcessReadQueue();
- base::File device_file_;
- FileThreadHelper* helper_;
+ // This object lives on the sequence to which |blocking_task_runner_| posts
+ // tasks so all calls must be posted there including this object's
+ // destruction.
+ std::unique_ptr<FileThreadHelper> helper_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+ const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
std::queue<PendingHidReport> pending_reports_;
std::queue<PendingHidRead> pending_reads_;
+ base::SequenceChecker sequence_checker_;
+
base::WeakPtrFactory<HidConnectionLinux> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(HidConnectionLinux);
diff --git a/chromium/device/hid/hid_connection_mac.cc b/chromium/device/hid/hid_connection_mac.cc
index 4aa4a8f3c5b..c13fc2b0d8c 100644
--- a/chromium/device/hid/hid_connection_mac.cc
+++ b/chromium/device/hid/hid_connection_mac.cc
@@ -25,11 +25,11 @@ std::string HexErrorCode(IOReturn error_code) {
} // namespace
HidConnectionMac::HidConnectionMac(
- IOHIDDeviceRef device,
+ base::ScopedCFTypeRef<IOHIDDeviceRef> device,
scoped_refptr<HidDeviceInfo> device_info,
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
: HidConnection(device_info),
- device_(device, base::scoped_policy::RETAIN),
+ device_(std::move(device)),
file_task_runner_(file_task_runner) {
task_runner_ = base::ThreadTaskRunnerHandle::Get();
DCHECK(task_runner_.get());
@@ -152,6 +152,12 @@ void HidConnectionMac::InputReportCallback(void* context,
void HidConnectionMac::ProcessInputReport(
scoped_refptr<net::IOBufferWithSize> buffer) {
DCHECK(thread_checker().CalledOnValidThread());
+ DCHECK_GE(buffer->size(), 1);
+
+ uint8_t report_id = buffer->data()[0];
+ if (IsReportIdProtected(report_id))
+ return;
+
PendingHidReport report;
report.buffer = buffer;
report.size = buffer->size();
@@ -161,14 +167,17 @@ void HidConnectionMac::ProcessInputReport(
void HidConnectionMac::ProcessReadQueue() {
DCHECK(thread_checker().CalledOnValidThread());
+
+ // Hold a reference to |this| to prevent a callback from freeing this object
+ // during the loop.
+ scoped_refptr<HidConnectionMac> self(this);
while (pending_reads_.size() && pending_reports_.size()) {
PendingHidRead read = pending_reads_.front();
PendingHidReport report = pending_reports_.front();
+ pending_reads_.pop();
pending_reports_.pop();
- if (CompleteRead(report.buffer, report.size, read.callback)) {
- pending_reads_.pop();
- }
+ read.callback.Run(true, report.buffer, report.size);
}
}
diff --git a/chromium/device/hid/hid_connection_mac.h b/chromium/device/hid/hid_connection_mac.h
index c3ea163b39f..da0dacd501c 100644
--- a/chromium/device/hid/hid_connection_mac.h
+++ b/chromium/device/hid/hid_connection_mac.h
@@ -6,7 +6,7 @@
#define DEVICE_HID_HID_CONNECTION_MAC_H_
#include <CoreFoundation/CoreFoundation.h>
-#include <IOKit/hid/IOHIDManager.h>
+#include <IOKit/hid/IOHIDDevice.h>
#include <stddef.h>
#include <stdint.h>
@@ -29,7 +29,7 @@ namespace device {
class HidConnectionMac : public HidConnection {
public:
HidConnectionMac(
- IOHIDDeviceRef device,
+ base::ScopedCFTypeRef<IOHIDDeviceRef> device,
scoped_refptr<HidDeviceInfo> device_info,
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner);
diff --git a/chromium/device/hid/hid_connection_win.cc b/chromium/device/hid/hid_connection_win.cc
index a98007ae095..ad4ca2a26f8 100644
--- a/chromium/device/hid/hid_connection_win.cc
+++ b/chromium/device/hid/hid_connection_win.cc
@@ -11,7 +11,6 @@
#include "base/files/file.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/numerics/safe_conversions.h"
#include "base/win/object_watcher.h"
#include "components/device_event_log/device_event_log.h"
@@ -30,8 +29,7 @@ extern "C" {
namespace device {
-class PendingHidTransfer : public base::win::ObjectWatcher::Delegate,
- public base::MessageLoop::DestructionObserver {
+class PendingHidTransfer : public base::win::ObjectWatcher::Delegate {
public:
typedef base::OnceCallback<void(PendingHidTransfer*, bool)> Callback;
@@ -45,9 +43,6 @@ class PendingHidTransfer : public base::win::ObjectWatcher::Delegate,
// Implements base::win::ObjectWatcher::Delegate.
void OnObjectSignaled(HANDLE object) override;
- // Implements base::MessageLoop::DestructionObserver
- void WillDestroyCurrentMessageLoop() override;
-
private:
// The buffer isn't used by this object but it's important that a reference
// to it is held until the transfer completes.
@@ -70,7 +65,6 @@ PendingHidTransfer::PendingHidTransfer(scoped_refptr<net::IOBuffer> buffer,
}
PendingHidTransfer::~PendingHidTransfer() {
- base::MessageLoop::current()->RemoveDestructionObserver(this);
if (callback_)
std::move(callback_).Run(this, false);
}
@@ -79,7 +73,6 @@ void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) {
if (result) {
std::move(callback_).Run(this, true);
} else if (GetLastError() == ERROR_IO_PENDING) {
- base::MessageLoop::current()->AddDestructionObserver(this);
watcher_.StartWatchingOnce(event_.Get(), this);
} else {
HID_PLOG(EVENT) << "HID transfer failed";
@@ -91,14 +84,9 @@ void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) {
std::move(callback_).Run(this, true);
}
-void PendingHidTransfer::WillDestroyCurrentMessageLoop() {
- watcher_.StopWatching();
- std::move(callback_).Run(this, false);
-}
-
HidConnectionWin::HidConnectionWin(scoped_refptr<HidDeviceInfo> device_info,
base::win::ScopedHandle file)
- : HidConnection(device_info), file_(std::move(file)) {}
+ : HidConnection(std::move(device_info)), file_(std::move(file)) {}
HidConnectionWin::~HidConnectionWin() {
DCHECK(!file_.IsValid());
@@ -191,13 +179,26 @@ void HidConnectionWin::OnReadComplete(scoped_refptr<net::IOBuffer> buffer,
std::unique_ptr<PendingHidTransfer> transfer = UnlinkTransfer(transfer_raw);
DWORD bytes_transferred;
- if (signaled && GetOverlappedResult(file_.Get(), transfer->GetOverlapped(),
- &bytes_transferred, FALSE)) {
- CompleteRead(buffer, bytes_transferred, callback);
- } else {
+ if (!signaled || !GetOverlappedResult(file_.Get(), transfer->GetOverlapped(),
+ &bytes_transferred, FALSE)) {
HID_PLOG(EVENT) << "HID read failed";
callback.Run(false, nullptr, 0);
+ return;
}
+
+ if (bytes_transferred < 1) {
+ HID_LOG(EVENT) << "HID read too short.";
+ callback.Run(false, nullptr, 0);
+ return;
+ }
+
+ uint8_t report_id = buffer->data()[0];
+ if (IsReportIdProtected(report_id)) {
+ PlatformRead(callback);
+ return;
+ }
+
+ callback.Run(true, buffer, bytes_transferred);
}
void HidConnectionWin::OnReadFeatureComplete(
diff --git a/chromium/device/hid/hid_service_linux.cc b/chromium/device/hid/hid_service_linux.cc
index 1cd5d393b17..6b524466403 100644
--- a/chromium/device/hid/hid_service_linux.cc
+++ b/chromium/device/hid/hid_service_linux.cc
@@ -16,6 +16,7 @@
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -52,25 +53,25 @@ const char kSysfsReportDescriptorKey[] = "report_descriptor";
struct HidServiceLinux::ConnectParams {
ConnectParams(scoped_refptr<HidDeviceInfoLinux> device_info,
const ConnectCallback& callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
- : device_info(device_info),
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
+ : device_info(std::move(device_info)),
callback(callback),
- task_runner(task_runner),
- file_task_runner(file_task_runner) {}
+ task_runner(std::move(task_runner)),
+ blocking_task_runner(std::move(blocking_task_runner)) {}
~ConnectParams() {}
scoped_refptr<HidDeviceInfoLinux> device_info;
ConnectCallback callback;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner;
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner;
- base::File device_file;
+ scoped_refptr<base::SequencedTaskRunner> task_runner;
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner;
+ base::ScopedFD fd;
};
class HidServiceLinux::FileThreadHelper : public DeviceMonitorLinux::Observer {
public:
FileThreadHelper(base::WeakPtr<HidServiceLinux> service,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
: observer_(this), service_(service), task_runner_(task_runner) {
thread_checker_.DetachFromThread();
}
@@ -192,18 +193,19 @@ class HidServiceLinux::FileThreadHelper : public DeviceMonitorLinux::Observer {
// This weak pointer is only valid when checked on this task runner.
base::WeakPtr<HidServiceLinux> service_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(FileThreadHelper);
};
HidServiceLinux::HidServiceLinux(
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
- : file_task_runner_(std::move(file_task_runner)), weak_factory_(this) {
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
+ : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ blocking_task_runner_(std::move(blocking_task_runner)),
+ weak_factory_(this) {
helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr(),
task_runner_);
- file_task_runner_->PostTask(
+ blocking_task_runner_->PostTask(
FROM_HERE,
base::Bind(&FileThreadHelper::Start, base::Unretained(helper_.get())));
}
@@ -214,7 +216,7 @@ HidServiceLinux::~HidServiceLinux() {
void HidServiceLinux::Shutdown() {
const bool did_post_task =
- file_task_runner_->DeleteSoon(FROM_HERE, helper_.release());
+ blocking_task_runner_->DeleteSoon(FROM_HERE, helper_.release());
DCHECK(did_post_task);
HidService::Shutdown();
}
@@ -232,7 +234,7 @@ void HidServiceLinux::Connect(const HidDeviceId& device_id,
static_cast<HidDeviceInfoLinux*>(map_entry->second.get());
std::unique_ptr<ConnectParams> params(new ConnectParams(
- device_info, callback, task_runner_, file_task_runner_));
+ device_info, callback, task_runner_, blocking_task_runner_));
#if defined(OS_CHROMEOS)
chromeos::PermissionBrokerClient* client =
@@ -246,9 +248,9 @@ void HidServiceLinux::Connect(const HidDeviceId& device_id,
base::Bind(&HidServiceLinux::OnPathOpenComplete, base::Passed(&params)),
error_callback);
#else
- file_task_runner_->PostTask(FROM_HERE,
- base::Bind(&HidServiceLinux::OpenOnBlockingThread,
- base::Passed(&params)));
+ blocking_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HidServiceLinux::OpenOnBlockingThread,
+ base::Passed(&params)));
#endif // defined(OS_CHROMEOS)
}
@@ -257,11 +259,12 @@ void HidServiceLinux::Connect(const HidDeviceId& device_id,
// static
void HidServiceLinux::OnPathOpenComplete(std::unique_ptr<ConnectParams> params,
base::ScopedFD fd) {
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner =
- params->file_task_runner;
- params->device_file = base::File(fd.release());
- file_task_runner->PostTask(FROM_HERE, base::Bind(&HidServiceLinux::FinishOpen,
- base::Passed(&params)));
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
+ params->blocking_task_runner;
+ params->fd = std::move(fd);
+ blocking_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&HidServiceLinux::FinishOpen, base::Passed(&params)));
}
// static
@@ -280,10 +283,10 @@ void HidServiceLinux::OnPathOpenError(const std::string& device_path,
void HidServiceLinux::OpenOnBlockingThread(
std::unique_ptr<ConnectParams> params) {
base::ThreadRestrictions::AssertIOAllowed();
- scoped_refptr<base::SingleThreadTaskRunner> task_runner = params->task_runner;
+ scoped_refptr<base::SequencedTaskRunner> task_runner = params->task_runner;
base::FilePath device_path(params->device_info->device_node());
- base::File& device_file = params->device_file;
+ base::File device_file;
int flags =
base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE;
device_file.Initialize(device_path, flags);
@@ -304,7 +307,7 @@ void HidServiceLinux::OpenOnBlockingThread(
task_runner->PostTask(FROM_HERE, base::Bind(params->callback, nullptr));
return;
}
-
+ params->fd.reset(device_file.TakePlatformFile());
FinishOpen(std::move(params));
}
@@ -313,9 +316,9 @@ void HidServiceLinux::OpenOnBlockingThread(
// static
void HidServiceLinux::FinishOpen(std::unique_ptr<ConnectParams> params) {
base::ThreadRestrictions::AssertIOAllowed();
- scoped_refptr<base::SingleThreadTaskRunner> task_runner = params->task_runner;
+ scoped_refptr<base::SequencedTaskRunner> task_runner = params->task_runner;
- if (!base::SetNonBlocking(params->device_file.GetPlatformFile())) {
+ if (!base::SetNonBlocking(params->fd.get())) {
HID_PLOG(ERROR) << "Failed to set the non-blocking flag on the device fd";
task_runner->PostTask(FROM_HERE, base::Bind(params->callback, nullptr));
return;
@@ -328,10 +331,10 @@ void HidServiceLinux::FinishOpen(std::unique_ptr<ConnectParams> params) {
// static
void HidServiceLinux::CreateConnection(std::unique_ptr<ConnectParams> params) {
- DCHECK(params->device_file.IsValid());
+ DCHECK(params->fd.is_valid());
params->callback.Run(make_scoped_refptr(new HidConnectionLinux(
- params->device_info, std::move(params->device_file),
- params->file_task_runner)));
+ std::move(params->device_info), std::move(params->fd),
+ std::move(params->blocking_task_runner))));
}
} // namespace device
diff --git a/chromium/device/hid/hid_service_linux.h b/chromium/device/hid/hid_service_linux.h
index 5f8084f8bf8..17616ba6699 100644
--- a/chromium/device/hid/hid_service_linux.h
+++ b/chromium/device/hid/hid_service_linux.h
@@ -19,7 +19,8 @@ namespace device {
class HidServiceLinux : public HidService {
public:
- HidServiceLinux(scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+ HidServiceLinux(
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
~HidServiceLinux() override;
// HidService:
@@ -48,8 +49,8 @@ class HidServiceLinux : public HidService {
static void FinishOpen(std::unique_ptr<ConnectParams> params);
static void CreateConnection(std::unique_ptr<ConnectParams> params);
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+ const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
// The helper lives on the FILE thread and holds a weak reference back to the
// service that owns it.
diff --git a/chromium/device/hid/hid_service_mac.cc b/chromium/device/hid/hid_service_mac.cc
index d887eeee947..92d1617b9ff 100644
--- a/chromium/device/hid/hid_service_mac.cc
+++ b/chromium/device/hid/hid_service_mac.cc
@@ -5,7 +5,6 @@
#include "device/hid/hid_service_mac.h"
#include <CoreFoundation/CoreFoundation.h>
-#include <IOKit/hid/IOHIDDevice.h>
#include <stdint.h>
#include <set>
@@ -33,58 +32,67 @@ std::string HexErrorCode(IOReturn error_code) {
return base::StringPrintf("0x%04x", error_code);
}
-bool TryGetHidIntProperty(IOHIDDeviceRef device,
- CFStringRef key,
- int32_t* result) {
- CFNumberRef ref =
- base::mac::CFCast<CFNumberRef>(IOHIDDeviceGetProperty(device, key));
- return ref && CFNumberGetValue(ref, kCFNumberSInt32Type, result);
-}
-
-int32_t GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key) {
- int32_t value;
- if (TryGetHidIntProperty(device, key, &value))
- return value;
+int32_t GetIntProperty(io_service_t service, CFStringRef key) {
+ base::ScopedCFTypeRef<CFNumberRef> ref(base::mac::CFCast<CFNumberRef>(
+ IORegistryEntryCreateCFProperty(service, key, kCFAllocatorDefault, 0)));
+ int32_t result;
+ if (ref && CFNumberGetValue(ref, kCFNumberSInt32Type, &result))
+ return result;
return 0;
}
-bool TryGetHidStringProperty(IOHIDDeviceRef device,
- CFStringRef key,
- std::string* result) {
- CFStringRef ref =
- base::mac::CFCast<CFStringRef>(IOHIDDeviceGetProperty(device, key));
- if (!ref) {
- return false;
- }
- *result = base::SysCFStringRefToUTF8(ref);
- return true;
-}
-
-std::string GetHidStringProperty(IOHIDDeviceRef device, CFStringRef key) {
- std::string value;
- TryGetHidStringProperty(device, key, &value);
- return value;
+std::string GetStringProperty(io_service_t service, CFStringRef key) {
+ base::ScopedCFTypeRef<CFStringRef> ref(base::mac::CFCast<CFStringRef>(
+ IORegistryEntryCreateCFProperty(service, key, kCFAllocatorDefault, 0)));
+ if (ref)
+ return base::SysCFStringRefToUTF8(ref);
+ return std::string();
}
-bool TryGetHidDataProperty(IOHIDDeviceRef device,
+bool TryGetHidDataProperty(io_service_t service,
CFStringRef key,
std::vector<uint8_t>* result) {
- CFDataRef ref =
- base::mac::CFCast<CFDataRef>(IOHIDDeviceGetProperty(device, key));
- if (!ref) {
+ base::ScopedCFTypeRef<CFDataRef> ref(base::mac::CFCast<CFDataRef>(
+ IORegistryEntryCreateCFProperty(service, key, kCFAllocatorDefault, 0)));
+ if (!ref)
return false;
- }
+
base::STLClearObject(result);
const uint8_t* bytes = CFDataGetBytePtr(ref);
result->insert(result->begin(), bytes, bytes + CFDataGetLength(ref));
return true;
}
+scoped_refptr<HidDeviceInfo> CreateDeviceInfo(
+ base::mac::ScopedIOObject<io_service_t> service) {
+ uint64_t entry_id;
+ IOReturn result = IORegistryEntryGetRegistryEntryID(service, &entry_id);
+ if (result != kIOReturnSuccess) {
+ HID_LOG(EVENT) << "Failed to get IORegistryEntry ID: "
+ << HexErrorCode(result);
+ return nullptr;
+ }
+
+ std::vector<uint8_t> report_descriptor;
+ if (!TryGetHidDataProperty(service, CFSTR(kIOHIDReportDescriptorKey),
+ &report_descriptor)) {
+ HID_LOG(DEBUG) << "Device report descriptor not available.";
+ }
+
+ return new HidDeviceInfo(
+ entry_id, GetIntProperty(service, CFSTR(kIOHIDVendorIDKey)),
+ GetIntProperty(service, CFSTR(kIOHIDProductIDKey)),
+ GetStringProperty(service, CFSTR(kIOHIDProductKey)),
+ GetStringProperty(service, CFSTR(kIOHIDSerialNumberKey)),
+ kHIDBusTypeUSB, // TODO(reillyg): Detect Bluetooth. crbug.com/443335
+ report_descriptor);
+}
+
} // namespace
HidServiceMac::HidServiceMac(
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
- : file_task_runner_(file_task_runner) {
+ : file_task_runner_(file_task_runner), weak_factory_(this) {
task_runner_ = base::ThreadTaskRunnerHandle::Get();
DCHECK(task_runner_.get());
@@ -132,14 +140,25 @@ void HidServiceMac::Connect(const HidDeviceId& device_id,
task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
return;
}
- scoped_refptr<HidDeviceInfo> device_info = map_entry->second;
+ file_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&HidServiceMac::OpenOnBlockingThread, map_entry->second,
+ task_runner_, weak_factory_.GetWeakPtr(), callback));
+}
+
+// static
+void HidServiceMac::OpenOnBlockingThread(
+ scoped_refptr<HidDeviceInfo> device_info,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ base::WeakPtr<HidServiceMac> hid_service,
+ const ConnectCallback& callback) {
base::ScopedCFTypeRef<CFDictionaryRef> matching_dict(
- IORegistryEntryIDMatching(device_id));
+ IORegistryEntryIDMatching(device_info->device_id()));
if (!matching_dict.get()) {
HID_LOG(EVENT) << "Failed to create matching dictionary for ID: "
- << device_id;
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
+ << device_info->device_id();
+ task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr));
return;
}
@@ -148,8 +167,9 @@ void HidServiceMac::Connect(const HidDeviceId& device_id,
base::mac::ScopedIOObject<io_service_t> service(IOServiceGetMatchingService(
kIOMasterPortDefault, matching_dict.release()));
if (!service.get()) {
- HID_LOG(EVENT) << "IOService not found for ID: " << device_id;
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
+ HID_LOG(EVENT) << "IOService not found for ID: "
+ << device_info->device_id();
+ task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr));
return;
}
@@ -157,21 +177,28 @@ void HidServiceMac::Connect(const HidDeviceId& device_id,
IOHIDDeviceCreate(kCFAllocatorDefault, service));
if (!hid_device) {
HID_LOG(EVENT) << "Unable to create IOHIDDevice object.";
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
+ task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr));
return;
}
IOReturn result = IOHIDDeviceOpen(hid_device, kIOHIDOptionsTypeNone);
if (result != kIOReturnSuccess) {
HID_LOG(EVENT) << "Failed to open device: " << HexErrorCode(result);
- task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr));
+ task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr));
return;
}
- task_runner_->PostTask(
- FROM_HERE, base::Bind(callback, make_scoped_refptr(new HidConnectionMac(
- hid_device.release(), device_info,
- file_task_runner_))));
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(&HidServiceMac::DeviceOpened, hid_service,
+ device_info, base::Passed(&hid_device), callback));
+}
+
+void HidServiceMac::DeviceOpened(
+ scoped_refptr<HidDeviceInfo> device_info,
+ base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device,
+ const ConnectCallback& callback) {
+ callback.Run(make_scoped_refptr(new HidConnectionMac(
+ std::move(hid_device), std::move(device_info), file_task_runner_)));
}
// static
@@ -193,69 +220,25 @@ void HidServiceMac::TerminatedCallback(void* context, io_iterator_t iterator) {
void HidServiceMac::AddDevices() {
DCHECK(thread_checker_.CalledOnValidThread());
- io_service_t device;
- while ((device = IOIteratorNext(devices_added_iterator_)) != IO_OBJECT_NULL) {
- scoped_refptr<HidDeviceInfo> device_info = CreateDeviceInfo(device);
- if (device_info) {
+ base::mac::ScopedIOObject<io_service_t> device;
+ while (device.reset(IOIteratorNext(devices_added_iterator_)), device) {
+ scoped_refptr<HidDeviceInfo> device_info =
+ CreateDeviceInfo(std::move(device));
+ if (device_info)
AddDevice(device_info);
- // The reference retained by IOIteratorNext is released below in
- // RemoveDevices when the device is removed.
- } else {
- IOObjectRelease(device);
- }
}
}
void HidServiceMac::RemoveDevices() {
DCHECK(thread_checker_.CalledOnValidThread());
- io_service_t device;
- while ((device = IOIteratorNext(devices_removed_iterator_)) !=
- IO_OBJECT_NULL) {
+ base::mac::ScopedIOObject<io_service_t> device;
+ while (device.reset(IOIteratorNext(devices_removed_iterator_)), device) {
uint64_t entry_id;
IOReturn result = IORegistryEntryGetRegistryEntryID(device, &entry_id);
- if (result == kIOReturnSuccess) {
+ if (result == kIOReturnSuccess)
RemoveDevice(entry_id);
- }
-
- // Release reference retained by AddDevices above.
- IOObjectRelease(device);
- // Release the reference retained by IOIteratorNext.
- IOObjectRelease(device);
- }
-}
-
-// static
-scoped_refptr<HidDeviceInfo> HidServiceMac::CreateDeviceInfo(
- io_service_t service) {
- uint64_t entry_id;
- IOReturn result = IORegistryEntryGetRegistryEntryID(service, &entry_id);
- if (result != kIOReturnSuccess) {
- HID_LOG(EVENT) << "Failed to get IORegistryEntry ID: "
- << HexErrorCode(result);
- return nullptr;
}
-
- base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device(
- IOHIDDeviceCreate(kCFAllocatorDefault, service));
- if (!hid_device) {
- HID_LOG(EVENT) << "Unable to create IOHIDDevice object for new device.";
- return nullptr;
- }
-
- std::vector<uint8_t> report_descriptor;
- if (!TryGetHidDataProperty(hid_device, CFSTR(kIOHIDReportDescriptorKey),
- &report_descriptor)) {
- HID_LOG(DEBUG) << "Device report descriptor not available.";
- }
-
- return new HidDeviceInfo(
- entry_id, GetHidIntProperty(hid_device, CFSTR(kIOHIDVendorIDKey)),
- GetHidIntProperty(hid_device, CFSTR(kIOHIDProductIDKey)),
- GetHidStringProperty(hid_device, CFSTR(kIOHIDProductKey)),
- GetHidStringProperty(hid_device, CFSTR(kIOHIDSerialNumberKey)),
- kHIDBusTypeUSB, // TODO(reillyg): Detect Bluetooth. crbug.com/443335
- report_descriptor);
}
} // namespace device
diff --git a/chromium/device/hid/hid_service_mac.h b/chromium/device/hid/hid_service_mac.h
index f3af539a252..7d6c0531d50 100644
--- a/chromium/device/hid/hid_service_mac.h
+++ b/chromium/device/hid/hid_service_mac.h
@@ -7,6 +7,7 @@
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
+#include <IOKit/hid/IOHIDDevice.h>
#include <string>
@@ -15,6 +16,7 @@
#include "base/mac/scoped_ioobject.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "device/hid/hid_service.h"
namespace base {
@@ -32,6 +34,15 @@ class HidServiceMac : public HidService {
const ConnectCallback& connect) override;
private:
+ static void OpenOnBlockingThread(
+ scoped_refptr<HidDeviceInfo> device_info,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ base::WeakPtr<HidServiceMac> hid_service,
+ const ConnectCallback& callback);
+ void DeviceOpened(scoped_refptr<HidDeviceInfo> device_info,
+ base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device,
+ const ConnectCallback& callback);
+
// IOService matching callbacks.
static void FirstMatchCallback(void* context, io_iterator_t iterator);
static void TerminatedCallback(void* context, io_iterator_t iterator);
@@ -39,9 +50,6 @@ class HidServiceMac : public HidService {
void AddDevices();
void RemoveDevices();
- static scoped_refptr<device::HidDeviceInfo> CreateDeviceInfo(
- io_service_t device);
-
// Platform notification port.
base::mac::ScopedIONotificationPortRef notify_port_;
base::mac::ScopedIOObject<io_iterator_t> devices_added_iterator_;
@@ -54,6 +62,8 @@ class HidServiceMac : public HidService {
// on which slow running I/O operations can be performed.
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+ base::WeakPtrFactory<HidServiceMac> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(HidServiceMac);
};
diff --git a/chromium/device/hid/hid_service_win.cc b/chromium/device/hid/hid_service_win.cc
index 3bbc657562b..a7f252eefd4 100644
--- a/chromium/device/hid/hid_service_win.cc
+++ b/chromium/device/hid/hid_service_win.cc
@@ -19,11 +19,10 @@
#include "base/files/file.h"
#include "base/location.h"
#include "base/memory/free_deleter.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "components/device_event_log/device_event_log.h"
#include "device/hid/hid_connection_win.h"
#include "device/hid/hid_device_info.h"
@@ -32,19 +31,18 @@
namespace device {
HidServiceWin::HidServiceWin(
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
- : file_task_runner_(file_task_runner),
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
+ : task_runner_(base::SequencedTaskRunnerHandle::Get()),
+ blocking_task_runner_(std::move(blocking_task_runner)),
device_observer_(this),
weak_factory_(this) {
- task_runner_ = base::ThreadTaskRunnerHandle::Get();
- DCHECK(task_runner_.get());
DeviceMonitorWin* device_monitor =
DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_HID);
- if (device_monitor) {
+ if (device_monitor)
device_observer_.Add(device_monitor);
- }
- file_task_runner_->PostTask(
- FROM_HERE, base::Bind(&HidServiceWin::EnumerateOnFileThread,
+
+ blocking_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&HidServiceWin::EnumerateBlocking,
weak_factory_.GetWeakPtr(), task_runner_));
}
@@ -74,9 +72,9 @@ void HidServiceWin::Connect(const HidDeviceId& device_id,
}
// static
-void HidServiceWin::EnumerateOnFileThread(
+void HidServiceWin::EnumerateBlocking(
base::WeakPtr<HidServiceWin> service,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
HDEVINFO device_info_set =
SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
@@ -115,8 +113,7 @@ void HidServiceWin::EnumerateOnFileThread(
std::string device_path(
base::SysWideToUTF8(device_interface_detail_data->DevicePath));
DCHECK(base::IsStringASCII(device_path));
- AddDeviceOnFileThread(service, task_runner,
- base::ToLowerASCII(device_path));
+ AddDeviceBlocking(service, task_runner, base::ToLowerASCII(device_path));
}
}
@@ -170,9 +167,9 @@ void HidServiceWin::CollectInfoFromValueCaps(
}
// static
-void HidServiceWin::AddDeviceOnFileThread(
+void HidServiceWin::AddDeviceBlocking(
base::WeakPtr<HidServiceWin> service,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
const std::string& device_path) {
base::win::ScopedHandle device_handle(OpenDevice(device_path));
if (!device_handle.IsValid()) {
@@ -270,17 +267,17 @@ void HidServiceWin::AddDeviceOnFileThread(
void HidServiceWin::OnDeviceAdded(const GUID& class_guid,
const std::string& device_path) {
- file_task_runner_->PostTask(
+ blocking_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&HidServiceWin::AddDeviceOnFileThread,
- weak_factory_.GetWeakPtr(), task_runner_, device_path));
+ base::Bind(&HidServiceWin::AddDeviceBlocking, weak_factory_.GetWeakPtr(),
+ task_runner_, device_path));
}
void HidServiceWin::OnDeviceRemoved(const GUID& class_guid,
const std::string& device_path) {
// Execute a no-op closure on the file task runner to synchronize with any
// devices that are still being enumerated.
- file_task_runner_->PostTaskAndReply(
+ blocking_task_runner_->PostTaskAndReply(
FROM_HERE, base::Bind(&base::DoNothing),
base::Bind(&HidServiceWin::RemoveDevice, weak_factory_.GetWeakPtr(),
device_path));
diff --git a/chromium/device/hid/hid_service_win.h b/chromium/device/hid/hid_service_win.h
index c8814f986d4..519f8ed5b39 100644
--- a/chromium/device/hid/hid_service_win.h
+++ b/chromium/device/hid/hid_service_win.h
@@ -23,20 +23,24 @@ extern "C" {
#include "device/hid/hid_device_info.h"
#include "device/hid/hid_service.h"
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace device {
class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
public:
- HidServiceWin(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner);
+ HidServiceWin(scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
~HidServiceWin() override;
void Connect(const HidDeviceId& device_id,
const ConnectCallback& callback) override;
private:
- static void EnumerateOnFileThread(
+ static void EnumerateBlocking(
base::WeakPtr<HidServiceWin> service,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ scoped_refptr<base::SequencedTaskRunner> task_runner);
static void CollectInfoFromButtonCaps(PHIDP_PREPARSED_DATA preparsed_data,
HIDP_REPORT_TYPE report_type,
USHORT button_caps_length,
@@ -45,9 +49,9 @@ class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
HIDP_REPORT_TYPE report_type,
USHORT value_caps_length,
HidCollectionInfo* collection_info);
- static void AddDeviceOnFileThread(
+ static void AddDeviceBlocking(
base::WeakPtr<HidServiceWin> service,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
const std::string& device_path);
// DeviceMonitorWin::Observer implementation:
@@ -59,8 +63,8 @@ class HidServiceWin : public HidService, public DeviceMonitorWin::Observer {
// Tries to open the device read-write and falls back to read-only.
static base::win::ScopedHandle OpenDevice(const std::string& device_path);
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+ const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_;
base::WeakPtrFactory<HidServiceWin> weak_factory_;