Index: device/serial/serial_io_handler_win.cc |
diff --git a/device/serial/serial_io_handler_win.cc b/device/serial/serial_io_handler_win.cc |
index 56fe93bbbf527589e0859171ce2627c3d5dffb61..2a1e752c9f7d7444be2e44ce84c86def4e9ba6b6 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( |