Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Unified Diff: device/serial/serial_io_handler_win.cc

Issue 1439443002: Reland: Add code to deal with serial device disconnection detection on Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: added setupapi.lib to device/core/BUILD.gn Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « device/serial/serial_io_handler_win.h ('k') | device/usb/usb.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(
« no previous file with comments | « device/serial/serial_io_handler_win.h ('k') | device/usb/usb.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698