Android Usb源码分析

      • android上usb设备接入,拔出, 读写操作过程分析
          • a. usb设备插入,如何组成usbdevice. 存放在UsbManager.devicesList.
          • b. usbManager open device 获取usbConnect
          • c. usbConnect如何claimInterface.
          • d. bulk/control/interrupt收发数据.
            • bulk传输:
          • e. hal层代码分析.

android上usb设备接入,拔出, 读写操作过程分析

a. usb设备插入,如何组成usbdevice. 存放在UsbManager.devicesList.

从两个角度来看
1, 从设备插入后, kernel端怎么处理.
usb设备插入后host端如何获取该设备信息呢?
分析:

当usb设备接入时, 会有硬件产生中断. 收到中断后host端会由总线驱动程序根据usb协议, 对端口0地址发送一个请求包给usb设备.
2. 设备收到请求后会将自己的设备描述符信息发给host端.
3. host端通过解析设备描述符来获取usb设备信息, 同时找到对应的设备驱动, 调用其prob函数.
在linux 4.4.103上代码跟踪如下:
drivers/usb/core/hub.c
hub_irq(struct urb *urb)
|-kick_hub_wq(struct usb_hub *hub)
|-queue_work(hub_wq, &hub->events)
hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|-INIT_WORK(&hub->events, hub_event);
|-hub_event(struct work_struct *work)
|–port_event(struct usb_hub *hub, int port1)
|—hub_port_connect_change(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange)
|----hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,u16 portchange)
|-----udev = usb_alloc_dev(hdev, hdev->bus, port1);
|-----hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,int retry_counter)
|------usb_control_msg()
|------hub_set_address(udev, devnum);
|------usb_get_device_descriptor(udev, 8);

|-----hcd->driver->update_device(hcd, udev);
未完待续…

2, 从调用角度来跟踪.

获取后又是如何将改设备信息组成usbdevice对象存放在deviceslist?
反过来跟踪代码, 从调用端看.
|-UsbManager#getDeviceList();
|–mService.getDeviceList(bundle);
|—UsbServer#getDeviceList(Bundle devices)
|----UsbHostManager#getDeviceList(Bundle devices)
从全局变量HashMap mDevices取出数据存入Bundle.
而更新mDevices数据由底层jni函数调用
/* Called from JNI in monitorUsbHostBus() to finish adding a new device /
@SuppressWarnings(“unused”)
private void endUsbDeviceAdded()
看注释可以发现,底层jni会分别调用如下函数来晚上devices信息.
/
Called from JNI in monitorUsbHostBus() to report new USB devices
Returns true if successful, in which case the JNI code will continue adding configurations,
interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
have been processed
*/

现在我们需要跟踪一下JNI层beginUsbDeviceAdded和adding configurations, interfaces and endpoints和endUsbDeviceAdded
分别是在什么时候调用的
jni的调用来自于com_android_server_UsbHostManager.cpp base\services\core\jni 中
usb_device_added分别调用了
|–method_beginUsbDeviceAdded
|–method_addUsbConfiguration
|–method_addUsbInterface
|–method_addUsbEndpoint
|–method_endUsbDeviceAdded

而这个函数由java端调用.

static const JNINativeMethod method_table[] = {    { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus },    { "nativeOpenDevice",  "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",                                  (void*)android_server_UsbHostManager_openDevice },};>UsbHostManager里 public void systemReady() {        synchronized (mLock) {            // Create a thread to call into native code to wait for USB host events.            // This thread will call us back on usbDeviceAdded and usbDeviceRemoved.            Runnable runnable = this::monitorUsbHostBus;            new Thread(null, runnable, "UsbService host thread").start();        }    }>systemReady调用来自于UsbService的Lifecycle/SystemService> @Override        public void onBootPhase(int phase) {            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {                mUsbService.systemReady();            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {                mUsbService.bootCompleted();            }        }

所以操作又重新回到com_android_server_UsbHostManager.cpp中

static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv* /* env */, jobject thiz){    struct usb_host_context* context = usb_host_init();    if (!context) {        ALOGE("usb_host_init failed");        return;    }    // this will never return so it is safe to pass thiz directly    usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz);}跟踪一下usb_host_run>system/core/libusbhost/usbhost.cvoid usb_host_run(struct usb_host_context *context,                  usb_device_added_cb added_cb,                  usb_device_removed_cb removed_cb,                  usb_discovery_done_cb discovery_done_cb,                  void *client_data){    int done;    done = usb_host_load(context, added_cb, removed_cb, discovery_done_cb, client_data);    while (!done) {        done = usb_host_read_event(context);    }} /* usb_host_run() */在循环中轮询读取事件int usb_host_read_event(struct usb_host_context *context)就是read在init中初始化的fdstruct usb_host_context *usb_host_init(){    struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context));    if (!context) {        fprintf(stderr, "out of memory in usb_host_context\n");        return NULL;    }    context->fd = inotify_init();    if (context->fd < 0) {        fprintf(stderr, "inotify_init failed\n");        free(context);        return NULL;    }    return context;}

这里就涉及到了linux的inotify.
可以看usb_host_load中添加了监听目录

/* watch the root for new subdirectories */context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE);

也就是说当底层kernel收到usb设备插入后在/dev目录下创建了设备节点或者usb设备拔出后删除了设备节点.
都会被监听到.
从而通过jni层通知到java层.

这里我们只是获取了通过inotify我们只是获取到了设备的挂载的路径. 而真正解析设备信息, 获取相关设备描述符则需要回到
com_android_server_UsbHostManager.cpp base\services\core\jni
usb_device_added(const char devname, void client_data)
struct usb_device device = usb_device_open(devname);
const usb_device_descriptor
deviceDesc = usb_device_get_device_descriptor(device);
在usb_device_open里, 直接open(fname)来open设备节点.
open成功后通过usb_device_new(dev_name, fd);来获取一个usb_device的结构体.
而描述符信息是直接通过length = read(fd, device->desc, sizeof(device->desc));读取4096个字节来填充.
具体的描述符信息是怎么添加的 ,需要看kernel层的处理.

b. usbManager open device 获取usbConnect

UsbManager#openDevice
/-ParcelFileDescriptor pfd = mService.openDevice(deviceName);
|-UsbService#openDevice
/-fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt));
|-UsbHostManager#openDevice
/-nativeOpenDevice(deviceName);
调用到JNI层com_android_server_UsbHostManager.cpp base\services\core\jni
static const JNINativeMethod method_table[] = {
{ “monitorUsbHostBus”, “()V”, (void*)android_server_UsbHostManager_monitorUsbHostBus },
{ “nativeOpenDevice”, “(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;”,
(void*)android_server_UsbHostManager_openDevice },
};
|-android_server_UsbHostManager_openDevice
/-usb_device_open
/–usb_device_new
同样,通过open函数对指定文件名(设备挂载路径)来打开设备, 通过usb_device_new将设备信息放入usb_device结构体中返回
open操作完后回到UsbManager中.
|-UsbDeviceConnection connection = new UsbDeviceConnection(device);
|-boolean result = connection.open(deviceName, pfd, mContext);
/-native_open
上一步open获取的pfd用来给到connection的open, 调用到底层的native_open
找到对应的cpp文件android_hardware_UsbDeviceConnection.cpp base\core\jni
映射数组如下:

static const JNINativeMethod method_table[] = {    {"native_open",             "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",                                        (void *)android_hardware_UsbDeviceConnection_open},    {"native_close",            "()V",  (void *)android_hardware_UsbDeviceConnection_close},    {"native_get_fd",           "()I",  (void *)android_hardware_UsbDeviceConnection_get_fd},    {"native_get_desc",         "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc},    {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},    {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},    {"native_set_interface","(II)Z",    (void *)android_hardware_UsbDeviceConnection_set_interface},    {"native_set_configuration","(I)Z", (void *)android_hardware_UsbDeviceConnection_set_configuration},    {"native_control_request",  "(IIII[BIII)I",                                        (void *)android_hardware_UsbDeviceConnection_control_request},    {"native_bulk_request",     "(I[BIII)I",                                        (void *)android_hardware_UsbDeviceConnection_bulk_request},    {"native_request_wait",             "(J)Landroid/hardware/usb/UsbRequest;",                                        (void *)android_hardware_UsbDeviceConnection_request_wait},    { "native_get_serial",      "()Ljava/lang/String;",                                        (void*)android_hardware_UsbDeviceConnection_get_serial },    {"native_reset_device","()Z", (void *)android_hardware_UsbDeviceConnection_reset_device},};

来看对应的android_hardware_UsbDeviceConnection_open函数
最终也调用了UsbHost.c里的usb_device_new函数, 好像和之前操作有点重复 , 不清楚为什么

c. usbConnect如何claimInterface.

接着上面通过connection open操作之后 , 我们需要claimInterface 来确保有权限对指定interface进行操作.
那就调用到了jni的native_claim_interface, 也就是android_hardware_UsbDeviceConnection.cpp base\core\jni中

static const JNINativeMethod method_table[] = {...    {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},...};调用int ret = usb_device_claim_interface(device, interfaceID);int usb_device_claim_interface(struct usb_device *device, unsigned int interface){    return ioctl(device->fd, USBDEVFS_CLAIMINTERFACE, &interface);}

最后调用到ioctl来和kernel通信.
进到/kernel/driver/ 执行grep -rn “USBDEVFS_CLAIMINTERFACE” 看下会调用到哪里.

usb/core/devio.c:2306: case USBDEVFS_CLAIMINTERFACE:
可以发现跑到devio.c中进行处理.

看文件开头注释来大概了解一下这个文件的作用.

devio.c – User space communication with USB devices.
This file implements the usbfs/x/y files, where
x is the bus number and y the device number.
It allows user space programs/“drivers” to communicate directly
with USB devices without intervening kernel driver.
嗯 , 也就是免驱动直接和usb设备进行交互

我们来看ioctl调用到的地方

/* * NOTE:  All requests here that have interface numbers as parameters * are assuming that somehow the configuration has been prevented from * changing.  But there's no mechanism to ensure that... */static long usbdev_do_ioctl(struct file *file, unsigned int cmd,void __user *p){...case USBDEVFS_CLAIMINTERFACE:        snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__);        ret = proc_claiminterface(ps, p);        break;...}static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg){        unsigned int ifnum;        if (get_user(ifnum, (unsigned int __user *)arg))                return -EFAULT;        return claimintf(ps, ifnum);}static int claimintf(struct usb_dev_state *ps, unsigned int ifnum){        struct usb_device *dev = ps->dev;        struct usb_interface *intf;        int err;        if (ifnum >= 8*sizeof(ps->ifclaimed))                return -EINVAL;        /* already claimed */        if (test_bit(ifnum, &ps->ifclaimed))                return 0;        intf = usb_ifnum_to_if(dev, ifnum);        if (!intf)                err = -ENOENT;        else                err = usb_driver_claim_interface(&usbfs_driver, intf, ps);        if (err == 0)                set_bit(ifnum, &ps->ifclaimed);        return err;}

后面就是
usb_driver_claim_interface - bind a driver to an interface
device_bind_driver - bind a driver to one device.
/-driver_sysfs_add
/-driver_bound
这里的几个函数就不是很理解了 , 后面再来跟进.

d. bulk/control/interrupt收发数据.

现在来看看数据读写都是怎么操作的.

bulk传输:

也是从connection开始
|-UsbDeviceConnection#bulkTransfer
/-native_bulk_request
通过jni调用到android_hardware_UsbDeviceConnection.cpp base\core\jni

static const JNINativeMethod method_table[] = {  ...    {"native_bulk_request",     "(I[BIII)I",                                        (void *)android_hardware_UsbDeviceConnection_bulk_request},   ...};

需要注意的一点是bulk是支持双向传输的 , 可以通过bulk接受数据,可以发送数据,但都通过同一个接口来操作.
想要区分是发送还是接受数据, 则有传入端点类型参数来区分, 如果端点是out类型则表示是发送数据, 如果是in则是接受数据.
到了native层则是拿到端点的address来区分.

通过上面的调用, 则会调用到usbhost.c E:\storage\si\android_fw_8.1\system\core\libusbhost

int usb_device_bulk_transfer(struct usb_device *device,                            int endpoint,                            void* buffer,                            int length,                            unsigned int timeout){    struct usbdevfs_bulktransfer  ctrl;    // need to limit request size to avoid EINVAL    if (length > MAX_USBFS_BUFFER_SIZE)        length = MAX_USBFS_BUFFER_SIZE;    memset(&ctrl, 0, sizeof(ctrl));    ctrl.ep = endpoint;    ctrl.len = length;    ctrl.data = buffer;    ctrl.timeout = timeout;    return ioctl(device->fd, USBDEVFS_BULK, &ctrl);}

又通过ioctl调用到kernel层.

devio.c kernel/drivers/usb/core

static long usbdev_do_ioctl(struct file *file, unsigned int cmd,void __user *p){...case USBDEVFS_BULK:snoop(&dev->dev, "%s: BULK\n", __func__);ret = proc_bulk(ps, p);if (ret >= 0)inode->i_mtime = CURRENT_TIME;break;...}static int proc_bulk(struct usb_dev_state *ps, void __user *arg){struct usb_device *dev = ps->dev;struct usbdevfs_bulktransfer bulk;unsigned int tmo, len1, pipe;int len2;unsigned char *tbuf;int i, ret;//将android层传入的数据拷贝到kernel层if (copy_from_user(&bulk, arg, sizeof(bulk)))return -EFAULT;ret = findintfep(ps->dev, bulk.ep);//看看当前endpoint在哪个interfaceif (ret < 0)return ret;ret = checkintf(ps, ret);//检查一下if (ret)return ret;if (bulk.ep & USB_DIR_IN) //根据endpoint地址来建立输入或者输出管道pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);elsepipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))return -EINVAL;len1 = bulk.len;if (len1 >= USBFS_XFER_MAX)return -EINVAL;ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));if (ret)return ret;tbuf = kmalloc(len1, GFP_KERNEL);if (!tbuf) {ret = -ENOMEM;goto done;}tmo = bulk.timeout;if (bulk.ep & 0x80) {if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {ret = -EINVAL;goto done;}snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);usb_unlock_device(dev);i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);//bulk开始传输数据usb_lock_device(dev);snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);if (!i && len2) {if (copy_to_user(bulk.data, tbuf, len2)) {ret = -EFAULT;goto done;}}} else {if (len1) {if (copy_from_user(tbuf, bulk.data, len1)) {ret = -EFAULT;goto done;}}snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);usb_unlock_device(dev);i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);usb_lock_device(dev);snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);}ret = (i < 0 ? i : len2); done:kfree(tbuf);usbfs_decrease_memory_usage(len1 + sizeof(struct urb));return ret;}

主要关注usb_bulk_msg
message.c \kernel\drivers\usb\core
先来看看函数的注释

usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
@usb_dev: pointer to the usb device to send the message to
@pipe: endpoint “pipe” to send the message to
@data: pointer to the data to send
@len: length in bytes of the data to send
@actual_length: pointer to a location to put the actual length transferred
in bytes
@timeout: time in msecs to wait for the message to complete before
timing out (if 0 the wait is forever)

Context: !in_interrupt ()

This function sends a simple bulk message to a specified endpoint
and waits for the message to complete, or timeout.

Don’t use this function from within an interrupt context, like a bottom half
handler. If you need an asynchronous message, or need to send a message
from within interrupt context, use usb_submit_urb() If a thread in your
driver uses this call, make sure your disconnect() method can wait for it to
complete. Since you don’t have a handle on the URB used, you can’t cancel
the request.

Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl,
users are forced to abuse this routine by using it to submit URBs for
interrupt endpoints. We will take the liberty of creating an interrupt URB
(with the default interval) if the target is an interrupt endpoint.

Return:
If successful, 0. Otherwise a negative error number. The number of actual
bytes transferred will be stored in the @actual_length parameter.

函数作用就是: 构建一个urb(usb request block) , 发送出去, 然后等待它完成.

int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout){struct urb *urb;struct usb_host_endpoint *ep;ep = usb_pipe_endpoint(usb_dev, pipe);if (!ep || len < 0)return -EINVAL;urb = usb_alloc_urb(0, GFP_KERNEL);if (!urb)return -ENOMEM;//填充urb if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==USB_ENDPOINT_XFER_INT) {pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);usb_fill_int_urb(urb, usb_dev, pipe, data, len,usb_api_blocking_completion, NULL,ep->desc.bInterval);} elseusb_fill_bulk_urb(urb, usb_dev, pipe, data, len,usb_api_blocking_completion, NULL);return usb_start_wait_urb(urb, timeout, actual_length); //等待传输完成}|-usb_start_wait_urb|-usb_submit_urb\-usb_hcd_submit_urb调用到hcd.cE:\bash\source\kernel\drivers\usb\coreusb_hcd_submit_urbusbmon_urb_submit

可以看到应该调用到hcd部分了 , 应该是host controller driver.

e. hal层代码分析.

更多相关文章

  1. SQLite数据库总结
  2. Android连接SQLite数据库
  3. 从数据库中获取浏览器书签信息(Android Browser开发)
  4. JS判断设备终端(PC,iPad,iPhone,android,winPhone)和浏览器
  5. SQlite与android 的数据交互 (android 项目心得三)
  6. Android应用程序组件Content Provider在应用程序之间共享数据的
  7. [android]fmodex在某些android设备上声音延迟Latency
  8. android中清空一个表。类似truncate table 表名 这样的功能 andr
  9. Android8.1添加MTP数据同步操作

随机推荐

  1. [4.18]Android生命周期介绍
  2. android:launchMode="singleTask" 与 onN
  3. Android(安卓)service 实现过程
  4. Android(安卓)Rom签名文件的生成与签名
  5. android 暗码
  6. FAQ00366]如何使Android应用程序获取系统
  7. Android(安卓)-Recovery
  8. Android(安卓)RadioGroup设置默认选中项
  9. How-To: Install Google’s Android(安卓
  10. 关于android中Email未设置账户的情况下发