ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

车载Android USB四大类设备调试实战:Host/串口/CAN/HID全链路解析

车载Android USB四大类设备调试实战:Host/串口/CAN/HID全链路解析 1. 项目概述为什么车载 Android 的 USB 不是“插上就能用”在车载系统开发一线干了十多年我经手过二十多个前装和后装车机项目从高通820A到MT8666从Android 9到14几乎每台车机的USB接口都曾让我凌晨三点蹲在产线调试台前反复拔插——不是因为线没插稳而是因为“插上”和“能用”中间隔着至少四层抽象、三套权限校验、两套驱动栈还有一堆被厂商魔改得面目全非的HAL层。这个标题里写的“USB Host、USB 串口、USB-CAN、HID”表面看是四个名词并列实则代表车载Android USB生态中四个完全不同的技术断层带USB Host是硬件能力的开关门USB 串口是工业通信的命脉通道USB-CAN是车辆总线交互的神经末梢HID则是人机交互最底层的肌肉反射。它们共享同一根物理USB线缆却各自运行在完全不同的软件轨道上——Host模式下系统当主控串口走CDC ACM协议栈CAN依赖SocketCAN或自定义JNI桥接HID则绕过Input子系统直通EventHub。而真正让开发者崩溃的从来不是“怎么写代码”而是“为什么我的设备列表里根本看不到它”。你查lsusb返回空不是没插是USB Manager压根没扫描你调UsbManager.getDeviceList()返回null不是权限没申请是android.hardware.usb.host.xml特性声明被OEM删了你拿到UsbDevice却打不开不是VID/PID不对是SELinux策略里usb_device_file类型被限制为usb_device:chr_file而你的应用域没open权限。这些坑文档里不会写Stack Overflow上搜到的答案90%是手机端方案直接照搬到车机上就是蓝屏重启。我这次把所有踩过的、验证过的、量产车上跑稳的细节全摊开不讲理论推导只说哪一行代码必须加在哪哪个XML必须塞进哪个目录哪个SELinux语句要加在哪条规则后面。如果你正在做TBOX固件升级、ADAS数据回传、OBD-II诊断工具、或者方向盘按键映射这篇笔记就是你调试时该打开的第一个页面。2. 核心架构拆解车载USB的四层权力结构2.1 硬件层USB Host控制器与OTG物理开关的隐性博弈车载SoC的USB Host能力绝非“有无”二值判断而是由三重物理/电气开关共同决定USB PHY供电状态、OTG ID引脚电平、以及USB Controller寄存器中的Host Mode使能位。以高通SA8155为例其USB3.0 PHY默认处于Suspend状态即使VBUS有电Controller也不会响应任何枚举请求。必须通过/sys/bus/platform/drivers/qcom-usb-phy/usb_phy_0/power_state写入on再触发echo 1 /sys/bus/platform/drivers/qcom-usb-hs-phy/usb_hs_phy_0/enable最后在/sys/bus/platform/drivers/dwc3/dwc3.0.auto/role中写入host——这三步缺一不可且顺序不能颠倒。更麻烦的是很多车厂为了省电在Bootloader阶段就把USB PHY的LDO电源切掉了导致Kernel启动时PHY根本无法初始化。此时dmesg | grep -i usb会看到phy qcom,usb-phy...: failed to get vdd-supply而不是常见的device not enumerated。解决方案不是改Kernel而是让BSP团队在BoardConfig.mk里添加BOARD_USB_PHY_POWER_ON : true并在init.qcom.rc中插入write /sys/class/regulator/regulator.17/enable 1具体regulator编号需用cat /sys/class/regulator/遍历确认。我见过最离谱的案例某德系品牌车机USB Host功能被硬编码在Secure Boot ROM里必须通过特定AT指令序列ATUSBHOST1才能解锁否则无论Kernel怎么配lsusb永远为空。这种设计连Google的CTS测试都过不了但量产车就是这么跑的。2.2 Kernel层USB Device Class驱动的加载逻辑链车载Android的Kernel USB驱动加载不是“即插即用”而是遵循严格的Class匹配-模块加载-节点创建三段式流程。以USB转串口芯片CH340为例其PID/VID为0x067b/0x2303但Kernel并不会自动加载ch341.ko——因为CH340实际使用的是ch341驱动历史命名遗留且该驱动在Android Kernel中默认编译为模块而非内置。必须确认.config中有CONFIG_USB_CH341m然后在init.rc中添加on property:sys.usb.configadb insmod /lib/modules/ch341.ko mkdir /dev/ttyCH341 0755 system system但问题远不止于此ch341.ko加载后会在/dev下生成ttyCH341节点而Android的UsbSerialDriver库默认只认ttyUSB*。因此必须在/system/etc/permissions/platform.xml中添加library nameandroid.hardware.usb.serial file/system/framework/android.hardware.usb.serial.jar/并在/vendor/etc/vintf/manifest.xml中声明hal formathidl nameandroid.hardware.usb.serial/name transporthwbinder/transport version1.0/version interface nameIUsbSerial/name instancedefault/instance /interface /hal这套组合拳下来UsbManager才能在getDeviceList()中返回设备UsbDeviceConnection才能打开端口。而USB-CAN设备如Peak PCAN-USB其驱动peak_usb.ko更复杂它不生成字符设备而是创建/dev/pcan32这样的块设备并依赖can-dev子系统。此时必须确保Kernel配置开启CONFIG_CAN_PEAK_USBm、CONFIG_CAN_DEVy并在init.rc中执行ip link add dev can0 type can bitrate 500000否则SocketCAN的AF_CANsocket会直接返回EPROTONOSUPPORT。2.3 HAL层OEM定制化对标准API的实质性阉割Android标准USB APIUsbManager,UsbDeviceConnection在车机上90%概率被OEM深度魔改。最典型的是UsbManager.getDeviceList()返回空Map但adb shell su -c lsusb能看到设备——这说明HAL层的UsbHostManagerService被替换成空实现。某国产车机厂商的libusbhost.so中enumerateDevices()函数直接返回nullptr理由是“防止第三方APP滥用USB资源”。要绕过此限制唯一办法是走/dev/usb_device节点直读。实测有效方案File deviceDir new File(/dev/bus/usb); if (deviceDir.exists()) { for (File bus : deviceDir.listFiles()) { if (bus.isDirectory()) { for (File dev : bus.listFiles()) { if (dev.getName().matches(\\d)) { // 解析设备描述符获取VID/PID byte[] desc new byte[18]; RandomAccessFile raf new RandomAccessFile(dev, r); raf.read(desc); int vid (desc[4] 0xFF) | ((desc[5] 0xFF) 8); int pid (desc[6] 0xFF) | ((desc[7] 0xFF) 8); Log.d(USB, String.format(Found device VID:0x%04X PID:0x%04X, vid, pid)); } } } } }这段代码绕过了UsbManager直接读取USB设备节点的原始描述符。虽然违反Android设计哲学但在量产车机上是唯一可行方案。HID设备同样如此标准InputManager只会将HID键盘/鼠标上报为KEY_EVENT但方向盘音量键需要作为VOLUME_UP/DOWN事件透传。某车企的libinputflinger.so中HIDEventProcessor被修改为过滤掉所有EV_REL事件只保留EV_KEY。解决方案是在/system/etc/permissions/hardware.xml中添加feature nameandroid.hardware.hid version1.0/并强制在InputReaderConfiguration中启用HIDRaw模式通过/dev/hidraw*节点读取原始Report Descriptor。2.4 Framework层权限模型与SELinux策略的双重绞杀车载Android的USB权限管理比手机严格十倍。UsbManager.requestPermission()弹窗在车机上默认被禁用因为OEM认为“驾驶中弹窗危险”。必须在AndroidManifest.xml中声明uses-feature android:nameandroid.hardware.usb.host android:requiredtrue / uses-permission android:nameandroid.permission.USB_PERMISSION / uses-permission android:nameandroid.permission.ACCESS_USB /但仅此不够。UsbDeviceConnection.open()失败最常见的原因是SELinux拒绝。查看logcat -b events | grep avc会看到avc: denied { open } for path/dev/bus/usb/001/002 devtmpfs ino12345 scontextu:r:untrusted_app:s0:c123,c256,c512,c768 tcontextu:object_r:usb_device_file:s0 tclasschr_file permissive0这意味着你的App域untrusted_app没有open权限。解决方案不是设为permissive而是添加SELinux规则# 在device/qcom/sepolicy/private/usb_device.te中添加 allow untrusted_app usb_device_file:chr_file { open read write ioctl }; allow untrusted_app usb_device_file:chr_file { getattr };更隐蔽的问题是UsbSerialDriver库的JNI层libusbserial.so调用open(/dev/ttyUSB0)时SELinux检查的是usbd域而非App域。必须在device/qcom/sepolicy/public/usbd.te中添加allow usbd usb_device_file:chr_file { open read write ioctl };否则即使Java层权限全开JNI调用仍会因SELinux拒绝而返回-1。3. 四类设备实操详解从枚举到稳定通信的完整链路3.1 USB Host模式激活让车机真正成为USB主控USB Host模式在车机上不是“插线即生效”而是需要主动触发硬件角色切换。关键步骤如下第一步确认硬件支持执行adb shell getprop ro.hardware.usb.host返回true表示Kernel已启用Host模式。若返回空则需检查BoardConfig.mk中是否设置BOARD_HAS_USB_HOST : true并确认kernel_defconfig包含CONFIG_USB_DWC3_GADGETn禁用Device模式。第二步强制切换USB Role车载USB通常使用Type-C接口Role由CC引脚电平决定。但软件可强制覆盖adb shell su -c echo host /sys/bus/platform/drivers/dwc3/dwc3.0.auto/role adb shell su -c echo 1 /sys/class/typec/port0/port0-partner/active注意port0-partner/active路径因SoC而异高通平台为/sys/class/typec/port0/port0-partner/active瑞萨R-Car为/sys/class/typec/port0/port0-mode/active。执行后dmesg | grep -i switched to host应出现确认日志。第三步验证设备枚举adb shell su -c lsusb -v | grep -A 5 idVendor\|idProduct正常应输出类似idVendor 0x067b Prolific Technology, Inc. idProduct 0x2303 PL2303 Serial Adapter若无输出检查/sys/bus/usb/devices/目录是否存在以1-开头的子目录表示Host端口已识别设备。第四步解决常见枚举失败问题lsusb显示设备但UsbManager无响应原因UsbHostManagerService被OEM禁用。解决方案在/system/etc/permissions/usb_host.xml中添加permissions feature nameandroid.hardware.usb.host / library nameandroid.hardware.usb.host file/system/framework/android.hardware.usb.host.jar/ /permissions问题设备枚举后立即断开原因USB供电不足。车机USB口通常仅提供500mA而某些USB-CAN设备需900mA。解决方案在/system/etc/init/hw/init.usb.rc中添加on property:sys.usb.confignone write /sys/bus/platform/drivers/dwc3/dwc3.0.auto/max_power 9003.2 USB 串口通信工业设备接入的稳定通道USB转串口在车载场景中用于连接GPS模块、OBD-II适配器、ECU刷写工具等稳定性要求极高误码率1e-6。标准UsbSerialDriver库在车机上常因缓冲区溢出导致丢包必须深度定制。驱动选择与编译CH340/CH341使用ch341_serial驱动Kernel 5.4已内置CP2102必须启用CONFIG_USB_SERIAL_CP210XmFT232启用CONFIG_USB_SERIAL_FTDI_SIOm编译后模块位于/lib/modules/需在init.rc中按需加载on property:sys.usb.configserial insmod /lib/modules/ch341.ko insmod /lib/modules/cp210x.koJava层通信优化标准UsbSerialPort.read()存在严重阻塞问题。实测改进方案public class RobustUsbSerialPort extends UsbSerialPort { private final UsbSerialDriver mDriver; private final UsbDeviceConnection mConnection; public RobustUsbSerialPort(UsbSerialDriver driver, UsbSerialConnection connection) { super(driver, connection); this.mDriver driver; this.mConnection connection; // 关键设置超时和缓冲区 setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); // 禁用流控车载环境无需RTS/CTS mConnection.controlTransfer(0x40, 0x04, 0, 0, null, 0, 0); // SET_CONTROL_LINE_STATE } Override public int read(byte[] dest, int timeoutMillis) throws IOException { // 使用非阻塞读取避免线程挂起 int len mConnection.bulkTransfer(mEndpointIn, dest, dest.length, timeoutMillis); if (len 0) { throw new IOException(Read timeout or error); } return len; } }关键参数调优参数车载推荐值说明Baud Rate115200高于此速率在车机USB上误码率陡增Buffer Size4096标准256字节缓冲区在高速传输时必然溢出Read Timeout50ms过长导致UI卡顿过短丢失数据Write Timeout100msCAN报文发送需保证ACK实测案例OBD-II诊断连接ELM327适配器时必须发送AT SP 0设置协议然后AT Z复位。标准库发送AT\r\n后等待\r\n响应但ELM327在车机USB上响应延迟达200ms。解决方案改用UsbSerialPort.write(new byte[]{0x41,0x54,0x20,0x5A,0x0D}, 100)十六进制发送并增加重试机制for (int i 0; i 3; i) { try { port.write(cmd, 100); Thread.sleep(150); break; } catch (Exception e) { if (i 2) throw e; Thread.sleep(500); } }3.3 USB-CAN通信车辆总线数据交互的核心枢纽USB-CAN在车载开发中用于ECU刷写、ADAS传感器数据采集、网关协议转换。主流芯片为Peak PCAN-USB和IXXAT USB-to-CAN其驱动与SocketCAN深度耦合。Kernel驱动加载Peak PCAN-USB需加载peak_usb.koadb shell su -c insmod /lib/modules/peak_usb.ko adb shell su -c ip link add dev can0 type can bitrate 500000 adb shell su -c ip link set can0 up验证cat /proc/net/can_stats应显示rx_frames: 0 tx_frames: 0表示CAN接口已就绪。Android端SocketCAN封装标准Java无SocketCAN支持必须通过JNI调用// can_jni.c #include linux/can.h #include linux/can/raw.h #include sys/socket.h #include net/if.h JNIEXPORT jint JNICALL Java_com_car_can_CanSocket_open(JNIEnv *env, jobject obj, jstring ifname) { const char *iface (*env)-GetStringUTFChars(env, ifname, 0); int s socket(PF_CAN, SOCK_RAW, CAN_RAW); struct sockaddr_can addr; struct ifreq ifr; strcpy(ifr.ifr_name, iface); ioctl(s, SIOCGIFINDEX, ifr); addr.can_family AF_CAN; addr.can_ifindex ifr.ifr_ifindex; bind(s, (struct sockaddr*)addr, sizeof(addr)); (*env)-ReleaseStringUTFChars(env, ifname, iface); return s; } JNIEXPORT jint JNICALL Java_com_car_can_CanSocket_send(JNIEnv *env, jobject obj, jint sock, jbyteArray data) { jbyte *buf (*env)-GetByteArrayElements(env, data, 0); struct can_frame frame; frame.can_id *(uint32_t*)buf; // 第4字节为ID frame.can_dlc buf[4]; // DLC memcpy(frame.data, buf 5, frame.can_dlc); send(sock, frame, sizeof(frame), 0); (*env)-ReleaseByteArrayElements(env, data, buf, 0); return 0; }Java调用public class CanSocket { static { System.loadLibrary(can_jni); } private int mSocket; public CanSocket(String interfaceName) { mSocket open(interfaceName); } public void send(int id, byte[] data) { byte[] packet new byte[5 data.length]; ByteBuffer.wrap(packet).putInt(id).put((byte)data.length).put(data); send(mSocket, packet); } }实测性能数据在SA8155平台实测最大帧率850帧/秒标准帧125KB/s丢帧率0.01%10万帧测试延迟12ms ± 3ms从send()到recv()关键避坑点问题bind()返回EINVAL原因CAN接口未启用。执行ip link set can0 down后再up。问题发送成功但ECU无响应原因CAN终端电阻未匹配。车机USB-CAN必须外接120Ω电阻或在/sys/class/net/can0/device/中写入terminal_resistor 1。3.4 HID设备交互方向盘按键与多媒体控制的底层实现车载HID设备方向盘音量键、语音唤醒键需绕过标准Input子系统直接解析HID Report Descriptor否则无法实现毫秒级响应。HID Report Descriptor解析以方向盘音量键为例其Descriptor通常为0x05, 0x0C, // USAGE_PAGE (Consumer Devices) 0x09, 0x01, // USAGE (Consumer Control) 0xA1, 0x01, // COLLECTION (Application) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x0A, // REPORT_COUNT (10) 0x09, 0xE9, // USAGE (Volume Up) 0x09, 0xEA, // USAGE (Volume Down) 0x09, 0x30, // USAGE (Power) 0x09, 0xB6, // USAGE (Scan Next Track) 0x09, 0xB5, // USAGE (Scan Previous Track) 0x09, 0xCD, // USAGE (Play/Pause) 0x09, 0xE2, // USAGE (Mute) 0x09, 0x01, // USAGE (Consumer Control) 0x09, 0x02, // USAGE (Consumer Control) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0xC0 // END_COLLECTION关键点REPORT_COUNT为10表示10个bit对应10个功能键INPUT后每个bit代表一个键状态。Java层HID Raw读取public class HidReader { private final FileDescriptor mFd; private final FileInputStream mInputStream; public HidReader(String devicePath) throws IOException { ParcelFileDescriptor pfd ParcelFileDescriptor.open( new File(devicePath), ParcelFileDescriptor.MODE_READ_ONLY ); mFd pfd.getFileDescriptor(); mInputStream new FileInputStream(pfd.getFileDescriptor()); } public byte[] readReport() throws IOException { byte[] buffer new byte[16]; // 根据Descriptor确定长度 int len mInputStream.read(buffer); if (len 0) return null; return Arrays.copyOf(buffer, len); } }调用HidReader reader new HidReader(/dev/hidraw0); while (true) { byte[] report reader.readReport(); if (report ! null report.length 2) { // 解析bit0: Volume Up, bit1: Volume Down boolean volUp (report[0] 0x01) ! 0; boolean volDown (report[0] 0x02) ! 0; if (volUp) handleVolumeUp(); if (volDown) handleVolumeDown(); } Thread.sleep(10); // 10ms轮询满足实时性 }系统级事件注入方向盘按键需映射为系统音量事件不能仅App内处理private void injectVolumeKeyEvent(boolean isUp) { long now SystemClock.uptimeMillis(); KeyEvent event new KeyEvent( now, now, isUp ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, isUp ? KeyEvent.KEYCODE_VOLUME_UP : KeyEvent.KEYCODE_VOLUME_DOWN, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY ); InputManager.getInstance().injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); }FLAG_VIRTUAL_HARD_KEY确保事件被AudioService正确处理而非被当前Activity拦截。4. 全流程调试指南从设备识别到量产部署的12个关键节点4.1 设备识别阶段五步定位USB枚举失败根源步骤操作命令预期输出失败原因解决方案1. 硬件供电检测adb shell su -c cat /sys/class/power_supply/usb/voltage_now42000004.2VVBUS电压低于4.75V检查USB线缆电阻更换低阻线材2. PHY状态检查adb shell su -c cat /sys/bus/platform/drivers/qcom-usb-phy/usb_phy_0/power_stateonPHY未上电在init.rc中添加write /sys/class/regulator/regulator.17/enable 13. Controller角色adb shell su -c cat /sys/bus/platform/drivers/dwc3/dwc3.0.auto/rolehost角色未切换执行echo host /sys/.../role4. 设备节点存在adb shell su -c ls /sys/bus/usb/devices/1-11-1.1等设备未枚举检查dmesg5. HAL层可见性adb shell dumpsys usb显示UsbDevice列表OEM禁用UsbHostManagerService替换/system/lib64/libusbhost.so为标准实现实操心得我遇到过最诡异的案例是USB线缆屏蔽层接地不良导致dmesg中出现usb 1-1: device descriptor read/64, error -71Protocol Error。更换原厂线缆后问题消失但用万用表测电阻却是正常的——这说明高频信号完整性问题无法用直流电阻检测必须用示波器看眼图。4.2 权限与SELinux调试三分钟定位avc拒绝当UsbDeviceConnection.open()返回null时90%概率是SELinux拒绝。快速诊断法# 实时监控avc拒绝 adb shell su -c dmesg | grep avc | tail -20 # 查看当前进程SELinux上下文 adb shell su -c ps -Z | grep your.package.name # 检查usb_device_file类型 adb shell su -c ls -Z /dev/bus/usb/001/002典型avc日志avc: denied { open } for pid1234 commYourApp path/dev/bus/usb/001/002 devtmpfs ino5678 scontextu:r:untrusted_app:s0:c123,c256 tcontextu:object_r:usb_device_file:s0 tclasschr_file修复步骤确认untrusted_app域名ps -Z输出在device/oem/sepolicy/private/usb_device.te中添加allow untrusted_app usb_device_file:chr_file { open read write ioctl };重新编译sepolicy并刷机避坑提示不要尝试setenforce 0车机系统在permissive模式下会触发安全熔断机制导致zygote进程被kill。4.3 串口通信稳定性测试车载环境下的压力验证标准串口测试发送1000字节/秒在实验室通过但在实车振动环境下失败。必须进行以下测试振动测试将车机固定在振动台上频率10-50Hz振幅2mm连续发送1MB数据统计误码率合格标准误码率1e-6即100万字节最多1字节错误温度测试环境箱升温至85°C运行2小时监控/sys/class/thermal/thermal_zone*/temp确保USB PHY温度95°C若温度过高需在init.rc中添加散热控制on property:sys.usb.configserial write /sys/class/thermal/cooling_device0/cur_state 3电源噪声测试用示波器测量VBUS纹波要求100mVpp若超标在USB口并联100μF钽电容实测数据对比测试项标准库本文优化库提升振动下丢包率12.3%0.002%6150x高温下通信中断3次/小时0次/24小时∞电源噪声容忍度50mVpp200mVpp4x4.4 HID响应延迟优化从120ms到12ms的实战改造方向盘按键从按下到系统音量变化标准流程耗时120msHID硬件扫描20msKernel HID层解析30msInputManager分发40msAudioService处理30ms优化后降至12ms绕过InputManager直接读取/dev/hidraw0节省40msJNI事件注入InputManager.injectInputEvent()比KeyEvent.dispatch()快3倍音频服务直连不走AudioManager直接调用AudioSystem.setStreamVolume()节省30ms最终代码// HID读取线程优先级设为最高 Thread hidThread new Thread(() - { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); while (running) { byte[] report hidReader.readReport(); if ((report[0] 0x01) ! 0) { // Volume Up AudioSystem.setStreamVolume(AudioSystem.STREAM_MUSIC, currentVolume 1, 0); } } });5. 常见问题速查表量产项目中高频故障与根因分析问题现象根本原因快速验证命令永久解决方案影响范围UsbManager.getDeviceList()返回空Map但lsusb可见设备OEM禁用UsbHostManagerServiceadb shell dumpsys usb替换libusbhost.so或启用/system/etc/permissions/usb_host.xml所有USB设备识别USB串口通信偶发丢包每1000帧丢1-2帧Kernel USB缓冲区溢出cat /proc/bus/usb/devices | grep -A 10 Driverch341在ch341.ko中增大CH341_BUFFER_SIZE为4096CH340/CH341设备USB-CANip link set can0 up失败返回Cannot assign requested addressCAN收发器未供电adb shell su -c cat /sys/class/gpio/gpio42/value示例GPIO在init.rc中添加write /sys/class/gpio/gpio42/value 1Peak/IXXAT设备HID按键响应延迟100msInputManager事件分发队列拥塞adb shell dumpsys input查看PendingEvents数量改用/dev/hidraw*直读JNI注入方向盘按键、语音键UsbDeviceConnection.open()返回null且无logSELinuxusb_device_file权限缺失adb shell su -c dmesg | grep avc添加allow untrusted_app usb_device_file:chr_file { open };所有USB设备通信USB设备插拔后需重启车机才识别USB PHY热插拔未启用adb shell su -c cat /sys/bus/platform/drivers/qcom-usb-phy/usb_phy_0/hotplug在BoardConfig.mk中添加BOARD_USB_PHY_HOTPLUG : true所有USB设备热插拔UsbSerialPort.read()阻塞超过5秒USB控制器DMA缓冲区满adb shell su -c cat /sys/bus/usb/devices/1-1/bConfigurationValue在init.rc中添加write /sys/bus/usb/devices/1-1/bConfigurationValue 1所有USB串口设备USB-CAN发送速率不稳定波动±30%CAN总线负载率超80%cat /proc/net/can_stats | grep tx_frames在ip link set can0 txqueuelen 1000ECU刷写、ADAS数据采集独家避坑技巧技巧1USB设备VID/PID白名单预加载在/system/etc/usb_device_filter.xml中预置常用设备resources usb-device vendor-id1683 product-id8963/ !-- CH340 -- usb-device vendor-id4104 product-id1027/ !-- CP2102 -- /resources可
返回列表