Android的USB系統(tǒng)簡(jiǎn)單分析之一

1.1PAD作為USB Device設(shè)備

USB Device的功能很豐富,其支持的協(xié)議越來(lái)越多包括:MTP、ADB、rndis、mass storage、accessory、audio_source、CDROOM等。

1.1.1代碼簡(jiǎn)單分析

在代碼中涉及到的目錄主要有:

1.frameworks/base/services/java/com/android/server/usb/? -----usbService.java用來(lái)管理usb協(xié)議,其通過(guò)property系統(tǒng)與init.xxx.usb.rc通訊。其中UsbDeviceManager.java以及HostManager.java分別管理device和host的設(shè)備。

2.init.xxx.usb.rc這里定義了所有usb device協(xié)議的組合。當(dāng)usb device的協(xié)議發(fā)生變化的時(shí)候,會(huì)設(shè)置sys.usb.config這個(gè)屬性,init.xxx.usb.rc中定義的某種組合會(huì)被觸發(fā),通過(guò)sys節(jié)點(diǎn)來(lái)通知kernel切換USB總線協(xié)議。

1.1.2常用協(xié)議切換

我們常用到的有device協(xié)議有ADB、MTP、PTP、MassStorage這幾個(gè),這些都是可以在Setting中開關(guān)或者是切換的。在切換協(xié)議的時(shí)候是調(diào)用UsbDeviceManager中的setCurrentFunctions(String functions, boolean makeDefault)最終設(shè)置sys.usb.config這個(gè)屬性,從而觸發(fā)init.xx.usb.rc去通知kernel切換usb協(xié)議。UsbDeviceManager.java中同時(shí)也監(jiān)聽(tīng)usb事件的uevent,并通過(guò)updateUsbState()發(fā)出UsbManager.ACTION_USB_STATE這個(gè)廣播來(lái)通知MtpReceiver和MountService。其中MtpReceiver負(fù)責(zé)根據(jù)所選擇的usb協(xié)議,啟動(dòng)或者關(guān)閉MtpService。

1.1.3Accessory模式

在accessory模式下,PAD是作為Device設(shè)備的,通常需要一個(gè)支持Accessory的Host設(shè)備(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。這里面模擬了一個(gè)Host端的設(shè)備。其思路是調(diào)用system/core/libusbhost/usbhost.c中的usb_host_run()函數(shù),這個(gè)函數(shù)的主要作用就是去監(jiān)控/dev/bus/usb/這個(gè)目錄。

調(diào)用如下接口去查詢/dev/bus/usb其中的設(shè)備是否支持accessory協(xié)議

usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,

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

如果支持就調(diào)用如下接口嘗試將其切換到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這個(gè)ioctl后(其實(shí)是由usb中斷傳遞上來(lái)的)就會(huì)發(fā)送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后調(diào)用startAccessoryMode();--->setCurrentFunctions(xxx)-->設(shè)置sys.usb.config這個(gè)屬性后,就觸發(fā)init.xxx.usb.rc去通知kernel切換到accessory模式。

1.1.4Mass_Storage模式

幾個(gè)重要代碼點(diǎn):

1.UsbDeviceManager監(jiān)聽(tīng)DEVPATH=/devices/virtual/android_usb/android0"這個(gè)路徑的UEVENT,

在收到狀態(tài)改變的時(shí)候會(huì)發(fā)出UsbManager.ACTION_USB_STATE這個(gè)broadcast。其中包含connect,configuration狀態(tài)以及當(dāng)前的usb配置的function。

2.在MountService收到ACTION_USB_STATE這個(gè)廣播的時(shí)候,notifyShareAvailabilityChange()會(huì)調(diào)用所有注冊(cè)的listener的bl.mListener.onUsbMassStorageConnectionChanged(avail);

同時(shí)在這里還要處理usb拔出的事件,這里必須把已經(jīng)shared的盤重新Mount回系統(tǒng)中。

3.StorageManager向Mountservice注冊(cè)了listener,其他應(yīng)用又向StorageManager注冊(cè)listener

主要有如下地方:

UsbStorageActivity.java ---UMS開關(guān)界面UI切換

StorageNotification.java----實(shí)現(xiàn)狀態(tài)欄通知(在onUsbMassStorageConnectionChange()中實(shí)現(xiàn),這個(gè)函數(shù)中可以實(shí)現(xiàn)自動(dòng)彈出usbStorageActivity,關(guān)鍵字POP_UMS_ACTIVITY_ON_CONNECT)

TabletStatusBar.java---------向StorageManager注冊(cè)listener,用來(lái)顯示UMS狀態(tài)欄通知

MtpService.java--------------Mtp狀態(tài)變化

1.1.5目前SDK中的配置

幾種不能共存的配置:

1.多用戶和UMS不能共存

----谷歌默認(rèn)的方式是采用fuse將/data/media模擬成用戶盤,這種模式下支持多用戶,但是不能支持UMS。如果要支持UMS那么就不能使用fuse,需要?jiǎng)澇鯱SER分區(qū),通過(guò)Vold來(lái)管理。

目前Android4.4的SDK中通過(guò)BoradConfig.mk中的BUILD_WITH_UMS這個(gè)宏來(lái)在二者中切換。

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

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

2.CDROOM和UMS不能共存

----CDROOM和UMS在kernel中的實(shí)現(xiàn)是類似的,都往/sys/class/android_usb/f_mass_storage/lun/file中寫入內(nèi)容來(lái)與kernel通訊。

目前Android4.4的SDK中通過(guò)BoradConfig.mk中的BUILD_WITH_CDROM來(lái)控制是否打開CDROOM,BUILD_WITH_CDROM_PATH來(lái)設(shè)置iso的路徑。注意BUILD_WITH_UMS和BUILD_WITH_CDROM兩者應(yīng)該是互斥的,不能同時(shí)設(shè)置成true。

1.2PAD作為USB Host設(shè)備

當(dāng)usb口作為host使用時(shí),可以連接u盤,鼠標(biāo)/鍵盤,usb音響等設(shè)備,針對(duì)不同的設(shè)備由不同的子系統(tǒng)來(lái)處理。

1.2.1輸入設(shè)備

連接鼠標(biāo)/鍵盤/手柄等輸入設(shè)備時(shí),這些外設(shè)被當(dāng)成是輸入設(shè)備,歸輸入子系統(tǒng)管理。設(shè)備節(jié)點(diǎn)在/dev/input下,輸入事件由InputReader調(diào)用EventHub來(lái)讀取,具體請(qǐng)看EventHub的分析。

1.2.2音頻設(shè)備

外接usb音響等音頻設(shè)備,這些外設(shè)被識(shí)別成音頻設(shè)備,設(shè)備節(jié)點(diǎn)在/dev/snd/下,歸音頻系統(tǒng)管理。

1.2.3塊設(shè)備

連接usb存儲(chǔ)設(shè)備(u盤,硬盤等)時(shí),設(shè)備節(jié)點(diǎn)在/dev/bus/usb下,由UsbHostManager.java來(lái)管理,簡(jiǎn)單分析如下:

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

2)frameworks/base/services/java/com/android/server/usb/UsbHostManager.java的systemReady中啟動(dòng)一個(gè)線程來(lái)運(yùn)行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);

}

其中分別調(diào)用到了system/core/libusbhost/usbhost.c中的usb_host_init(...)和usb_host_run(...)

在usb_host_init()中,最主要的是初始化context->fd = inotify_init();,這個(gè)會(huì)在后面用來(lái)監(jiān)聽(tīng)/dev/bus/usb目錄的創(chuàng)建和刪除在usb_host_run中,主要是添加監(jiān)控的目錄ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);如果發(fā)現(xiàn)目錄有create或者是delete操作,通知回調(diào)函數(shù).

3)在usb_device_added()中,主要是獲取usb設(shè)備的屬性,然后調(diào)用UsbHostManager.java中的usbDeviceAdded(),并將這些usb屬性傳遞上去

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

deviceSubClass, protocol, interfaceArray, endpointArray);

4)在UsbHostManager.java中的usbDeviceAdded()中,主要是創(chuàng)建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()函數(shù),主要是檢查系統(tǒng)中是否有安裝能處理UsbManager.ACTION_USB_DEVICE_ATTACHED這個(gè)廣播的activity,并轉(zhuǎn)到該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設(shè)備通信的接口

struct usb_device *usb_device_open(const char *dev_name) ---打開一個(gè)usb設(shè)備,在/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一個(gè)interface用于通訊

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

int usb_device_bulk_transfer(struct usb_device *device, --------傳輸數(shù)據(jù)

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代碼中可以通過(guò)一下文件中提供的接口來(lái)訪問(wèn)usb設(shè)備。

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容