Commit d9ba49e1 authored by Reilly Grant's avatar Reilly Grant Committed by Commit Bot

[serial] Add monitor for device add/remove events on Windows

This change removes the old serial enumeration code on Windows and
always uses the new enumeration path while listening to window messages
to discover when ports are added and removed from the system.

This will allow us to keep the UI up-to-date in real time when the user
plugs in a device and deliver connection events to web apps.

Bug: 981483
Change-Id: I4126e370b02973458b5c2aac6a230244248b2320
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2099238
Commit-Queue: Reilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarRobert Liao <robliao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#751217}
parent 3f161ac2
...@@ -93,6 +93,7 @@ CHROME_DECLARE_HANDLE(HWND); ...@@ -93,6 +93,7 @@ CHROME_DECLARE_HANDLE(HWND);
typedef LPVOID HINTERNET; typedef LPVOID HINTERNET;
typedef HINSTANCE HMODULE; typedef HINSTANCE HMODULE;
typedef PVOID LSA_HANDLE; typedef PVOID LSA_HANDLE;
typedef PVOID HDEVINFO;
// Forward declare some Windows struct/typedef sets. // Forward declare some Windows struct/typedef sets.
...@@ -114,6 +115,8 @@ typedef struct tagMENUITEMINFOW MENUITEMINFOW, MENUITEMINFO; ...@@ -114,6 +115,8 @@ typedef struct tagMENUITEMINFOW MENUITEMINFOW, MENUITEMINFO;
typedef struct tagNMHDR NMHDR; typedef struct tagNMHDR NMHDR;
typedef struct _SP_DEVINFO_DATA SP_DEVINFO_DATA;
typedef PVOID PSID; typedef PVOID PSID;
// Declare Chrome versions of some Windows structures. These are needed for // Declare Chrome versions of some Windows structures. These are needed for
......
...@@ -7,9 +7,32 @@ ...@@ -7,9 +7,32 @@
#include <utility> #include <utility>
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "build/build_config.h"
#if defined(OS_LINUX)
#include "services/device/serial/serial_device_enumerator_linux.h"
#elif defined(OS_MACOSX)
#include "services/device/serial/serial_device_enumerator_mac.h"
#elif defined(OS_WIN)
#include "services/device/serial/serial_device_enumerator_win.h"
#endif
namespace device { namespace device {
// static
std::unique_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
#if defined(OS_LINUX)
return std::make_unique<SerialDeviceEnumeratorLinux>();
#elif defined(OS_MACOSX)
return std::make_unique<SerialDeviceEnumeratorMac>();
#elif defined(OS_WIN)
return std::make_unique<SerialDeviceEnumeratorWin>(std::move(ui_task_runner));
#else
#error "No implementation of SerialDeviceEnumerator on this platform."
#endif
}
SerialDeviceEnumerator::SerialDeviceEnumerator() = default; SerialDeviceEnumerator::SerialDeviceEnumerator() = default;
SerialDeviceEnumerator::~SerialDeviceEnumerator() = default; SerialDeviceEnumerator::~SerialDeviceEnumerator() = default;
......
...@@ -24,7 +24,8 @@ class SerialDeviceEnumerator { ...@@ -24,7 +24,8 @@ class SerialDeviceEnumerator {
public: public:
using TokenPathMap = std::map<base::UnguessableToken, base::FilePath>; using TokenPathMap = std::map<base::UnguessableToken, base::FilePath>;
static std::unique_ptr<SerialDeviceEnumerator> Create(); static std::unique_ptr<SerialDeviceEnumerator> Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
SerialDeviceEnumerator(); SerialDeviceEnumerator();
virtual ~SerialDeviceEnumerator(); virtual ~SerialDeviceEnumerator();
......
...@@ -33,11 +33,6 @@ const char kRfcommMajor[] = "216"; ...@@ -33,11 +33,6 @@ const char kRfcommMajor[] = "216";
} // namespace } // namespace
// static
std::unique_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() {
return std::make_unique<SerialDeviceEnumeratorLinux>();
}
SerialDeviceEnumeratorLinux::SerialDeviceEnumeratorLinux() { SerialDeviceEnumeratorLinux::SerialDeviceEnumeratorLinux() {
DETACH_FROM_SEQUENCE(sequence_checker_); DETACH_FROM_SEQUENCE(sequence_checker_);
......
...@@ -104,11 +104,6 @@ bool GetUInt16Property(io_service_t service, ...@@ -104,11 +104,6 @@ bool GetUInt16Property(io_service_t service,
} // namespace } // namespace
// static
std::unique_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() {
return std::make_unique<SerialDeviceEnumeratorMac>();
}
SerialDeviceEnumeratorMac::SerialDeviceEnumeratorMac() { SerialDeviceEnumeratorMac::SerialDeviceEnumeratorMac() {
notify_port_.reset(IONotificationPortCreate(kIOMasterPortDefault)); notify_port_.reset(IONotificationPortCreate(kIOMasterPortDefault));
CFRunLoopAddSource(CFRunLoopGetMain(), CFRunLoopAddSource(CFRunLoopGetMain(),
......
...@@ -19,7 +19,7 @@ class SerialDeviceEnumeratorTest : public testing::Test { ...@@ -19,7 +19,7 @@ class SerialDeviceEnumeratorTest : public testing::Test {
: task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {} : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {}
~SerialDeviceEnumeratorTest() override = default; ~SerialDeviceEnumeratorTest() override = default;
private: protected:
base::test::TaskEnvironment task_environment_; base::test::TaskEnvironment task_environment_;
}; };
...@@ -27,7 +27,8 @@ TEST_F(SerialDeviceEnumeratorTest, GetDevices) { ...@@ -27,7 +27,8 @@ TEST_F(SerialDeviceEnumeratorTest, GetDevices) {
// There is no guarantee that a test machine will have a serial device // There is no guarantee that a test machine will have a serial device
// available. The purpose of this test is to ensure that the process of // available. The purpose of this test is to ensure that the process of
// attempting to enumerate devices does not cause a crash. // attempting to enumerate devices does not cause a crash.
auto enumerator = SerialDeviceEnumerator::Create(); auto enumerator = SerialDeviceEnumerator::Create(
task_environment_.GetMainThreadTaskRunner());
ASSERT_TRUE(enumerator); ASSERT_TRUE(enumerator);
std::vector<mojom::SerialPortInfoPtr> devices = enumerator->GetDevices(); std::vector<mojom::SerialPortInfoPtr> devices = enumerator->GetDevices();
} }
......
...@@ -7,17 +7,19 @@ ...@@ -7,17 +7,19 @@
#include <windows.h> // Must be in front of other Windows header files. #include <windows.h> // Must be in front of other Windows header files.
#include <devguid.h> #include <devguid.h>
#include <ntddser.h>
#include <setupapi.h> #include <setupapi.h>
#include <stdint.h> #include <stdint.h>
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_set>
#include <utility> #include <utility>
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/numerics/ranges.h" #include "base/numerics/ranges.h"
#include "base/scoped_generic.h"
#include "base/sequence_checker.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
...@@ -30,29 +32,38 @@ namespace device { ...@@ -30,29 +32,38 @@ namespace device {
namespace { namespace {
struct DevInfoScopedTraits {
static HDEVINFO InvalidValue() { return INVALID_HANDLE_VALUE; }
static void Free(HDEVINFO h) { SetupDiDestroyDeviceInfoList(h); }
};
using ScopedDevInfo = base::ScopedGeneric<HDEVINFO, DevInfoScopedTraits>;
// Searches the specified device info for a property with the specified key, // Searches the specified device info for a property with the specified key,
// assigns the result to value, and returns whether the operation was // assigns the result to value, and returns whether the operation was
// successful. // successful.
bool GetProperty(HDEVINFO dev_info, bool GetProperty(HDEVINFO dev_info,
SP_DEVINFO_DATA dev_info_data, SP_DEVINFO_DATA* dev_info_data,
const int key, const int key,
std::string* value) { std::string* value) {
// We don't know how much space the property's value will take up, so we call // We don't know how much space the property's value will take up, so we call
// the property retrieval function once to fetch the size of the required // the property retrieval function once to fetch the size of the required
// value buffer, then again once we've allocated a sufficiently large buffer. // value buffer, then again once we've allocated a sufficiently large buffer.
DWORD buffer_size = 0; DWORD buffer_size = 0;
SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, key, nullptr, SetupDiGetDeviceRegistryProperty(dev_info, dev_info_data, key, nullptr,
nullptr, buffer_size, &buffer_size); nullptr, buffer_size, &buffer_size);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return false; return false;
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buffer_size]); base::string16 buffer;
if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, key, nullptr, if (!SetupDiGetDeviceRegistryProperty(
reinterpret_cast<PBYTE>(buffer.get()), dev_info, dev_info_data, key, nullptr,
buffer_size, nullptr)) reinterpret_cast<PBYTE>(base::WriteInto(&buffer, buffer_size)),
buffer_size, nullptr)) {
return false; return false;
}
*value = base::WideToUTF8(buffer.get()); *value = base::UTF16ToUTF8(buffer);
return true; return true;
} }
...@@ -92,40 +103,71 @@ bool GetProductID(const std::string hardware_id, uint32_t* product_id) { ...@@ -92,40 +103,71 @@ bool GetProductID(const std::string hardware_id, uint32_t* product_id) {
} // namespace } // namespace
// static class SerialDeviceEnumeratorWin::UiThreadHelper
std::unique_ptr<SerialDeviceEnumerator> SerialDeviceEnumerator::Create() { : public DeviceMonitorWin::Observer {
return std::make_unique<SerialDeviceEnumeratorWin>(); public:
} UiThreadHelper() : task_runner_(base::SequencedTaskRunnerHandle::Get()) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
SerialDeviceEnumeratorWin::SerialDeviceEnumeratorWin() {} // Disallow copy and assignment.
UiThreadHelper(UiThreadHelper&) = delete;
UiThreadHelper& operator=(UiThreadHelper&) = delete;
SerialDeviceEnumeratorWin::~SerialDeviceEnumeratorWin() {} virtual ~UiThreadHelper() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
std::vector<mojom::SerialPortInfoPtr> SerialDeviceEnumeratorWin::GetDevices() { void Initialize(base::WeakPtr<SerialDeviceEnumeratorWin> enumerator) {
std::vector<mojom::SerialPortInfoPtr> devices = GetDevicesNew(); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<mojom::SerialPortInfoPtr> old_devices = GetDevicesOld(); enumerator_ = std::move(enumerator);
device_observer_.Add(
base::UmaHistogramSparse( DeviceMonitorWin::GetForDeviceInterface(GUID_DEVINTERFACE_COMPORT));
"Hardware.Serial.NewMinusOldDeviceListSize",
base::ClampToRange<int>(devices.size() - old_devices.size(), -10, 10));
// Add devices found from both the new and old methods of enumeration. If a
// device is found using both the new and the old enumeration method, then we
// take the device from the new enumeration method because it's able to
// collect more information. We do this by inserting the new devices first,
// because insertions are ignored if the key already exists.
std::unordered_set<base::FilePath> devices_seen;
for (const auto& device : devices) {
bool inserted = devices_seen.insert(device->path).second;
DCHECK(inserted);
} }
for (auto& device : old_devices) {
if (devices_seen.insert(device->path).second) void OnDeviceAdded(const GUID& class_guid,
devices.push_back(std::move(device)); const base::string16& device_path) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&SerialDeviceEnumeratorWin::OnPathAdded,
enumerator_, device_path));
}
void OnDeviceRemoved(const GUID& class_guid,
const base::string16& device_path) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
task_runner_->PostTask(
FROM_HERE, base::BindOnce(&SerialDeviceEnumeratorWin::OnPathRemoved,
enumerator_, device_path));
} }
return devices;
private:
SEQUENCE_CHECKER(sequence_checker_);
// Weak reference to the SerialDeviceEnumeratorWin that owns this object.
// Calls on |enumerator_| must be posted to |task_runner_|.
base::WeakPtr<SerialDeviceEnumeratorWin> enumerator_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
ScopedObserver<DeviceMonitorWin, DeviceMonitorWin::Observer> device_observer_{
this};
};
SerialDeviceEnumeratorWin::SerialDeviceEnumeratorWin(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
: helper_(new UiThreadHelper(), base::OnTaskRunnerDeleter(ui_task_runner)) {
// Passing a raw pointer to |helper_| is safe here because this task will
// reach the UI thread before any task to delete |helper_|.
ui_task_runner->PostTask(FROM_HERE,
base::BindOnce(&UiThreadHelper::Initialize,
base::Unretained(helper_.get()),
weak_factory_.GetWeakPtr()));
DoInitialEnumeration();
} }
SerialDeviceEnumeratorWin::~SerialDeviceEnumeratorWin() = default;
// static // static
base::Optional<base::FilePath> SerialDeviceEnumeratorWin::GetPath( base::Optional<base::FilePath> SerialDeviceEnumeratorWin::GetPath(
const std::string& friendly_name) { const std::string& friendly_name) {
...@@ -136,83 +178,135 @@ base::Optional<base::FilePath> SerialDeviceEnumeratorWin::GetPath( ...@@ -136,83 +178,135 @@ base::Optional<base::FilePath> SerialDeviceEnumeratorWin::GetPath(
return FixUpPortName(com_port); return FixUpPortName(com_port);
} }
// Returns an array of devices as retrieved through the new method of std::vector<mojom::SerialPortInfoPtr> SerialDeviceEnumeratorWin::GetDevices() {
// enumerating serial devices (SetupDi). This new method gives more information std::vector<mojom::SerialPortInfoPtr> ports;
// about the devices than the old method. ports.reserve(ports_.size());
std::vector<mojom::SerialPortInfoPtr> for (const auto& map_entry : ports_)
SerialDeviceEnumeratorWin::GetDevicesNew() { ports.push_back(map_entry.second->Clone());
std::vector<mojom::SerialPortInfoPtr> devices; return ports;
}
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::Optional<base::FilePath> SerialDeviceEnumeratorWin::GetPathFromToken(
base::BlockingType::MAY_BLOCK); const base::UnguessableToken& token) {
// Make a device interface query to find all serial devices. auto it = ports_.find(token);
HDEVINFO dev_info = if (it == ports_.end())
SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0, 0, DIGCF_PRESENT); return base::nullopt;
if (dev_info == INVALID_HANDLE_VALUE) return it->second->path;
return devices; }
SP_DEVINFO_DATA dev_info_data;
dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
for (DWORD i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
std::string friendly_name;
// SPDRP_FRIENDLYNAME looks like "USB_SERIAL_PORT (COM3)".
// In Windows, the COM port is the path used to uniquely identify the
// serial device. If the COM can't be found, ignore the device.
if (!GetProperty(dev_info, dev_info_data, SPDRP_FRIENDLYNAME,
&friendly_name)) {
continue;
}
base::Optional<base::FilePath> path = GetPath(friendly_name); void SerialDeviceEnumeratorWin::OnPathAdded(const base::string16& device_path) {
if (!path) ScopedDevInfo dev_info(SetupDiCreateDeviceInfoList(nullptr, nullptr));
continue; if (!dev_info.is_valid())
return;
auto info = mojom::SerialPortInfo::New();
info->path = *path; if (!SetupDiOpenDeviceInterface(dev_info.get(), device_path.c_str(), 0,
info->token = GetTokenFromPath(info->path); nullptr)) {
return;
std::string display_name; }
if (GetDisplayName(friendly_name, &display_name))
info->display_name = std::move(display_name); SP_DEVINFO_DATA dev_info_data = {};
dev_info_data.cbSize = sizeof(dev_info_data);
std::string hardware_id; if (!SetupDiEnumDeviceInfo(dev_info.get(), 0, &dev_info_data))
// SPDRP_HARDWAREID looks like "FTDIBUS\COMPORT&VID_0403&PID_6001". return;
if (GetProperty(dev_info, dev_info_data, SPDRP_HARDWAREID, &hardware_id)) {
uint32_t vendor_id, product_id; EnumeratePort(dev_info.get(), &dev_info_data);
if (GetVendorID(hardware_id, &vendor_id)) { }
info->has_vendor_id = true;
info->vendor_id = vendor_id; void SerialDeviceEnumeratorWin::OnPathRemoved(
} const base::string16& device_path) {
if (GetProductID(hardware_id, &product_id)) { ScopedDevInfo dev_info(SetupDiCreateDeviceInfoList(nullptr, nullptr));
info->has_product_id = true; if (!dev_info.is_valid())
info->product_id = product_id; return;
}
}
devices.push_back(std::move(info)); if (!SetupDiOpenDeviceInterface(dev_info.get(), device_path.c_str(), 0,
nullptr)) {
return;
} }
SetupDiDestroyDeviceInfoList(dev_info); SP_DEVINFO_DATA dev_info_data = {};
return devices; dev_info_data.cbSize = sizeof(dev_info_data);
if (!SetupDiEnumDeviceInfo(dev_info.get(), 0, &dev_info_data))
return;
std::string friendly_name;
// SPDRP_FRIENDLYNAME looks like "USB_SERIAL_PORT (COM3)".
// In Windows, the COM port is the path used to uniquely identify the
// serial device. If the COM can't be found, ignore the device.
if (!GetProperty(dev_info.get(), &dev_info_data, SPDRP_FRIENDLYNAME,
&friendly_name)) {
return;
}
base::Optional<base::FilePath> path = GetPath(friendly_name);
if (!path)
return;
auto it = paths_.find(*path);
if (it == paths_.end())
return;
ports_.erase(it->second);
paths_.erase(it);
} }
// Returns an array of devices as retrieved through the old method of void SerialDeviceEnumeratorWin::DoInitialEnumeration() {
// enumerating serial devices (searching the registry). This old method gives
// less information about the devices than the new method.
std::vector<mojom::SerialPortInfoPtr>
SerialDeviceEnumeratorWin::GetDevicesOld() {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK); base::BlockingType::MAY_BLOCK);
base::win::RegistryValueIterator iter_key( // Make a device interface query to find all serial devices.
HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM\\"); ScopedDevInfo dev_info(
std::vector<mojom::SerialPortInfoPtr> devices; SetupDiGetClassDevs(&GUID_DEVINTERFACE_COMPORT, nullptr, 0,
for (; iter_key.Valid(); ++iter_key) { DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
auto info = mojom::SerialPortInfo::New(); if (!dev_info.is_valid())
info->path = FixUpPortName(base::UTF16ToASCII(iter_key.Value())); return;
info->token = GetTokenFromPath(info->path);
devices.push_back(std::move(info)); SP_DEVINFO_DATA dev_info_data = {};
dev_info_data.cbSize = sizeof(dev_info_data);
for (DWORD i = 0; SetupDiEnumDeviceInfo(dev_info.get(), i, &dev_info_data);
i++) {
EnumeratePort(dev_info.get(), &dev_info_data);
}
}
void SerialDeviceEnumeratorWin::EnumeratePort(HDEVINFO dev_info,
SP_DEVINFO_DATA* dev_info_data) {
std::string friendly_name;
// SPDRP_FRIENDLYNAME looks like "USB_SERIAL_PORT (COM3)".
// In Windows, the COM port is the path used to uniquely identify the
// serial device. If the COM can't be found, ignore the device.
if (!GetProperty(dev_info, dev_info_data, SPDRP_FRIENDLYNAME,
&friendly_name)) {
return;
} }
return devices;
base::Optional<base::FilePath> path = GetPath(friendly_name);
if (!path)
return;
auto info = mojom::SerialPortInfo::New();
info->path = *path;
base::UnguessableToken token = base::UnguessableToken::Create();
info->token = token;
std::string display_name;
if (GetDisplayName(friendly_name, &display_name))
info->display_name = std::move(display_name);
std::string hardware_id;
// SPDRP_HARDWAREID looks like "FTDIBUS\COMPORT&VID_0403&PID_6001".
if (GetProperty(dev_info, dev_info_data, SPDRP_HARDWAREID, &hardware_id)) {
uint32_t vendor_id, product_id;
if (GetVendorID(hardware_id, &vendor_id)) {
info->has_vendor_id = true;
info->vendor_id = vendor_id;
}
if (GetProductID(hardware_id, &product_id)) {
info->has_product_id = true;
info->product_id = product_id;
}
}
ports_[token] = std::move(info);
paths_.insert(std::make_pair(*path, token));
} }
} // namespace device } // namespace device
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
#ifndef SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_WIN_H_ #ifndef SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_WIN_H_
#define SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_WIN_H_ #define SERVICES_DEVICE_SERIAL_SERIAL_DEVICE_ENUMERATOR_WIN_H_
#include <vector>
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "base/scoped_observer.h"
#include "base/win/windows_types.h"
#include "device/base/device_monitor_win.h"
#include "services/device/serial/serial_device_enumerator.h" #include "services/device/serial/serial_device_enumerator.h"
namespace device { namespace device {
...@@ -16,21 +16,35 @@ namespace device { ...@@ -16,21 +16,35 @@ namespace device {
// Discovers and enumerates serial devices available to the host. // Discovers and enumerates serial devices available to the host.
class SerialDeviceEnumeratorWin : public SerialDeviceEnumerator { class SerialDeviceEnumeratorWin : public SerialDeviceEnumerator {
public: public:
SerialDeviceEnumeratorWin(); SerialDeviceEnumeratorWin(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
~SerialDeviceEnumeratorWin() override; ~SerialDeviceEnumeratorWin() override;
// Implementation for SerialDeviceEnumerator.
std::vector<mojom::SerialPortInfoPtr> GetDevices() override;
// Searches for the COM port in the device's friendly name and returns the // Searches for the COM port in the device's friendly name and returns the
// appropriate device path or nullopt if the input did not contain a valid // appropriate device path or nullopt if the input did not contain a valid
// name. // name.
static base::Optional<base::FilePath> GetPath( static base::Optional<base::FilePath> GetPath(
const std::string& friendly_name); const std::string& friendly_name);
// SerialDeviceEnumerator
std::vector<mojom::SerialPortInfoPtr> GetDevices() override;
base::Optional<base::FilePath> GetPathFromToken(
const base::UnguessableToken& token) override;
void OnPathAdded(const base::string16& device_path);
void OnPathRemoved(const base::string16& device_path);
private: private:
std::vector<mojom::SerialPortInfoPtr> GetDevicesNew(); class UiThreadHelper;
std::vector<mojom::SerialPortInfoPtr> GetDevicesOld();
void DoInitialEnumeration();
void EnumeratePort(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data);
std::map<base::UnguessableToken, mojom::SerialPortInfoPtr> ports_;
std::map<base::FilePath, base::UnguessableToken> paths_;
std::unique_ptr<UiThreadHelper, base::OnTaskRunnerDeleter> helper_;
base::WeakPtrFactory<SerialDeviceEnumeratorWin> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(SerialDeviceEnumeratorWin); DISALLOW_COPY_AND_ASSIGN(SerialDeviceEnumeratorWin);
}; };
......
...@@ -36,7 +36,7 @@ void SerialPortManagerImpl::SetSerialEnumeratorForTesting( ...@@ -36,7 +36,7 @@ void SerialPortManagerImpl::SetSerialEnumeratorForTesting(
void SerialPortManagerImpl::GetDevices(GetDevicesCallback callback) { void SerialPortManagerImpl::GetDevices(GetDevicesCallback callback) {
if (!enumerator_) if (!enumerator_)
enumerator_ = SerialDeviceEnumerator::Create(); enumerator_ = SerialDeviceEnumerator::Create(ui_task_runner_);
std::move(callback).Run(enumerator_->GetDevices()); std::move(callback).Run(enumerator_->GetDevices());
} }
...@@ -45,7 +45,7 @@ void SerialPortManagerImpl::GetPort( ...@@ -45,7 +45,7 @@ void SerialPortManagerImpl::GetPort(
mojo::PendingReceiver<mojom::SerialPort> receiver, mojo::PendingReceiver<mojom::SerialPort> receiver,
mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher) { mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher) {
if (!enumerator_) if (!enumerator_)
enumerator_ = SerialDeviceEnumerator::Create(); enumerator_ = SerialDeviceEnumerator::Create(ui_task_runner_);
base::Optional<base::FilePath> path = enumerator_->GetPathFromToken(token); base::Optional<base::FilePath> path = enumerator_->GetPathFromToken(token);
if (path) { if (path) {
io_task_runner_->PostTask( io_task_runner_->PostTask(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment