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

更多相关文章

  1. android webview js不执行原因解析
  2. android组件之Service
  3. Android(安卓)集成TBS浏览文档,不调用手机内部app 查看,在自身查
  4. MVP模式
  5. 采用MQTT协议实现Android消息推送
  6. DialogFragment的使用总结
  7. Android中字符设备驱动和应用实例(一)——驱动部分
  8. Android(安卓)NestedScrolling 实战
  9. android Service深入详解

随机推荐

  1. Android在一个应用程序中启动另一个应用
  2. Android记事本NotePad应用功能拓展(五)
  3. Android错误之--Error retrieving parent
  4. Android(安卓)killer和Apktool回编译错误
  5. Oracle Android(安卓)Apps - 'Oracle Now
  6. android中读XML文件
  7. 2010.12.28(3)——— android alertDialo
  8. 使用adb shell dumpsys检测Android的Acti
  9. Android启动画面实现
  10. 2011.09.13(2)——— android 图标上面添加