fix(devicecontrol): rebind USB HID driver on device enable - #731
fix(devicecontrol): rebind USB HID driver on device enable#731GongHeng2017 wants to merge 1 commit into
Conversation
Restructure authorizedEnable to mirror a physical replug: deauthorize the parent USB device, settle for teardown, reauthorize it, explicitly reauthorize the interface, then trigger udev to rebuild input devices. 重构 authorizedEnable 启用流程使其等价物理拔插:父设备去授权后等待 内核清理完成再重新授权,并显式重新授权接口、触发 udev 重建输入设备 节点,修复 USB 鼠标禁用后启用仍无响应需重新拔插的问题。 Log: 修复USB鼠标禁用后启用仍无法使用需重新拔插的问题 PMS: BUG-341577 Influence: USB外设禁用后启用可正常恢复使用,无需物理拔插
There was a problem hiding this comment.
Sorry @GongHeng2017, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: GongHeng2017 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Reviewer's GuideRefactors the USB device enable flow in ControlInterface::authorizedEnable to emulate a full disconnect–reconnect cycle so that USB HID drivers and input nodes are reliably rebound when a device is re-enabled. Sequence diagram for updated USB device enable flow in authorizedEnablesequenceDiagram
participant ControlInterface
participant SysfsParent as parent_authorized
participant SysfsInterface as interface_authorized
participant Udevadm
participant Udevd
ControlInterface->>SysfsParent: QFile::write("0") // parent /authorized
ControlInterface->>ControlInterface: QThread::msleep(100)
ControlInterface->>SysfsParent: QFile::write("1") // parent /authorized
ControlInterface->>SysfsInterface: QFile::write("1") // interface /authorized
ControlInterface->>Udevadm: QProcess::execute("udevadm trigger --action=add --syspath=/sys/...")
Udevadm->>Udevd: add event for USB device
Udevd-->>SysfsInterface: recreate input device nodes
ControlInterface-->>ControlInterface: EnableSqlManager::removeDataFromAuthorizedTable(unique_id)
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
deepin pr auto review★ 总体评分:50分■ 【总体评价】
■ 【详细分析】
■ 【改进建议代码示例】 diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp b/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp
index 105f5e60..safe_code_patch 100644
--- a/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp
+++ b/deepin-devicemanager-server/deepin-devicecontrol/src/controlinterface.cpp
@@ -333,6 +333,13 @@ bool ControlInterface::authorizedEnable(const QString &hclass, const QString &na
}
if (enable_device) {
+ // 安全校验:防止路径遍历和参数注入
+ QRegularExpression validPathRegex("^[a-zA-Z0-9\\-\\./:]+$");
+ if (!validPathRegex.match(path).hasMatch() || path.contains("..")) {
+ qWarning() << "Invalid path detected:" << path;
+ return false;
+ }
+
/*
启用流程需等价于物理拔插的「断开—重连」,使 usbhid 重新绑定、
输入节点重建,否则鼠标启用后仍无响应(PMS 341577)。
@@ -368,8 +375,11 @@ bool ControlInterface::authorizedEnable(const QString &hclass, const QString &na
// 第四步:显式重新授权接口(禁用的直接逆操作)
- if (file.open(QIODevice::ReadWrite)) {
+ if (!file.open(QIODevice::ReadWrite)) {
+ qWarning() << "Failed to open interface authorized file for re-enabling:" << file.fileName();
+ return false;
+ }
+ {
file.write("1");
file.close();
}
@@ -377,8 +387,9 @@ bool ControlInterface::authorizedEnable(const QString &hclass, const QString &na
// 第五步:触发 udev 重新处理设备添加事件,确保输入设备节点重建
- QProcess::execute("udevadm", QStringList() << "trigger"
- << "--action=add" << ("--syspath=" + QString("/sys") + pop));
+ QString sysPath = "/sys" + pop;
+ if (sysPath.startsWith("/sys/devices/")) {
+ QProcess::startDetached("udevadm", QStringList() << "trigger" << "--action=add" << ("--syspath=" + sysPath));
+ }
EnableSqlManager::getInstance()->removeDataFromAuthorizedTable(unique_id); |
|
@GongHeng2017: The following test failed, say
Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
fix(devicecontrol): rebind USB HID driver on device enable
问题现象
USB 鼠标在设备管理器中右键「禁用」后,右键「启用」仍无法使用,必须物理拔插才恢复。必现(飞腾 D3000M 平台)。
根因分析(强根因)
禁用后恢复 USB 鼠标的唯一代码路径是
ControlInterface::authorizedEnable的启用分支(controlinterface.cpp原三步序列)。该序列仅做「/sys/.../authorized就地翻转」:unbind/bind、udevadm trigger)。该就地翻转不等价于物理拔插的「断开—重连 + udev add」,usbhid 未被可靠重新绑定、输入节点未重建,故启用后鼠标无响应。
关键证据(
file:line,基线develop/eagle@ccd4ab90):controlinterface.cpp:361— 禁用向接口authorized写0(解绑 usbhid)。controlinterface.cpp:341 / 350 / 356— 启用三步就地翻转;:350抹掉:341,无 settle。controlinterface.cpp:365— 启用仍return true,前端据此标记「已启用」(UI 与实际不符)。controlinterface.cpp:372-376— 同文件旁证:removeEnable用/sys/bus/pci/rescan做真正重新枚举,authorizedEnable缺等价机制。排除项:
:103sPath = path(480a9ef8/Bug 316525 引入)破坏的是「换 USB 口」回查,与本 bug(同口禁用-启用)无关,为独立共存 bug,不在本次修复范围。修复方案
重构
authorizedEnable启用分支为「断开—重连」等价序列(仅改该函数内部,签名不变):0)——整设备去授权,解绑所有接口驱动、销毁输入节点(断开等价);QThread::msleep(100))——等待内核完成去授权清理,避免去授权-重新授权竞态;1)——整设备重新授权,重新枚举并探测接口驱动(重连等价);1)——禁用的直接逆操作,确保接口已授权(sysfs 条目在重新枚举后重建,重新打开);udevadm trigger --action=add --syspath=...——模拟物理拔插产生的 udev add 事件,确保输入设备节点重建。移除了被自身抹掉的旧第一步(接口写 1 被随后的父设备去授权覆盖)。
改动安全评估
低风险。
blame显示目标行全部归因于原始引入提交c0f83b6f(非既有 bug 修复,无撤销风险);authorizedEnable唯一调用者是同文件enable()(:109),签名不变、返回值语义不变,调用者不受负面影响。新增依赖为 Qt/系统标准设施(QThread、udevadm)。验证建议
建议在复现机(飞腾 D3000M)验证:禁用 USB 鼠标 → 软件启用 → 滚动/点击可用(无需拔插)。可对照
dmesg/udevadm monitor/ls /dev/input/确认启用后输入节点重建。Summary by Sourcery
Ensure USB HID devices are properly reinitialized when re-enabled via device manager by making the authorization sequence equivalent to a physical unplug-replug cycle.
Bug Fixes:
Enhancements: