Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

记录车机先插u盘再插iPhone,u盘会掉的问题 #8

Open
jason--liu opened this issue Jun 21, 2019 · 0 comments
Open

记录车机先插u盘再插iPhone,u盘会掉的问题 #8

jason--liu opened this issue Jun 21, 2019 · 0 comments
Labels

Comments

@jason--liu
Copy link
Owner

jason--liu commented Jun 21, 2019

这个问题很坑,走了不少弯路,在此记录一下。
背景:
在车机上先插入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 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant