Android API 19设备重启后USB Accessory无法通信排查求助
解决Android API 19下重启后USB Accessory无法通信的问题
我帮你分析过了,你遇到的这个问题在API19(KitKat)的默认Home应用里其实挺常见的——核心就是重启后明明UsbManager.hasPermission()显示有权限,但调用openAccessory()就是没法建立有效通信,只有拔插线缆才能恢复。结合你给出的代码和配置,我整理了几个针对性的修复方案:
一、API19的USB权限持久化bug
API19的USB权限管理存在一个已知问题:设备重启后,系统虽然会保留权限标记(所以hasPermission()返回true),但USB Accessory的底层设备节点并没有正确绑定到你的应用,导致openAccessory()拿到的文件描述符无效。
修复方案:强制触发一次Accessory重新识别
你可以在应用启动或恢复前台时,主动触发一次权限请求(即使权限已存在),让系统重新校验并绑定Accessory:
// 在应用onCreate或onResume中调用 private void refreshUsbAccessory() { UsbAccessory[] accessories = usbmanager.getAccessoryList(); if (accessories != null && accessories.length > 0) { UsbAccessory accessory = accessories[0]; // 先关闭可能存在的无效连接 if (usbaccessory != null) { DestroyAccessory(true); } // 主动请求权限,触发系统重新绑定Accessory usbmanager.requestPermission(accessory, mPermissionIntent); } }
二、BroadcastReceiver注册时机问题
你的代码在初始化时注册Receiver,但作为默认Home应用,重启后应用启动可能早于USB系统服务初始化,导致Receiver没捕获到USB_ACCESSORY_ATTACHED的系统广播,Accessory未被正确初始化。
修复方案:
- 将Receiver注册移到
onResume()中,确保应用前台时能捕获广播:
@Override protected void onResume() { super.onResume(); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); registerReceiver(mUsbReceiver, filter); // 同时触发Accessory刷新 refreshUsbAccessory(); } @Override protected void onPause() { super.onPause(); unregisterReceiver(mUsbReceiver); }
- 补充静态注册广播(作为兜底,确保系统能唤醒应用处理Accessory事件):
<receiver android:name=".UsbAccessoryReceiver"> <intent-filter> <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" android:resource="@xml/accessory_filter" /> </receiver>
三、OpenAccessory方法的有效性校验缺失
你的OpenAccessory()只判断了文件描述符是否为null,但API19中即使openAccessory()返回非null对象,文件描述符也可能无效。
修复方案:增加文件描述符有效性检查
private void OpenAccessory(UsbAccessory accessory) { filedescriptor = usbmanager.openAccessory(accessory); if(filedescriptor != null){ FileDescriptor fd = filedescriptor.getFileDescriptor(); // 新增:检查文件描述符是否有效 if (!fd.valid()) { Log.e("LED", "Invalid file descriptor for accessory"); usbmanager.requestPermission(accessory, mPermissionIntent); return; } usbaccessory = accessory; inputstream = new FileInputStream(fd); outputstream = new FileOutputStream(fd); if(inputstream == null || outputstream==null){ Log.e("LED", "Input/Output stream null"); return; } if(READ_ENABLE == false){ READ_ENABLE = true; readThread = new read_thread(inputstream); readThread.start(); } SerialComm.getInstance().initPort(); } else { Log.e("LED", "Failed to open accessory"); usbmanager.requestPermission(accessory, mPermissionIntent); } }
额外注意事项
- API19下默认Home应用启动优先级很高,可能早于USB服务初始化,一定要在
onResume()中做二次检查,不要只依赖启动时的初始化。 - 不要把
hasPermission()的返回值作为能否打开Accessory的唯一判断,权限标记和底层设备绑定是分离的。 - 测试时可以在
openAccessory()前后打印usbmanager.getAccessoryList(),确认Accessory是否被系统正确识别。
内容的提问来源于stack exchange,提问作者Macaret
相关产品推荐
相关产品推荐

