Blog
Blog copied to clipboard
记录车机先插u盘再插iPhone,u盘会掉的问题
这个问题很坑,走了不少弯路,在此记录一下。 背景: 在车机上先插入u盘(车机Host)播放音乐,再插入iPhone(车机OTG)然后U盘会掉。
开始调试
跟踪内核打印发现每次掉的时候内核都有"disconnect by usbfs
的打印,搜索内核源码,发现是通过ioctl主动调用的。
/* disconnect kernel driver from interface */
case USBDEVFS_DISCONNECT:
if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver);
dev_dbg(&intf->dev, "disconnect by usbfs\n");
usb_driver_release_interface(driver, intf);
} else
retval = -ENODATA;
break;
添加打印
通过添加打印发现调用进程是system_server。
printk(KERN_INFO "The process is \"%s\" (pid %i)\n", current->comm, current->pid);
本以为可以直接发现是某个我们自己写的进程调用,结果是system_server就有点麻烦了。不过还有其他办法,既然是通过ioctl
调用,那么系统里面肯定哪里会有USBDEVFS_DISCONNECT
调用代码。
调试系统
在Android系统代码里面搜索USBDEVFS_DISCONNECT
在system/core/libusbhost/usbhost.c/里面搜到如下代码
int usb_device_connect_kernel_driver(struct usb_device *device,
unsigned int interface, int connect)
{
struct usbdevfs_ioctl ctl;
ctl.ifno = interface;
ctl.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT);
ctl.data = NULL;
return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
}
好,找都调用函数了,再继续找调用函数 base/core/jni/android_hardware_UsbDeviceConnection.cpp中
static jboolean
android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz,
int interfaceID, jboolean force)
{
struct usb_device* device = get_device_from_object(env, thiz);
if (!device) {
ALOGE("device is closed in native_claim_interface");
return -1;
}
int ret = usb_device_claim_interface(device, interfaceID);
if (ret && force && errno == EBUSY) {
// disconnect kernel driver and try again
usb_device_connect_kernel_driver(device, interfaceID, false);
ret = usb_device_claim_interface(device, interfaceID);
}
return ret == 0;
}
对应的native方法是native_claim_interface,再看下哪里被调用
public boolean claimInterface(UsbInterface intf, boolean force) {
return native_claim_interface(intf.getId(), force);
}
这个是系统对外的借口,搜索中发现是我们系统中间件调用了这个接口。
由于中间件是想获取iPhone的信息,当调用
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
if (deviceIterator.hasNext()) {
HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
UsbDevice device = (UsbDevice) deviceIterator.next();
}
if语句下面获得的第一个设备是优盘,当调用connection.claimInterface(intf, true)
时,从上面的jni函数可以知道此时优盘因为在播放音乐会返回EBUSY
,然后再调用usb_device_connect_kernel_driver(device, interfaceID, false)
就不把优盘整掉线了。
参考资料
https://blog.csdn.net/encourage2011/article/details/76407232 https://blog.csdn.net/u014742281/article/details/89328518 https://www.veryarm.com/57647.html base/core/jni/android_hardware_UsbDeviceConnection.cpp android_hardware_UsbDeviceConnection_claim_interface