如何让Android主机USB在休眠时进入L2模式(OTG设备适配)
解决Android USB OTG休眠时设备不进入L2模式的问题
首先得明确:你遇到的差异是因为Android对不同USB设备类的电源管理策略默认不一样——带HID属性的耳机触发了系统的自动挂起逻辑,而其他设备(鼠标、MSD、CDC、普通ADC耳机)要么被系统标记为「需要持续供电」,要么没满足挂起的前置条件。下面是几个可落地的排查和解决方向:
1. 调整内核层的USB自动挂起配置
Android的USB主机行为很大程度由内核的usbcore驱动控制,你可以针对目标设备类强制开启自动挂起:
- 找到对应设备类的内核驱动文件:比如MSD在
drivers/usb/storage/usb.c,CDC串口在drivers/usb/class/cdc-acm.c - 在设备的probe函数中,添加
usb_enable_autosuspend(dev);,同时确保dev->do_autosuspend被设置为1(有些驱动会默认关闭这个属性) - 注意:如果设备之前被标记为唤醒源,可能需要先调用
usb_autopm_get_interface_no_resume()来解除唤醒锁定,再允许自动挂起
2. 修改系统层面的USB电源策略
系统层的PowerManager和UsbManager会干预USB设备的休眠行为,你可以通过以下方式调整:
- 全局开启自动挂起:用adb命令设置系统属性:
adb shell setprop persist.sys.usb.autosuspend 1,这个属性会让USB主机默认对所有支持的设备启用自动挂起 - 针对单个设备设置:如果是系统应用或者有系统签名的应用,可以通过
UsbManager的API设置设备的电源策略:
这个需要申请UsbDevice targetDevice = ...; // 获取目标设备实例 usbManager.setDevicePowerPolicy(targetDevice, UsbManager.POWER_POLICY_AUTO_SUSPEND);android.permission.MANAGE_USB权限 - 检查唤醒权限:有些设备默认没有「唤醒系统」的权限,系统会因为怕挂起后无法唤醒而保持供电。你可以用adb给设备添加唤醒权限:
adb shell setprop sys.usb.device.remote_wakeup 1
3. 检查设备的USB描述符是否支持挂起
如果设备本身的USB描述符没声明支持远程唤醒或L2模式,Android主机可能不会主动挂起它:
- 在root的设备上用
lsusb -v查看设备描述符,找bDeviceCapability字段,确认是否包含USB_DEVICE_CAPABILITY_REMOTE_WAKEUP - 如果设备不支持远程唤醒,你可以在内核驱动中强制忽略这个检查——修改
usb_remote_wakeup()函数的判断逻辑,不管设备是否支持,都允许挂起(当然这有风险,挂起后设备无法唤醒系统,只能手动唤醒手机)
4. 通过sysfs实时调整设备电源参数
你可以直接修改sysfs中的参数来测试,不需要重新编译内核:
- 先查看USB主机控制器的参数:
cat /sys/module/usbcore/parameters/autosuspend,如果是-1表示禁用自动挂起,改成2(2秒延迟挂起):echo 2 > /sys/module/usbcore/parameters/autosuspend - 针对单个设备,找到它的sysfs路径(比如
/sys/bus/usb/devices/1-1),设置电源控制为自动:echo auto > /sys/bus/usb/devices/1-1/power/control,同时调整挂起延迟:echo 1000 > /sys/bus/usb/devices/1-1/power/autosuspend_delay_ms
5. 排查上层服务的唤醒锁
有些设备(比如普通ADC耳机)可能被音频服务持有唤醒锁,导致系统无法进入深度休眠,进而USB不挂起:
- 用
adb shell dumpsys power查看当前持有的唤醒锁,找是否有音频相关的锁(比如audio_hw_lock) - 修改音频服务的代码,当系统进入休眠时,主动释放对USB音频设备的占用,允许USB总线进入L2模式
- 对于MSD设备,确保休眠前没有未完成的文件读写操作,系统默认会在存储设备有IO时阻止挂起,必要时可以在休眠前卸载存储设备
内容的提问来源于stack exchange,提问作者Adrian




