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


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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,049评论 25 707
  • USB设备驱动程序用来驱动相应的USB设备,USB设备驱动用usb_driver表示,它主要用来将USB设备挂接到...
    Joe_HUST阅读 5,976评论 1 5
  • 1:InputChannel提供函数创建底层的Pipe对象 2: 1)客户端需要新建窗口 2)new ViewRo...
    自由人是工程师阅读 5,199评论 0 18
  • 初识燕洵,眼里心里满是惊艳。 翩翩少年,鲜衣怒马,眉梢眼角都写着意气风发,像极了耀眼的光芒,直击心脏。 此时的燕洵...
    橘溟阅读 493评论 0 10
  • "简单"做些回应: 1很可能你没有认真读文章吧(也难怪毕竟写得又臭又长)。我太赞同你的观点了: 转发不等于救命,善...
    楷歌Kale阅读 259评论 0 1