diff options
Diffstat (limited to 'device')
-rw-r--r-- | device/core/BUILD.gn | 2 | ||||
-rw-r--r-- | device/core/core.gyp | 2 | ||||
-rw-r--r-- | device/core/device_info_query_win.cc | 66 | ||||
-rw-r--r-- | device/core/device_info_query_win.h | 49 | ||||
-rw-r--r-- | device/serial/BUILD.gn | 1 | ||||
-rw-r--r-- | device/serial/serial.gyp | 1 | ||||
-rw-r--r-- | device/serial/serial_io_handler.cc | 1 | ||||
-rw-r--r-- | device/serial/serial_io_handler.h | 12 | ||||
-rw-r--r-- | device/serial/serial_io_handler_win.cc | 103 | ||||
-rw-r--r-- | device/serial/serial_io_handler_win.h | 8 | ||||
-rw-r--r-- | device/usb/usb.gyp | 1 | ||||
-rw-r--r-- | device/usb/usb_service_impl.cc | 80 |
12 files changed, 252 insertions, 74 deletions
diff --git a/device/core/BUILD.gn b/device/core/BUILD.gn index e85acb6..6f55190 100644 --- a/device/core/BUILD.gn +++ b/device/core/BUILD.gn @@ -8,6 +8,8 @@ component("core") { sources = [ "device_client.cc", "device_client.h", + "device_info_query_win.cc", + "device_info_query_win.h", "device_monitor_win.cc", "device_monitor_win.h", ] diff --git a/device/core/core.gyp b/device/core/core.gyp index d27073d..6002a5f 100644 --- a/device/core/core.gyp +++ b/device/core/core.gyp @@ -19,6 +19,8 @@ 'sources': [ 'device_client.cc', 'device_client.h', + 'device_info_query_win.cc', + 'device_info_query_win.h', 'device_monitor_win.cc', 'device_monitor_win.h', ], diff --git a/device/core/device_info_query_win.cc b/device/core/device_info_query_win.cc new file mode 100644 index 0000000..4d62b32 --- /dev/null +++ b/device/core/device_info_query_win.cc @@ -0,0 +1,66 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/core/device_info_query_win.h" + +#include <string.h> + +#include "base/strings/string_util.h" + +namespace device { + +DeviceInfoQueryWin::DeviceInfoQueryWin() + : device_info_list_(SetupDiCreateDeviceInfoList(nullptr, nullptr)) { + memset(&device_info_data_, 0, sizeof(device_info_data_)); +} + +DeviceInfoQueryWin::~DeviceInfoQueryWin() { + if (device_info_list_valid()) { + // Release |device_info_data_| only when it is valid. + if (device_info_data_.cbSize != 0) + SetupDiDeleteDeviceInfo(device_info_list_, &device_info_data_); + SetupDiDestroyDeviceInfoList(device_info_list_); + } +} + +bool DeviceInfoQueryWin::AddDevice(const char* device_path) { + return SetupDiOpenDeviceInterfaceA(device_info_list_, device_path, 0, + nullptr) != FALSE; +} + +bool DeviceInfoQueryWin::GetDeviceInfo() { + DCHECK_EQ(0U, device_info_data_.cbSize); + device_info_data_.cbSize = sizeof(device_info_data_); + if (!SetupDiEnumDeviceInfo(device_info_list_, 0, &device_info_data_)) { + // Clear cbSize to maintain the invariant. + device_info_data_.cbSize = 0; + return false; + } + return true; +} + +bool DeviceInfoQueryWin::GetDeviceStringProperty(DWORD property, + std::string* property_buffer) { + DWORD property_reg_data_type; + const size_t property_buffer_length = 512; + if (!SetupDiGetDeviceRegistryPropertyA( + device_info_list_, &device_info_data_, property, + &property_reg_data_type, + reinterpret_cast<PBYTE>( + base::WriteInto(property_buffer, property_buffer_length)), + static_cast<DWORD>(property_buffer_length), nullptr)) + return false; + + if (property_reg_data_type != REG_SZ) + return false; + + // Shrink |property_buffer| down to its correct size. + size_t eos = property_buffer->find('\0'); + if (eos != std::string::npos) + property_buffer->resize(eos); + + return true; +} + +} // namespace device diff --git a/device/core/device_info_query_win.h b/device/core/device_info_query_win.h new file mode 100644 index 0000000..2e399e4 --- /dev/null +++ b/device/core/device_info_query_win.h @@ -0,0 +1,49 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_CORE_DEVICE_INFO_QUERY_WIN_H_ +#define DEVICE_CORE_DEVICE_INFO_QUERY_WIN_H_ + +#include <windows.h> +#include <setupapi.h> + +#include <string> + +#include "base/macros.h" +#include "device/core/device_core_export.h" + +namespace device { + +// Wraps HDEVINFO and SP_DEVINFO_DATA into a class that can automatically +// release them. Provides interfaces that can add a device using its +// device path, get device info and get device string property. +class DEVICE_CORE_EXPORT DeviceInfoQueryWin { + public: + DeviceInfoQueryWin(); + ~DeviceInfoQueryWin(); + + // Add a device to |device_info_list_| using its |device_path| so that + // its device info can be retrieved. + bool AddDevice(const char* device_path); + // Get the device info and store it into |device_info_data_|, this function + // should be called at most once. + bool GetDeviceInfo(); + // Get device string property and store it into |property_buffer|. + bool GetDeviceStringProperty(DWORD property, std::string* property_buffer); + + bool device_info_list_valid() { + return device_info_list_ != INVALID_HANDLE_VALUE; + } + + private: + HDEVINFO device_info_list_ = INVALID_HANDLE_VALUE; + // When device_info_data_.cbSize != 0, |device_info_data_| is valid. + SP_DEVINFO_DATA device_info_data_; + + DISALLOW_COPY_AND_ASSIGN(DeviceInfoQueryWin); +}; + +} // namespace device + +#endif // DEVICE_CORE_DEVICE_INFO_QUERY_WIN_H_ diff --git a/device/serial/BUILD.gn b/device/serial/BUILD.gn index 1ee6c5f..f66cedf 100644 --- a/device/serial/BUILD.gn +++ b/device/serial/BUILD.gn @@ -45,6 +45,7 @@ static_library("serial") { public_deps = [ ":serial_mojo", "//base", + "//device/core", ] deps = [ "//mojo/public/cpp/system", diff --git a/device/serial/serial.gyp b/device/serial/serial.gyp index de18133..0e56df1 100644 --- a/device/serial/serial.gyp +++ b/device/serial/serial.gyp @@ -50,6 +50,7 @@ '../../net/net.gyp:net', '../../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', '../../third_party/re2/re2.gyp:re2', + '../core/core.gyp:device_core', ], 'export_dependent_settings': [ 'device_serial_mojo', diff --git a/device/serial/serial_io_handler.cc b/device/serial/serial_io_handler.cc index 452f91c..1cfb1cd 100644 --- a/device/serial/serial_io_handler.cc +++ b/device/serial/serial_io_handler.cc @@ -44,6 +44,7 @@ void SerialIoHandler::Open(const std::string& port, DCHECK(file_thread_task_runner_.get()); DCHECK(ui_thread_task_runner_.get()); MergeConnectionOptions(options); + port_ = port; #if defined(OS_CHROMEOS) chromeos::PermissionBrokerClient* client = diff --git a/device/serial/serial_io_handler.h b/device/serial/serial_io_handler.h index 81d7028..63e6c90 100644 --- a/device/serial/serial_io_handler.h +++ b/device/serial/serial_io_handler.h @@ -190,6 +190,16 @@ class SerialIoHandler : public base::NonThreadSafe, // Possibly fixes up a serial port path name in a platform-specific manner. static std::string MaybeFixUpPortName(const std::string& port_name); + base::SingleThreadTaskRunner* file_thread_task_runner() const { + return file_thread_task_runner_.get(); + } + + base::SingleThreadTaskRunner* ui_thread_task_runner() const { + return ui_thread_task_runner_.get(); + } + + const std::string& port() const { return port_; } + private: friend class base::RefCounted<SerialIoHandler>; @@ -229,6 +239,8 @@ class SerialIoHandler : public base::NonThreadSafe, // On Chrome OS, PermissionBrokerClient should be called on the UI thread. scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_; + std::string port_; + DISALLOW_COPY_AND_ASSIGN(SerialIoHandler); }; diff --git a/device/serial/serial_io_handler_win.cc b/device/serial/serial_io_handler_win.cc index 56fe93b..2a1e752 100644 --- a/device/serial/serial_io_handler_win.cc +++ b/device/serial/serial_io_handler_win.cc @@ -2,9 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "device/serial/serial_io_handler_win.h" + #include <windows.h> +#include <setupapi.h> -#include "device/serial/serial_io_handler_win.h" +#include "base/bind.h" +#include "base/scoped_observer.h" +#include "base/threading/thread_checker.h" +#include "device/core/device_info_query_win.h" +#include "device/core/device_monitor_win.h" +#include "third_party/re2/re2/re2.h" namespace device { @@ -130,6 +138,12 @@ serial::StopBits StopBitsConstantToEnum(int stop_bits) { } } +// Searches for the COM port in the device's friendly name, assigns its value to +// com_port, and returns whether the operation was successful. +bool GetCOMPort(const std::string friendly_name, std::string* com_port) { + return RE2::PartialMatch(friendly_name, ".* \\((COM[0-9]+)\\)", com_port); +} + } // namespace // static @@ -139,6 +153,81 @@ scoped_refptr<SerialIoHandler> SerialIoHandler::Create( return new SerialIoHandlerWin(file_thread_task_runner, ui_thread_task_runner); } +class SerialIoHandlerWin::UiThreadHelper : public DeviceMonitorWin::Observer { + public: + UiThreadHelper( + base::WeakPtr<SerialIoHandlerWin> io_handler, + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) + : device_observer_(this), + io_handler_(io_handler), + io_thread_task_runner_(io_thread_task_runner) {} + + ~UiThreadHelper() { DCHECK(thread_checker_.CalledOnValidThread()); } + + static void Start(UiThreadHelper* self) { + self->thread_checker_.DetachFromThread(); + DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces(); + if (device_monitor) + self->device_observer_.Add(device_monitor); + } + + private: + // DeviceMonitorWin::Observer + void OnDeviceRemoved(const GUID& class_guid, + const std::string& device_path) override { + DCHECK(thread_checker_.CalledOnValidThread()); + io_thread_task_runner_->PostTask( + FROM_HERE, base::Bind(&SerialIoHandlerWin::OnDeviceRemoved, io_handler_, + device_path)); + } + + base::ThreadChecker thread_checker_; + ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_; + + // This weak pointer is only valid when checked on this task runner. + base::WeakPtr<SerialIoHandlerWin> io_handler_; + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(UiThreadHelper); +}; + +void SerialIoHandlerWin::OnDeviceRemoved(const std::string& device_path) { + DCHECK(CalledOnValidThread()); + + DeviceInfoQueryWin device_info_query; + if (!device_info_query.device_info_list_valid()) { + DVPLOG(1) << "Failed to create a device information set"; + return; + } + + // This will add the device so we can query driver info. + if (!device_info_query.AddDevice(device_path.c_str())) { + DVPLOG(1) << "Failed to get device interface data for " << device_path; + return; + } + + if (!device_info_query.GetDeviceInfo()) { + DVPLOG(1) << "Failed to get device info for " << device_path; + return; + } + + std::string friendly_name; + if (!device_info_query.GetDeviceStringProperty(SPDRP_FRIENDLYNAME, + &friendly_name)) { + DVPLOG(1) << "Failed to get device service property"; + return; + } + + std::string com_port; + if (!GetCOMPort(friendly_name, &com_port)) { + DVPLOG(1) << "Failed to get port name from \"" << friendly_name << "\"."; + return; + } + + if (port() == com_port) + CancelRead(serial::RECEIVE_ERROR_DISCONNECTED); +} + bool SerialIoHandlerWin::PostOpen() { DCHECK(!comm_context_); DCHECK(!read_context_); @@ -159,6 +248,13 @@ bool SerialIoHandlerWin::PostOpen() { write_context_->handler = this; memset(&write_context_->overlapped, 0, sizeof(write_context_->overlapped)); + scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner = + base::ThreadTaskRunnerHandle::Get(); + helper_ = + new UiThreadHelper(weak_factory_.GetWeakPtr(), io_thread_task_runner); + ui_thread_task_runner()->PostTask( + FROM_HERE, base::Bind(&UiThreadHelper::Start, helper_)); + // A ReadIntervalTimeout of MAXDWORD will cause async reads to complete // immediately with any data that's available, even if there is none. // This is OK because we never issue a read request until WaitCommEvent @@ -271,10 +367,11 @@ SerialIoHandlerWin::SerialIoHandlerWin( scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner) : SerialIoHandler(file_thread_task_runner, ui_thread_task_runner), event_mask_(0), - is_comm_pending_(false) { -} + is_comm_pending_(false), + weak_factory_(this) {} SerialIoHandlerWin::~SerialIoHandlerWin() { + ui_thread_task_runner()->DeleteSoon(FROM_HERE, helper_); } void SerialIoHandlerWin::OnIOCompleted( diff --git a/device/serial/serial_io_handler_win.h b/device/serial/serial_io_handler_win.h index 7f438b5..831eab6 100644 --- a/device/serial/serial_io_handler_win.h +++ b/device/serial/serial_io_handler_win.h @@ -32,6 +32,7 @@ class SerialIoHandlerWin : public SerialIoHandler, bool PostOpen() override; private: + class UiThreadHelper; friend class SerialIoHandler; explicit SerialIoHandlerWin( @@ -44,6 +45,8 @@ class SerialIoHandlerWin : public SerialIoHandler, DWORD bytes_transfered, DWORD error) override; + void OnDeviceRemoved(const std::string& device_path); + // Context used for asynchronous WaitCommEvent calls. scoped_ptr<base::MessageLoopForIO::IOContext> comm_context_; @@ -61,6 +64,11 @@ class SerialIoHandlerWin : public SerialIoHandler, // after a corresponding WaitCommEvent has completed. bool is_comm_pending_; + // The helper lives on the UI thread and holds a weak reference back to the + // handler that owns it. + UiThreadHelper* helper_ = nullptr; + base::WeakPtrFactory<SerialIoHandlerWin> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(SerialIoHandlerWin); }; diff --git a/device/usb/usb.gyp b/device/usb/usb.gyp index c7bf776..453ba1a 100644 --- a/device/usb/usb.gyp +++ b/device/usb/usb.gyp @@ -14,6 +14,7 @@ '../../components/components.gyp:device_event_log_component', '../../net/net.gyp:net', '../../third_party/libusb/libusb.gyp:libusb', + '../core/core.gyp:device_core', ], 'include_dirs': [ '../..', diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc index dd5cc90..9770007 100644 --- a/device/usb/usb_service_impl.cc +++ b/device/usb/usb_service_impl.cc @@ -27,6 +27,7 @@ #include <usbiodef.h> #include "base/strings/string_util.h" +#include "device/core/device_info_query_win.h" #endif // OS_WIN #if defined(USE_UDEV) @@ -53,96 +54,33 @@ const int kControlTransferTimeout = 60000; // 1 minute #if defined(OS_WIN) -// Wrapper around a HDEVINFO that automatically destroys it. -class ScopedDeviceInfoList { - public: - explicit ScopedDeviceInfoList(HDEVINFO handle) : handle_(handle) {} - - ~ScopedDeviceInfoList() { - if (valid()) { - SetupDiDestroyDeviceInfoList(handle_); - } - } - - bool valid() { return handle_ != INVALID_HANDLE_VALUE; } - - HDEVINFO get() { return handle_; } - - private: - HDEVINFO handle_; - - DISALLOW_COPY_AND_ASSIGN(ScopedDeviceInfoList); -}; - -// Wrapper around an SP_DEVINFO_DATA that initializes it properly and -// automatically deletes it. -class ScopedDeviceInfo { - public: - ScopedDeviceInfo() { - memset(&dev_info_data_, 0, sizeof(dev_info_data_)); - dev_info_data_.cbSize = sizeof(dev_info_data_); - } - - ~ScopedDeviceInfo() { - if (dev_info_set_ != INVALID_HANDLE_VALUE) { - SetupDiDeleteDeviceInfo(dev_info_set_, &dev_info_data_); - } - } - - // Once the SP_DEVINFO_DATA has been populated it must be freed using the - // HDEVINFO it was created from. - void set_valid(HDEVINFO dev_info_set) { - DCHECK(dev_info_set_ == INVALID_HANDLE_VALUE); - DCHECK(dev_info_set != INVALID_HANDLE_VALUE); - dev_info_set_ = dev_info_set; - } - - PSP_DEVINFO_DATA get() { return &dev_info_data_; } - - private: - HDEVINFO dev_info_set_ = INVALID_HANDLE_VALUE; - SP_DEVINFO_DATA dev_info_data_; -}; - bool IsWinUsbInterface(const std::string& device_path) { - ScopedDeviceInfoList dev_info_list(SetupDiCreateDeviceInfoList(NULL, NULL)); - if (!dev_info_list.valid()) { + DeviceInfoQueryWin device_info_query; + if (!device_info_query.device_info_list_valid()) { USB_PLOG(ERROR) << "Failed to create a device information set"; return false; } - // This will add the device to |dev_info_list| so we can query driver info. - if (!SetupDiOpenDeviceInterfaceA(dev_info_list.get(), device_path.c_str(), 0, - NULL)) { + // This will add the device so we can query driver info. + if (!device_info_query.AddDevice(device_path.c_str())) { USB_PLOG(ERROR) << "Failed to get device interface data for " << device_path; return false; } - ScopedDeviceInfo dev_info; - if (!SetupDiEnumDeviceInfo(dev_info_list.get(), 0, dev_info.get())) { + if (!device_info_query.GetDeviceInfo()) { USB_PLOG(ERROR) << "Failed to get device info for " << device_path; return false; } - dev_info.set_valid(dev_info_list.get()); - DWORD reg_data_type; - BYTE buffer[256]; - if (!SetupDiGetDeviceRegistryPropertyA(dev_info_list.get(), dev_info.get(), - SPDRP_SERVICE, ®_data_type, - &buffer[0], sizeof buffer, NULL)) { + std::string buffer; + if (!device_info_query.GetDeviceStringProperty(SPDRP_SERVICE, &buffer)) { USB_PLOG(ERROR) << "Failed to get device service property"; return false; } - if (reg_data_type != REG_SZ) { - USB_LOG(ERROR) << "Unexpected data type for driver service: " - << reg_data_type; - return false; - } USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << "."; - if (base::StartsWith(reinterpret_cast<const char*>(buffer), "WinUSB", - base::CompareCase::INSENSITIVE_ASCII)) + if (base::StartsWith(buffer, "WinUSB", base::CompareCase::INSENSITIVE_ASCII)) return true; return false; } |