USB 主機和配件概覽Android 通過 USB 配件和 USB 主機兩種模式支持各種 USB 外圍設備和 Android USB 配件(實現 Android 配件協議的硬件)。在 USB 配件模式下,外部 USB 硬件充當 USB 主機。配件示例可能包括機器人控制器、擴展塢、診斷和音樂設備、自助服務終端、讀卡器等等。這樣,不具備主機功能的 Android 設備就能夠與 USB 硬件互動。
USB 主機和配件概覽
Android 通過 USB 配件和 USB 主機兩種模式支持各種 USB 外圍設備和 Android USB 配件(實現 Android 配件協議的硬件)。在 USB 配件模式下,外部 USB 硬件充當 USB 主機。配件示例可能包括機器人控制器、擴展塢、診斷和音樂設備、自助服務終端、讀卡器等等。這樣,不具備主機功能的 Android 設備就能夠與 USB 硬件互動。Android USB 配件必須設計為與 Android 設備兼容,并且必須遵守 Android 配件通信協議。在 USB 主機模式下,Android 設備充當主機。設備示例包括數碼相機、鍵盤、鼠標和游戲控制器。針對各類應用和環境設計的 USB 設備仍可與能夠與設備正常通信的 Android 應用互動。
下圖展示了這兩種模式之間的差異。當 Android 設備處于主機模式時,它會充當 USB 主機并為總線供電。當 Android 設備處于 USB 配件模式時,所連接的 USB 硬件(本例中為 Android USB 配件)充當主機并為總線供電。
Android 3.1(API 級別 12)或更高版本的平臺直接支持 USB 配件和主機模式。USB 配件模式還作為插件庫向后移植到 Android 2.3.4(API 級別 10)中,以支持更廣泛的設備。設備制造商可以選擇是否在設備的系統映像中添加該插件庫。
注意:配件模式取決于設備硬件;部分設備可能不支持配件模式。您可以在相應應用的 Android 清單中使用 元素過濾出支持配件模式的設備。
Android 開放配件 (AOA)
Android 開放配件 (AOA) 支持功能可讓外部 USB 硬件(Android USB 配件)與處于配件模式下的 Android 設備進行交互。當某臺 Android 設備處于配件模式時,所連接的配件會充當 USB 主機(為總線供電并列舉設備),而 Android 設備則充當 USB 配件。
Android USB 配件專門用于和 Android 設備相連。這些配件遵循 AOA 要求,從而能夠檢測到支持配件模式的 Android 設備,并且必須提供 500 毫安(電壓為 5 伏)的充電電流。之前發布的部分 Android 設備只能充當 USB 設備,無法發起與外部 USB 設備的連接。AOA 支持功能打破了這一局限,讓您能夠構建可以與各種 Android 設備建立連接并與其進行交互的配件。
AOA 設備握手過程
AOA 協議規定 Android 設備和配件之間握手的大致過程如下:
(1)通過 USB 線連接 Android 設備與配件。
(2)配件枚舉連接過來的設備。根據 VID 和 PID 判斷當前 Android 設備是否處于 Accessory Mode。如果否,則配件會向 Android 設備發出切換到 AOA 模式的請求,進入第(3)步; 如果是,則直接調轉到第(5)步。
判斷 Android 設備處于 Accessory Mode 時,VID 和 PID 值必須滿足如下條件如下:
VID | 模式 |
---|---|
0X18D1 | |
PID | 模式 |
0x2D00 | accessory |
0x2D01 | accessory + adb |
0x2D02 | audio |
0x2D03 | audio + adb |
0x2D04 | accessory + audio |
0x2D05 | accessory + audio + adb |
(3)配件發送查詢指令給 Android 設備。絕大多數 Android 設備,在缺省情況下都不掛載Accessory 驅動,即不會默認處于 Accessory Mode,在配件與 Android 設備建立 USB 連接時,配件會通過握手協議查詢該設備是否為Android 設備且是否支持 AOA 協議以及支持的版本號。配件向 endpoint 0 端口中寫入 51 號指令,如果返回值為1 或者 2,則說明Android 設備支持 AOA1.0 或者 AOA2.0,如果小于 1 或者大于 2,則說明連接設備不支持AOA協議或者支持的 AOA 協議版本號不正確。
(4) Android 配件發送認證信息給 Android 設備,并發送開始通信的指令。認證信息可以包含以下屬性:manufacturer(廠商)、model(型號)、version(版本)、description(描述信息)、URL(Web頁面)。
配件也會向Android設備發出53號指令,請求Android設備切換到AOA模式,Android 設備會執行請求,將 USB 切換到 AOA 模式;在這個過程中,USB 連接會出現一次邏輯插拔,配件會重新枚舉設備,進入第(2)步。Android 設備接收到配件通過 52 指令發送過來的參數信息以后,使用其中的三個參數 Manufacturer、Model 、Version 來確定綁定到該配件的 App。如果系統內無任何 App 可以匹配配件設備發來的上述三個參數,則 Android 設備會彈出一個對話框,向用戶提供 Accessory 設備發送過來的描述信息和 URL 信息,用戶可以點擊 URL 訪問它指向的 Web 頁面。
如果系統內有 App 可以匹配 Accessory 設備發來的握手信息,則 Android 系統會彈出一個對話框詢問用戶是否立刻啟動該 App。如果用戶選擇 OK 則啟動該App;同時該對話框提供一個勾選框,勾選之后每次 Accessory 設備連接后會自動啟動該 App。應該要求用戶勾選該對話框,否則 App 啟動后向 USB Manager獲取 Accessory 設備后可能因為 Permission 問題無法打開文件描述符建立通訊連接。
(5)建立連接
指令 | 作用 |
---|---|
51 | 判斷設備是否支持 AOA 協議,并獲取支持 AOA 協議的版本號。 |
52 | 發送配件相關設備認證信息,Android 設備可 以據此來確定綁定到該配件的 APP。 |
53 | 請求 Android 設備切換到 Accessory Mode |
54~57 | HID支持功能 |
58 | 音頻支持( Android 8.0 中已被棄用) |
AOA 配件端開發
在Android車機或者Android平板開發中,以車機或平臺為配件端,與Android手機通過數據線進行通信。
Android 官方是提供 USB 的相關接口用來進行 AOA 連接,主要有UsbManager, UsbDevice, UsbInterface, UsbDeviceConnection 等。具體參考官方文檔:USB 主機概覽
以下代碼段是執行同步數據傳輸的一種簡單方式:
private Byte[] bytes;private static int TIMEOUT = 0;private boolean forceClaim = true;...UsbInterface intf = device.getInterface(0);UsbEndpoint endpoint = intf.getEndpoint(0);UsbDeviceConnection connection = usbManager.openDevice(device);connection.claimInterface(intf, forceClaim);connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread
AOA 主機端開發
在與Android車機或Android平板USB通信過程中,手機作為主機端,默認不開啟配件模式,需要與配件建立AOA通信才會開啟啟動配件模式。
具體參考Google官方文檔:USB 配件模式
與配件通信代碼如下:
UsbAccessory accessory;ParcelFileDescriptor fileDescriptor;FileInputStream inputStream;FileOutputStream outputStream;...private void openAccessory() {Log.d(TAG, "openAccessory: " + accessory);fileDescriptor = usbManager.openAccessory(accessory);if (fileDescriptor != null) {FileDescriptor fd = fileDescriptor.getFileDescriptor();inputStream = new FileInputStream(fd);outputStream = new FileOutputStream(fd);Thread thread = new Thread(null, this, "AccessoryThread");thread.start();}}
----------------------------------------------------------------------------------------------------------------------------
Android 設備的USB 依據USB協議有多個接口(功能設備),多數 Android 設備中定義了 MTP 接口(功能設備),PTP接口 (功能設備)和 U 盤接口(功能設備),這些接口(功能設備)主要用來和 USB 主機傳輸媒體文件。
另外AOA 協議也為 Android 設備定義了一些接口選擇,通過設置不同的選項,可以與 USB 配件實現不同的功能。
AOA 協議定義了三種 USB 接口類型:
- ADB 接口:主要用來調試配件
- Accessory接口:用來交換數據
- Audio 接口:用來將音頻輸出到配件
AOA 協議將上述3種接口組合出6種 USB 接口層設備,這些USB設備的廠商 ID 統一為 0x18D1 (Google Inc),產品ID 如下圖
3. AOA標準請求
這部分可以解決第 2 個問題。
AOA 協議定義了標準控制請求包格式,如下圖所示:
USB 配件與 Android 設備建立連接主要通過 AOA 標準控制請求完成,這些標準請求通過控制端點 0 傳輸。
每個請求的請求號標識和功能如下,即request字段:
4. 配件連接流程
這部分可以解決第 3 個問題
4.1?USB枚舉
USB 配件物理連接到 Android設備之后,USB配件中的主機協議棧首先會來枚舉。枚舉將獲得 Android設備的USB 描述符信息。
4.2?根據枚舉得到的設備描述符來檢測 Android 設備是否處在配件模式
配件模式下的USB 設備描述符中的廠商 ID 應為 0x18D1,產品 ID 應為 0x2Dxx,即應該是AOA 協議定義的 6 種USB 設備類中的一種。只要廠商 ID 和產品 ID 符合條件,就確定 Android 設備處于配件模式,即可進行通信,如果 Android 設備不在配件模式下,則需要開啟配件模式。
4.3?開啟配件模式
- 如果 Android 設備未處于配件模式,則 USB 配件要發送 51 號請求來詢問 Android 設備是否支持 AOA 協議,如果返回非0值,說明支持 AOA 協議,這個值表示 AOA 協議版本號。
該標準請求格式如下所示:
requestType: USB_DIR_IN | USB_TYPE_VENDOR
request: 51
value: 0
index: 0
data: protocol version number (16 bits little endian sent from thedevice to the accessory)
- USB 配件獲得 AOA 版本號之后,USB 配件發送 52 號請求將驗證字符串信息發送給 Android 設備,這些字符串包括 USB 配件的制作商名稱、模型名稱、描述、版本、訪問配件的 URI 和 序列號,對應字符串的 ID 分別為 0、1、2、3、4、5,Android 設備收到這些字符串之后,會試圖找到與USB 配件對應的應用程序,如果沒有找到,Android 設備會 提供應用程序的URL提示安裝。
該標準請求格式如下所示:
requestType: USB_DIR_OUT | USB_TYPE_VENDOR
request: 52
value: 0
index: string ID
data zero terminated UTF8 string sent from accessory to device
其中string ID如下:
manufacturer name 廠商名稱: 0
model name 模型名稱: 1
description 描述: 2
version 版本: 3
URI: 4
serial number 序列號: 5
- USB配件發送完驗證字符串信息后,USB 配件發送 53 號控制命令來嘗試開啟配件模式,在這個過程中,Android 設備會修改 USB 設備描述符并復位觸發配件對總線進行再次枚舉。
該標準請求格式如下所示:
requestType: USB_DIR_OUT | USB_TYPE_VENDOR
request: 53
value: 0
index: 0
data: none
- 4.4?重新枚舉
Android 設備接收到 53 號請求之后,會自動復位 USB 總線,USB 配件重新枚舉,Android 設備會返回新的描述符信息,枚舉成功后,USB 配件獲得的設備描述符中 廠商 ID 和產品 ID 應為 AOA 協議中定義的一個。
4.5?開啟 HID 功能
如果 USB 配件需要 HID 功能,可以在與 Android 設備建立連接之后,發送 HID 控制請求給 Android 設備,這些請求仍然是通過端點 0 發送的。
到這里我也有幾個問題未解決:
- 當第二次枚舉的時候,Android 設備返回的描述符信息是怎么修改好的?
- 第一次枚舉和第二次枚舉的描述符有什么區別
- 使用USB Device Viewer可以看到Android 設備的USB描述符信息,如在文章一開始舉的例子,第二次枚舉返回的描述符只是這幾個接口的重新組合還是又重新定義了一組描述符