USB Device的功能很丰富,其支持的协议越来越多包括:MTP、ADB、rndis、mass storage、accessory、audio_source、CDROOM等。
在代码中涉及到的目录主要有:
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总线协议。
我们常用到的有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。
在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.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.多用户和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。
当usb口作为host使用时,可以连接u盘,鼠标/键盘,usb音响等设备,针对不同的设备由不同的子系统来处理。
连接鼠标/键盘/手柄等输入设备时,这些外设被当成是输入设备,归输入子系统管理。设备节点在/dev/input下,输入事件由InputReader调用EventHub来读取,具体请看EventHub的分析。
外接usb音响等音频设备,这些外设被识别成音频设备,设备节点在/dev/snd/下,归音频系统管理。
连接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
网友评论