Android的USB系统简单分析之一

作者: android之子 | 来源:发表于2017-08-28 09:39 被阅读545次

    1.1PAD作为USB Device设备

    USB Device的功能很丰富,其支持的协议越来越多包括:MTP、ADB、rndis、mass storage、accessory、audio_source、CDROOM等。

    1.1.1代码简单分析

    在代码中涉及到的目录主要有:

    1.frameworks/base/services/java/com/android/server/usb/  -----usbService.java用来管理usb协议,其通过property系统与init.xxx.usb.rc通讯。其中UsbDeviceManager.java以及HostManager.java分别管理device和host的设备。

    2.init.xxx.usb.rc这里定义了所有usb device协议的组合。当usb device的协议发生变化的时候,会设置sys.usb.config这个属性,init.xxx.usb.rc中定义的某种组合会被触发,通过sys节点来通知kernel切换USB总线协议。

    1.1.2常用协议切换

    我们常用到的有device协议有ADB、MTP、PTP、MassStorage这几个,这些都是可以在Setting中开关或者是切换的。在切换协议的时候是调用UsbDeviceManager中的setCurrentFunctions(String functions, boolean makeDefault)最终设置sys.usb.config这个属性,从而触发init.xx.usb.rc去通知kernel切换usb协议。UsbDeviceManager.java中同时也监听usb事件的uevent,并通过updateUsbState()发出UsbManager.ACTION_USB_STATE这个广播来通知MtpReceiver和MountService。其中MtpReceiver负责根据所选择的usb协议,启动或者关闭MtpService。

    1.1.3Accessory模式

    在accessory模式下,PAD是作为Device设备的,通常需要一个支持Accessory的Host设备(ADK2012等)配合才能工作,可以参考如下谷歌文档:

    http://developer.android.com/guide/topics/connectivity/usb/index.html

    http://developer.android.com/guide/topics/connectivity/usb/accessory.html

    http://developer.android.com/guide/topics/connectivity/usb/host.html

    Accessory模式下Host端代码可以参考cts/apps/cts-usb-accessory/cts-usb-accessory.c。这里面模拟了一个Host端的设备。其思路是调用system/core/libusbhost/usbhost.c中的usb_host_run()函数,这个函数的主要作用就是去监控/dev/bus/usb/这个目录。

    调用如下接口去查询/dev/bus/usb其中的设备是否支持accessory协议

    usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,

    ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0);

    如果支持就调用如下接口尝试将其切换到accessory模式。

    usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,ACCESSORY_START, 0, 0, 0, 0, 0);

    Accessory模式下Device端的代码分析:

    drivers/usb/gadget/f_accessory.c中收到ACCESSORY_START这个ioctl后(其实是由usb中断传递上来的)就会发送ACCESSORY=START的uevent。

    static void acc_work(struct work_struct *data)

    {

      char *envp[2] = { "ACCESSORY=START", NULL };

      kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp);

    }

    frameworks/base/services/java/com/android/server/usb/UsbDeviceManager.java中,接收到uevent后调用startAccessoryMode();--->setCurrentFunctions(xxx)-->设置sys.usb.config这个属性后,就触发init.xxx.usb.rc去通知kernel切换到accessory模式。

    1.1.4Mass_Storage模式

    几个重要代码点:

    1.UsbDeviceManager监听DEVPATH=/devices/virtual/android_usb/android0"这个路径的UEVENT,

    在收到状态改变的时候会发出UsbManager.ACTION_USB_STATE这个broadcast。其中包含connect,configuration状态以及当前的usb配置的function。

    2.在MountService收到ACTION_USB_STATE这个广播的时候,notifyShareAvailabilityChange()会调用所有注册的listener的bl.mListener.onUsbMassStorageConnectionChanged(avail);

    同时在这里还要处理usb拔出的事件,这里必须把已经shared的盘重新Mount回系统中。

    3.StorageManager向Mountservice注册了listener,其他应用又向StorageManager注册listener

    主要有如下地方:

    UsbStorageActivity.java ---UMS开关界面UI切换

    StorageNotification.java----实现状态栏通知(在onUsbMassStorageConnectionChange()中实现,这个函数中可以实现自动弹出usbStorageActivity,关键字POP_UMS_ACTIVITY_ON_CONNECT)

    TabletStatusBar.java---------向StorageManager注册listener,用来显示UMS状态栏通知

    MtpService.java--------------Mtp状态变化

    1.1.5目前SDK中的配置

    几种不能共存的配置:

    1.多用户和UMS不能共存

    ----谷歌默认的方式是采用fuse将/data/media模拟成用户盘,这种模式下支持多用户,但是不能支持UMS。如果要支持UMS那么就不能使用fuse,需要划出USER分区,通过Vold来管理。

    目前Android4.4的SDK中通过BoradConfig.mk中的BUILD_WITH_UMS这个宏来在二者中切换。

    BUILD_WITH_UMS = true即支持UMS不支持多用户

    BUILD_WITH_UMS = false即支持多用户但是不支持UMS

    2.CDROOM和UMS不能共存

    ----CDROOM和UMS在kernel中的实现是类似的,都往/sys/class/android_usb/f_mass_storage/lun/file中写入内容来与kernel通讯。

    目前Android4.4的SDK中通过BoradConfig.mk中的BUILD_WITH_CDROM来控制是否打开CDROOM,BUILD_WITH_CDROM_PATH来设置iso的路径。注意BUILD_WITH_UMS和BUILD_WITH_CDROM两者应该是互斥的,不能同时设置成true。

    1.2PAD作为USB Host设备

    当usb口作为host使用时,可以连接u盘,鼠标/键盘,usb音响等设备,针对不同的设备由不同的子系统来处理。

    1.2.1输入设备

    连接鼠标/键盘/手柄等输入设备时,这些外设被当成是输入设备,归输入子系统管理。设备节点在/dev/input下,输入事件由InputReader调用EventHub来读取,具体请看EventHub的分析。

    1.2.2音频设备

    外接usb音响等音频设备,这些外设被识别成音频设备,设备节点在/dev/snd/下,归音频系统管理。

    1.2.3块设备

    连接usb存储设备(u盘,硬盘等)时,设备节点在/dev/bus/usb下,由UsbHostManager.java来管理,简单分析如下:

    1)frameworks/base/services/java/com/android/server/usb/UsbService.java中的systemReady()调用mHostManager.systemReady()。

    2)frameworks/base/services/java/com/android/server/usb/UsbHostManager.java的systemReady中启动一个线程来运行monitorUsbHostBus();

    frameworks/base/services/jni/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);

    }

    其中分别调用到了system/core/libusbhost/usbhost.c中的usb_host_init(...)和usb_host_run(...)

    在usb_host_init()中,最主要的是初始化context->fd = inotify_init();,这个会在后面用来监听/dev/bus/usb目录的创建和删除在usb_host_run中,主要是添加监控的目录ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);如果发现目录有create或者是delete操作,通知回调函数.

    3)在usb_device_added()中,主要是获取usb设备的属性,然后调用UsbHostManager.java中的usbDeviceAdded(),并将这些usb属性传递上去

    env->CallVoidMethod(thiz, method_usbDeviceAdded,deviceName, vendorId, productId, deviceClass,

    deviceSubClass, protocol, interfaceArray, endpointArray);

    4)在UsbHostManager.java中的usbDeviceAdded()中,主要是创建UsbDevice,如下:

    UsbDevice device = new UsbDevice(deviceName, vendorID, productID,deviceClass, deviceSubclass, deviceProtocol, interfaces);

    mDevices.put(deviceName, device);

    mSettingsManager.deviceAttached(device);

    5)frameworks/base/services/java/com/android/server/usb/UsbSettingsManager.java中的deviceAttached()函数,主要是检查系统中是否有安装能处理UsbManager.ACTION_USB_DEVICE_ATTACHED这个广播的activity,并转到该activity.

    public void deviceAttached(UsbDevice device) {

    Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);

    intent.putExtra(UsbManager.EXTRA_DEVICE, device);

    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    ArrayList matches;

    String defaultPackage;

    synchronized (mLock) {

    matches = getDeviceMatchesLocked(device, intent);

    // Launch our default activity directly, if we have one.

    // Otherwise we will start the UsbResolverActivity to allow the user to choose.

    defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));

    }

    resolveActivity(intent, matches, defaultPackage, device, null);

    }

    1.2.4libusbhost

    libusbhost主要提供与usb设备通信的接口

    struct usb_device *usb_device_open(const char *dev_name) ---打开一个usb设备,在/dev/bus/usb/下

    void usb_device_close(struct usb_device *device)

    void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter)

    struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter) --获取descriptor

    int usb_device_claim_interface(struct usb_device *device, unsigned int interface) ----claim一个interface用于通讯

    int usb_device_release_interface(struct usb_device *device, unsigned int interface)

    int usb_device_bulk_transfer(struct usb_device *device, --------传输数据

    int endpoint,

    void* buffer,

    int length,

    unsigned int timeout)

    int usb_device_control_transfer(struct usb_device *device, ----------控制指令

    int requestType,

    int request,

    int value,

    int index,

    void* buffer,

    int length,

    unsigned int timeout)

    在java代码中可以通过一下文件中提供的接口来访问usb设备。

    frameworks/base/core/java/android/hardware/usb/UsbManager.java

    frameworks/base/core/java/android/hardware/usb/UsbDeviceConnection.java

    相关文章

      网友评论

        本文标题:Android的USB系统简单分析之一

        本文链接:https://www.haomeiwen.com/subject/khywdxtx.html