123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- // Copyright 2017 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 "services/device/usb/usb_service_win.h"
- // windows.h must be included first.
- #include <windows.h>
- #define INITGUID
- #include <devpkey.h>
- #include <objbase.h>
- #include <setupapi.h>
- #include <stdint.h>
- #include <usbiodef.h>
- #include "base/bind.h"
- #include "base/containers/contains.h"
- #include "base/location.h"
- #include "base/memory/free_deleter.h"
- #include "base/memory/ptr_util.h"
- #include "base/scoped_generic.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_piece_forward.h"
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "base/strings/sys_string_conversions.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/threading/scoped_blocking_call.h"
- #include "base/threading/scoped_thread_priority.h"
- #include "base/threading/sequenced_task_runner_handle.h"
- #include "base/win/registry.h"
- #include "base/win/scoped_devinfo.h"
- #include "base/win/scoped_handle.h"
- #include "base/win/win_util.h"
- #include "components/device_event_log/device_event_log.h"
- #include "services/device/usb/usb_descriptors.h"
- #include "services/device/usb/usb_device_handle.h"
- #include "services/device/usb/webusb_descriptors.h"
- #include "third_party/re2/src/re2/re2.h"
- namespace device {
- namespace {
- bool IsCompositeDevice(const std::wstring& service_name) {
- // Windows built-in composite device driver
- return base::EqualsCaseInsensitiveASCII(service_name, L"usbccgp") ||
- // Samsung Mobile USB Composite device driver
- base::EqualsCaseInsensitiveASCII(service_name, L"dg_ssudbus");
- }
- std::ostream& operator<<(std::ostream& os, const DEVPROPKEY& value) {
- os << "{" << base::win::WStringFromGUID(value.fmtid) << ", " << value.pid
- << "}";
- return os;
- }
- absl::optional<uint32_t> GetDeviceUint32Property(HDEVINFO dev_info,
- SP_DEVINFO_DATA* dev_info_data,
- const DEVPROPKEY& property) {
- // SetupDiGetDeviceProperty() makes an RPC which may block.
- base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
- base::BlockingType::MAY_BLOCK);
- DEVPROPTYPE property_type;
- uint32_t buffer;
- if (!SetupDiGetDeviceProperty(
- dev_info, dev_info_data, &property, &property_type,
- reinterpret_cast<PBYTE>(&buffer), sizeof(buffer), nullptr, 0)) {
- USB_PLOG(ERROR) << "SetupDiGetDeviceProperty(" << property << ") failed";
- return absl::nullopt;
- }
- if (property_type != DEVPROP_TYPE_UINT32) {
- USB_LOG(ERROR) << "SetupDiGetDeviceProperty(" << property
- << ") returned unexpected type (" << property_type
- << " != " << DEVPROP_TYPE_UINT32 << ")";
- return absl::nullopt;
- }
- return buffer;
- }
- absl::optional<std::wstring> GetDeviceStringProperty(
- HDEVINFO dev_info,
- SP_DEVINFO_DATA* dev_info_data,
- const DEVPROPKEY& property) {
- // SetupDiGetDeviceProperty() makes an RPC which may block.
- base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
- base::BlockingType::MAY_BLOCK);
- DEVPROPTYPE property_type;
- DWORD required_size;
- if (SetupDiGetDeviceProperty(dev_info, dev_info_data, &property,
- &property_type, nullptr, 0, &required_size, 0)) {
- USB_LOG(ERROR) << "SetupDiGetDeviceProperty(" << property
- << ") unexpectedly succeeded";
- return absl::nullopt;
- }
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- USB_PLOG(ERROR) << "SetupDiGetDeviceProperty(" << property << ") failed";
- return absl::nullopt;
- }
- if (property_type != DEVPROP_TYPE_STRING) {
- USB_LOG(ERROR) << "SetupDiGetDeviceProperty(" << property
- << ") returned unexpected type (" << property_type
- << " != " << DEVPROP_TYPE_STRING << ")";
- return absl::nullopt;
- }
- std::wstring buffer;
- if (!SetupDiGetDeviceProperty(
- dev_info, dev_info_data, &property, &property_type,
- reinterpret_cast<PBYTE>(base::WriteInto(&buffer, required_size)),
- required_size, nullptr, 0)) {
- USB_PLOG(ERROR) << "SetupDiGetDeviceProperty(" << property << ") failed";
- return absl::nullopt;
- }
- return buffer;
- }
- absl::optional<std::vector<std::wstring>> GetDeviceStringListProperty(
- HDEVINFO dev_info,
- SP_DEVINFO_DATA* dev_info_data,
- const DEVPROPKEY& property) {
- // SetupDiGetDeviceProperty() makes an RPC which may block.
- base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
- base::BlockingType::MAY_BLOCK);
- DEVPROPTYPE property_type;
- DWORD required_size;
- if (SetupDiGetDeviceProperty(dev_info, dev_info_data, &property,
- &property_type, nullptr, 0, &required_size, 0)) {
- USB_LOG(ERROR) << "SetupDiGetDeviceProperty(" << property
- << ") unexpectedly succeeded";
- return absl::nullopt;
- }
- if (GetLastError() == ERROR_NOT_FOUND) {
- // Simplify callers by returning empty list when the property isn't found.
- return std::vector<std::wstring>();
- }
- if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- USB_PLOG(ERROR) << "SetupDiGetDeviceProperty(" << property << ") failed";
- return absl::nullopt;
- }
- if (property_type != DEVPROP_TYPE_STRING_LIST) {
- USB_LOG(ERROR) << "SetupDiGetDeviceProperty(" << property
- << ") returned unexpected type (" << property_type
- << " != " << DEVPROP_TYPE_STRING_LIST << ")";
- return absl::nullopt;
- }
- std::wstring buffer;
- if (!SetupDiGetDeviceProperty(
- dev_info, dev_info_data, &property, &property_type,
- reinterpret_cast<PBYTE>(base::WriteInto(&buffer, required_size)),
- required_size, nullptr, 0)) {
- USB_PLOG(ERROR) << "SetupDiGetDeviceProperty(" << property << ") failed";
- return absl::nullopt;
- }
- // Windows string list properties use a NUL character as the delimiter.
- return base::SplitString(buffer, base::WStringPiece(L"\0", 1),
- base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- }
- std::wstring GetServiceName(HDEVINFO dev_info, SP_DEVINFO_DATA* dev_info_data) {
- absl::optional<std::wstring> property =
- GetDeviceStringProperty(dev_info, dev_info_data, DEVPKEY_Device_Service);
- if (!property.has_value())
- return std::wstring();
- // Windows pads this string with a variable number of NUL bytes for no
- // discernible reason.
- return std::wstring(base::TrimString(*property, base::WStringPiece(L"\0", 1),
- base::TRIM_TRAILING));
- }
- bool GetDeviceInterfaceDetails(HDEVINFO dev_info,
- SP_DEVICE_INTERFACE_DATA* device_interface_data,
- std::wstring* device_path,
- uint32_t* bus_number,
- uint32_t* port_number,
- std::wstring* instance_id,
- std::wstring* parent_instance_id,
- std::vector<std::wstring>* child_instance_ids,
- std::vector<std::wstring>* hardware_ids,
- std::wstring* service_name) {
- SP_DEVINFO_DATA dev_info_data = {};
- dev_info_data.cbSize = sizeof(dev_info_data);
- DWORD required_size = 0;
- std::unique_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA, base::FreeDeleter>
- device_interface_detail_data;
- // Probing for the required size of the SP_DEVICE_INTERFACE_DETAIL_DATA
- // struct is only required if we are looking for the device path.
- // Otherwise all the necessary data can be queried from the SP_DEVINFO_DATA.
- if (device_path) {
- if (!SetupDiGetDeviceInterfaceDetail(dev_info, device_interface_data,
- /*DeviceInterfaceDetailData=*/nullptr,
- /*DeviceInterfaceDetailDataSize=*/0,
- &required_size,
- /*DeviceInfoData=*/nullptr) &&
- GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- return false;
- }
- device_interface_detail_data.reset(
- static_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(malloc(required_size)));
- device_interface_detail_data->cbSize =
- sizeof(*device_interface_detail_data);
- }
- if (!SetupDiGetDeviceInterfaceDetail(
- dev_info, device_interface_data, device_interface_detail_data.get(),
- required_size, /*RequiredSize=*/nullptr, &dev_info_data) &&
- (device_path || GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
- USB_PLOG(ERROR) << "SetupDiGetDeviceInterfaceDetail";
- return false;
- }
- if (device_path)
- *device_path = std::wstring(device_interface_detail_data->DevicePath);
- if (bus_number) {
- auto result = GetDeviceUint32Property(dev_info, &dev_info_data,
- DEVPKEY_Device_BusNumber);
- if (!result.has_value())
- return false;
- *bus_number = result.value();
- }
- if (port_number) {
- auto result = GetDeviceUint32Property(dev_info, &dev_info_data,
- DEVPKEY_Device_Address);
- if (!result.has_value())
- return false;
- *port_number = result.value();
- }
- if (instance_id) {
- auto result = GetDeviceStringProperty(dev_info, &dev_info_data,
- DEVPKEY_Device_InstanceId);
- if (!result.has_value())
- return false;
- *instance_id = std::move(result.value());
- }
- if (parent_instance_id) {
- auto result = GetDeviceStringProperty(dev_info, &dev_info_data,
- DEVPKEY_Device_Parent);
- if (!result.has_value())
- return false;
- *parent_instance_id = std::move(result.value());
- }
- if (child_instance_ids) {
- auto result = GetDeviceStringListProperty(dev_info, &dev_info_data,
- DEVPKEY_Device_Children);
- if (!result.has_value())
- return false;
- *child_instance_ids = std::move(result.value());
- }
- if (hardware_ids) {
- auto result = GetDeviceStringListProperty(dev_info, &dev_info_data,
- DEVPKEY_Device_HardwareIds);
- if (!result.has_value())
- return false;
- *hardware_ids = std::move(result.value());
- }
- if (service_name) {
- *service_name = GetServiceName(dev_info, &dev_info_data);
- if (service_name->empty()) {
- return false;
- }
- }
- return true;
- }
- std::wstring GetDevicePath(const std::wstring& instance_id,
- const GUID& device_interface_guid) {
- base::win::ScopedDevInfo dev_info(
- SetupDiGetClassDevs(&device_interface_guid, instance_id.c_str(), 0,
- DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
- if (!dev_info.is_valid()) {
- USB_PLOG(ERROR) << "SetupDiGetClassDevs";
- return std::wstring();
- }
- SP_DEVICE_INTERFACE_DATA device_interface_data = {};
- device_interface_data.cbSize = sizeof(device_interface_data);
- if (!SetupDiEnumDeviceInterfaces(dev_info.get(), nullptr,
- &device_interface_guid, 0,
- &device_interface_data)) {
- USB_PLOG(ERROR) << "SetupDiEnumDeviceInterfaces";
- return std::wstring();
- }
- std::wstring device_path;
- if (!GetDeviceInterfaceDetails(
- dev_info.get(), &device_interface_data, &device_path,
- /*bus_number=*/nullptr, /*port_number=*/nullptr,
- /*instance_id=*/nullptr, /*parent_instance_id=*/nullptr,
- /*child_instance_ids=*/nullptr, /*hardware_ids=*/nullptr,
- /*service_name=*/nullptr)) {
- return std::wstring();
- }
- return device_path;
- }
- int GetInterfaceNumber(const std::wstring& instance_id,
- const std::vector<std::wstring>& hardware_ids) {
- // According to MSDN the instance IDs for the device nodes created by the
- // composite driver is in the form "USB\VID_vvvv&PID_dddd&MI_zz" where "zz"
- // is the interface number.
- //
- // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices
- RE2 pattern("MI_([0-9a-fA-F]{2})");
- std::string instance_id_ascii = base::WideToASCII(instance_id);
- std::string match;
- if (!RE2::PartialMatch(instance_id_ascii, pattern, &match)) {
- // Alternative composite drivers, such as the one used for Samsung devices,
- // don't use the standard format for the instance ID, but one of the
- // hardware IDs will still match the expected pattern.
- bool found = false;
- for (const std::wstring& hardware_id : hardware_ids) {
- std::string hardware_id_ascii = base::WideToASCII(hardware_id);
- if (RE2::PartialMatch(hardware_id_ascii, pattern, &match)) {
- found = true;
- break;
- }
- }
- if (!found)
- return -1;
- }
- int interface_number;
- if (!base::HexStringToInt(match, &interface_number))
- return -1;
- return interface_number;
- }
- UsbDeviceWin::FunctionInfo GetFunctionInfo(const std::wstring& instance_id) {
- UsbDeviceWin::FunctionInfo info;
- info.interface_number = -1;
- base::win::ScopedDevInfo dev_info(
- SetupDiCreateDeviceInfoList(nullptr, nullptr));
- if (!dev_info.is_valid()) {
- USB_PLOG(ERROR) << "SetupDiCreateDeviceInfoList";
- return info;
- }
- SP_DEVINFO_DATA dev_info_data = {};
- dev_info_data.cbSize = sizeof(dev_info_data);
- if (!SetupDiOpenDeviceInfo(dev_info.get(), instance_id.c_str(), nullptr, 0,
- &dev_info_data)) {
- USB_PLOG(ERROR) << "SetupDiOpenDeviceInfo";
- return info;
- }
- info.driver = GetServiceName(dev_info.get(), &dev_info_data);
- if (info.driver.empty()) {
- return info;
- }
- absl::optional<std::vector<std::wstring>> hardware_ids =
- GetDeviceStringListProperty(dev_info.get(), &dev_info_data,
- DEVPKEY_Device_HardwareIds);
- if (!hardware_ids.has_value()) {
- return info;
- }
- info.interface_number = GetInterfaceNumber(instance_id, *hardware_ids);
- if (info.interface_number == -1)
- return info;
- if (!base::EqualsCaseInsensitiveASCII(info.driver, L"winusb"))
- return info;
- // Boost priority while potentially loading Advapi32.dll on a background
- // thread for the registry functions used below.
- SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
- // There is no standard device interface GUID for USB functions and so we
- // must discover the set of GUIDs that have been set in the registry by
- // the INF file or Microsoft OS Compatibility descriptors before
- // SetupDiGetDeviceInterfaceDetail() can be used to get the device path.
- HKEY key = SetupDiOpenDevRegKey(dev_info.get(), &dev_info_data,
- DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
- if (key == INVALID_HANDLE_VALUE) {
- USB_PLOG(ERROR) << "Could not open device registry key";
- return info;
- }
- base::win::RegKey scoped_key(key);
- std::vector<std::wstring> device_interface_guids;
- LONG result =
- scoped_key.ReadValues(L"DeviceInterfaceGUIDs", &device_interface_guids);
- if (result != ERROR_SUCCESS) {
- USB_LOG(ERROR) << "Could not read device interface GUIDs: "
- << logging::SystemErrorCodeToString(result);
- return info;
- }
- for (const auto& guid_string : device_interface_guids) {
- // Boost priority while potentially loading Ole32.dll on a background
- // thread for CLSIDFromString().
- SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
- GUID guid;
- if (FAILED(CLSIDFromString(guid_string.c_str(), &guid))) {
- USB_LOG(ERROR) << "Failed to parse device interface GUID: "
- << guid_string;
- continue;
- }
- info.path = GetDevicePath(instance_id, guid);
- if (!info.path.empty())
- return info;
- }
- return info;
- }
- } // namespace
- class UsbServiceWin::BlockingTaskRunnerHelper {
- public:
- BlockingTaskRunnerHelper(
- base::WeakPtr<UsbServiceWin> service,
- scoped_refptr<base::SequencedTaskRunner> service_task_runner)
- : service_task_runner_(std::move(service_task_runner)),
- service_(std::move(service)) {
- // Boost priority while potentially loading SetupAPI.dll for the following
- // functions on a background thread.
- SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
- base::win::ScopedDevInfo dev_info(
- SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, nullptr, 0,
- DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
- if (!dev_info.is_valid()) {
- USB_PLOG(ERROR) << "Failed to set up device enumeration";
- service_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&UsbServiceWin::HelperStarted, service_));
- return;
- }
- SP_DEVICE_INTERFACE_DATA device_interface_data = {};
- device_interface_data.cbSize = sizeof(device_interface_data);
- for (DWORD i = 0; SetupDiEnumDeviceInterfaces(dev_info.get(), nullptr,
- &GUID_DEVINTERFACE_USB_DEVICE,
- i, &device_interface_data);
- ++i) {
- EnumerateDevice(dev_info.get(), &device_interface_data, absl::nullopt);
- }
- if (GetLastError() != ERROR_NO_MORE_ITEMS)
- USB_PLOG(ERROR) << "Failed to enumerate devices";
- service_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&UsbServiceWin::HelperStarted, service_));
- }
- ~BlockingTaskRunnerHelper() = default;
- void OnDeviceAdded(const GUID& guid, const std::wstring& device_path) {
- // Boost priority while potentially loading SetupAPI.dll and Ole32.dll on a
- // background thread for the following functions.
- SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
- base::win::ScopedDevInfo dev_info(SetupDiGetClassDevs(
- &guid, nullptr, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
- if (!dev_info.is_valid()) {
- USB_PLOG(ERROR) << "Failed to set up device enumeration";
- return;
- }
- SP_DEVICE_INTERFACE_DATA device_interface_data = {};
- device_interface_data.cbSize = sizeof(device_interface_data);
- if (!SetupDiOpenDeviceInterface(dev_info.get(), device_path.c_str(), 0,
- &device_interface_data)) {
- USB_PLOG(ERROR) << "Failed to add device interface: " << device_path;
- return;
- }
- if (IsEqualGUID(guid, GUID_DEVINTERFACE_USB_DEVICE)) {
- EnumerateDevice(dev_info.get(), &device_interface_data, device_path);
- } else {
- EnumeratePotentialFunction(dev_info.get(), &device_interface_data,
- device_path);
- }
- }
- private:
- void EnumerateDevice(HDEVINFO dev_info,
- SP_DEVICE_INTERFACE_DATA* device_interface_data,
- const absl::optional<std::wstring>& opt_device_path) {
- std::wstring device_path;
- std::wstring* device_path_ptr = &device_path;
- if (opt_device_path) {
- device_path = *opt_device_path;
- device_path_ptr = nullptr;
- }
- uint32_t bus_number;
- uint32_t port_number;
- std::wstring parent_instance_id;
- std::vector<std::wstring> child_instance_ids;
- std::wstring service_name;
- if (!GetDeviceInterfaceDetails(dev_info, device_interface_data,
- device_path_ptr, &bus_number, &port_number,
- /*instance_id=*/nullptr, &parent_instance_id,
- &child_instance_ids,
- /*hardware_ids=*/nullptr, &service_name)) {
- return;
- }
- auto driver_type = UsbDeviceWin::DriverType::kUnsupported;
- std::vector<std::pair<int, UsbDeviceWin::FunctionInfo>> functions;
- if (IsCompositeDevice(service_name)) {
- driver_type = UsbDeviceWin::DriverType::kComposite;
- // For composite devices Windows a composite device driver (usually the
- // built-in usbccgp.sys) creates child device nodes for each device
- // function. The device paths for these children must be opened in order
- // to communicate with the WinUSB driver.
- for (const std::wstring& instance_id : child_instance_ids) {
- UsbDeviceWin::FunctionInfo info = GetFunctionInfo(instance_id);
- if (info.interface_number != -1) {
- functions.emplace_back(info.interface_number, info);
- }
- }
- } else if (base::EqualsCaseInsensitiveASCII(service_name, L"winusb")) {
- driver_type = UsbDeviceWin::DriverType::kWinUSB;
- // A non-composite device has a single device node for all interfaces. It
- // may still include multiple functions but they will be ignored.
- UsbDeviceWin::FunctionInfo info;
- info.driver = service_name;
- info.path = device_path;
- functions.emplace_back(/*interface_number=*/0, info);
- }
- std::wstring& hub_path = hub_paths_[parent_instance_id];
- if (hub_path.empty()) {
- hub_path = GetDevicePath(parent_instance_id, GUID_DEVINTERFACE_USB_HUB);
- if (hub_path.empty())
- return;
- }
- service_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&UsbServiceWin::CreateDeviceObject, service_,
- std::move(device_path), std::move(hub_path),
- std::move(functions), bus_number, port_number,
- driver_type, service_name));
- }
- void EnumeratePotentialFunction(
- HDEVINFO dev_info,
- SP_DEVICE_INTERFACE_DATA* device_interface_data,
- const std::wstring& device_path) {
- std::wstring instance_id;
- std::wstring parent_instance_id;
- std::vector<std::wstring> hardware_ids;
- std::wstring service_name;
- if (!GetDeviceInterfaceDetails(
- dev_info, device_interface_data,
- /*device_path=*/nullptr, /*bus_number=*/nullptr,
- /*port_number=*/nullptr, &instance_id, &parent_instance_id,
- /*child_instance_ids=*/nullptr, &hardware_ids, &service_name)) {
- return;
- }
- int interface_number = GetInterfaceNumber(instance_id, hardware_ids);
- if (interface_number == -1)
- return;
- std::wstring parent_path =
- GetDevicePath(parent_instance_id, GUID_DEVINTERFACE_USB_DEVICE);
- if (parent_path.empty())
- return;
- UsbDeviceWin::FunctionInfo info;
- info.driver = service_name;
- info.path = device_path;
- service_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&UsbServiceWin::UpdateFunction, service_,
- std::move(parent_path), interface_number, info));
- }
- std::unordered_map<std::wstring, std::wstring> hub_paths_;
- // Calls back to |service_| must be posted to |service_task_runner_|, which
- // runs tasks on the thread where that object lives.
- scoped_refptr<base::SequencedTaskRunner> service_task_runner_;
- base::WeakPtr<UsbServiceWin> service_;
- };
- UsbServiceWin::UsbServiceWin()
- : blocking_task_runner_(CreateBlockingTaskRunner()) {
- DeviceMonitorWin* device_monitor = DeviceMonitorWin::GetForAllInterfaces();
- if (device_monitor)
- device_observation_.Observe(device_monitor);
- helper_ = base::SequenceBound<BlockingTaskRunnerHelper>(
- blocking_task_runner_, weak_factory_.GetWeakPtr(),
- base::SequencedTaskRunnerHandle::Get());
- }
- UsbServiceWin::~UsbServiceWin() {
- NotifyWillDestroyUsbService();
- }
- void UsbServiceWin::GetDevices(GetDevicesCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (enumeration_ready())
- UsbService::GetDevices(std::move(callback));
- else
- enumeration_callbacks_.push_back(std::move(callback));
- }
- void UsbServiceWin::OnDeviceAdded(const GUID& class_guid,
- const std::wstring& device_path) {
- helper_.AsyncCall(&BlockingTaskRunnerHelper::OnDeviceAdded)
- .WithArgs(class_guid, device_path);
- }
- void UsbServiceWin::OnDeviceRemoved(const GUID& class_guid,
- const std::wstring& device_path) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- auto by_path_it = devices_by_path_.find(device_path);
- if (by_path_it == devices_by_path_.end())
- return;
- scoped_refptr<UsbDeviceWin> device = by_path_it->second;
- devices_by_path_.erase(by_path_it);
- device->OnDisconnect();
- auto by_guid_it = devices().find(device->guid());
- if (by_guid_it != devices().end() && enumeration_ready()) {
- USB_LOG(USER) << "USB device removed: path=" << device->device_path()
- << " guid=" << device->guid();
- devices().erase(by_guid_it);
- NotifyDeviceRemoved(device);
- }
- }
- void UsbServiceWin::HelperStarted() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- helper_started_ = true;
- if (enumeration_ready()) {
- std::vector<scoped_refptr<UsbDevice>> result;
- result.reserve(devices().size());
- for (const auto& map_entry : devices())
- result.push_back(map_entry.second);
- for (auto& callback : enumeration_callbacks_)
- std::move(callback).Run(result);
- enumeration_callbacks_.clear();
- }
- }
- void UsbServiceWin::CreateDeviceObject(
- const std::wstring& device_path,
- const std::wstring& hub_path,
- const base::flat_map<int, UsbDeviceWin::FunctionInfo>& functions,
- uint32_t bus_number,
- uint32_t port_number,
- UsbDeviceWin::DriverType driver_type,
- const std::wstring& driver_name) {
- // Devices that appear during initial enumeration are gathered into the first
- // result returned by GetDevices() and prevent device add/remove notifications
- // from being sent.
- if (!enumeration_ready())
- ++first_enumeration_countdown_;
- auto device = base::MakeRefCounted<UsbDeviceWin>(
- device_path, hub_path, functions, bus_number, port_number, driver_type);
- devices_by_path_[device->device_path()] = device;
- device->ReadDescriptors(
- blocking_task_runner_,
- base::BindOnce(&UsbServiceWin::DeviceReady, weak_factory_.GetWeakPtr(),
- device, driver_name));
- }
- void UsbServiceWin::UpdateFunction(
- const std::wstring& device_path,
- int interface_number,
- const UsbDeviceWin::FunctionInfo& function_info) {
- auto it = devices_by_path_.find(device_path);
- if (it == devices_by_path_.end())
- return;
- const scoped_refptr<UsbDeviceWin>& device = it->second;
- USB_LOG(EVENT) << "USB device function updated: guid=" << device->guid()
- << ", interface_number=" << interface_number << ", path=\""
- << function_info.path << "\", driver=\""
- << function_info.driver << "\"";
- device->UpdateFunction(interface_number, function_info);
- }
- void UsbServiceWin::DeviceReady(scoped_refptr<UsbDeviceWin> device,
- const std::wstring& driver_name,
- bool success) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- bool enumeration_became_ready = false;
- if (!enumeration_ready()) {
- DCHECK_GT(first_enumeration_countdown_, 0u);
- first_enumeration_countdown_--;
- if (enumeration_ready())
- enumeration_became_ready = true;
- }
- // If |device| was disconnected while descriptors were being read then it
- // will have been removed from |devices_by_path_|.
- auto it = devices_by_path_.find(device->device_path());
- if (it == devices_by_path_.end()) {
- success = false;
- } else if (success) {
- DCHECK(!base::Contains(devices(), device->guid()));
- devices()[device->guid()] = device;
- USB_LOG(USER) << "USB device added: path=" << device->device_path()
- << " vendor=" << device->vendor_id() << " \""
- << device->manufacturer_string()
- << "\", product=" << device->product_id() << " \""
- << device->product_string() << "\", serial=\""
- << device->serial_number() << "\", driver=\"" << driver_name
- << "\", guid=" << device->guid();
- } else {
- devices_by_path_.erase(it);
- }
- if (enumeration_became_ready) {
- std::vector<scoped_refptr<UsbDevice>> result;
- result.reserve(devices().size());
- for (const auto& map_entry : devices())
- result.push_back(map_entry.second);
- for (auto& callback : enumeration_callbacks_)
- std::move(callback).Run(result);
- enumeration_callbacks_.clear();
- } else if (success && enumeration_ready()) {
- NotifyDeviceAdded(device);
- }
- }
- } // namespace device
|