Android的USB系统简单分析之一

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


Android的USB系统简单分析之一_第1张图片

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系统简单分析之一)