Androidadb驅動的代碼在以下兩個文件中實現,這部分的內容屬於Linux USB Gadget的範疇了。
<Kernel_Dir>/drivers/usb/gadget/androidadb.c
<Kernel_Dir>/drivers/usb/gadget/f_adb.c
關於Androidadb驅動的實現原理可以參照我的另外一篇文章:Androidadb驅動實現原理
應用層的實現代碼在以下目錄:
<Project_Dir>/platform/system/core/adb/
這部分的代碼可以從下面的路徑下載下來:
https://android.googlesource.com/platform/system/core/+/master/adb
一、adb定義
Android調試橋(Android Debug Bridge)是一個通用命令行工具,其允許您與模擬器實例或連接的 Android 設備進行通信。它可爲各種設備操作提供便利,如安裝和調試應用,並提供對 Unix shell(可用來在模擬器或連接的設備上運行各種命令)的訪問。該工具作爲一個客戶端-服務器程序,包括三個組件:
客戶端:該組件發送命令。客戶端在開發計算機上運行。您可以通過發出 adb 命令從命令行終端調用客戶端;
後臺程序:該組件在設備上運行命令。後臺程序在每個模擬器或設備實例上作爲後臺進程運行;
服務器:該組件管理客戶端和後臺程序之間的通信。服務器在開發計算機上作爲後臺進程運行;
在<Project_Dir>/platform/system/core/adb/OVERVIEW.TXT
文件中簡單介紹了adb的功能、組件、通信協議。
二、編譯
1、驅動編譯
在xxx_deconfig文件中添加CONFIG_USB_ANDROIDADB=m
的配置就行了,就會編譯androidadb.c
文件,在該文件的開頭會去#include "f_adb.c"
文件。最後該目錄下會生成 g_androidadb.ko
文件,g_ 的開頭表示這是一個gadget的驅動文件。
2、應用層編譯
只要下載了 adb/ 目錄,這個目錄的源代碼包括USB Host所需要的adb service,以及USB Device所需要的adbd。我們這裏只要編譯USB Device的adbd就行了。編譯就會生成一個adbd(adb daemon,adb守護進程),這個adbd只能運行在USB設備端。
三、配置
1、加載驅動
執行命令#insmod /system/lib/modules/g_androidadb.ko
後Kernel 會有如下打印,此時D+上的上拉電阻已經pullup上去,設備從USB Host變爲USB Device設備。
[ 24.824038] [xxx-adb] in android_bind:718
[ 24.828897] [xxx-adb] in adb_function_init:248
[ 24.834218] android_usb gadget: android_usb ready
[ 24.842046] USB suspend. -1
[ 24.844944] usb_gadget_state_work: state change: not attached -> suspended
執行之後,在會在sysfs下生成對應的目錄文件/sys/class/android_usb/android0/
:
xxx@xxxdroid:~$ ll /sys/class/android_usb/android0
-rw-r--r-- 0 0 4096 2017-05-01 12:01 bDeviceClass
-rw-r--r-- 0 0 4096 2017-05-01 12:01 bDeviceProtocol
-rw-r--r-- 0 0 4096 2017-05-01 12:01 bDeviceSubClass
-rw-r--r-- 0 0 4096 2017-05-01 12:01 bcdDevice
-rw-r--r-- 0 0 4096 2017-05-01 12:01 enable
drwxr-xr-x 0 0 2017-05-01 12:01 f_adb
-rw-r--r-- 0 0 4096 2017-05-01 12:01 functions
-rw-r--r-- 0 0 4096 2017-05-01 12:01 iManufacturer
-rw-r--r-- 0 0 4096 2017-05-01 12:01 iProduct
-rw-r--r-- 0 0 4096 2017-05-01 12:01 iSerial
-rw-r--r-- 0 0 4096 2017-05-01 12:01 idProduct
-rw-r--r-- 0 0 4096 2017-05-01 12:01 idVendor
drwxr-xr-x 0 0 2017-05-01 12:01 power
-r--r--r-- 0 0 4096 2017-05-01 12:01 state
lrwxrwxrwx 0 0 2017-05-01 12:01 subsystem -> ../../../../class/android_usb
2、添加usb functions到list中
#echo adb > /sys/class/android_usb/android0/functions
這條命令是添加名爲”adb”的function name到鏈表中。
3、使能androidadb
#echo 1 > /sys/class/android_usb/android0/enable
4、啓動adbd進程
將應用程序編譯生成的adbd可執行文件拷貝到 /data 目錄下,然後執行#./data/adbd &
,執行完會打印:
[ 475.678573] adb_open
[ 475.681237] [xxx-adb] in android_enable:210
[ 475.685478] adb_bind_config
上述執行完畢之後,這個USB Device已經準備就緒,接下來就等着連接到USB Host上,並被USB Host所枚舉。
將該設備連接到PC端的Ubuntu系統中,如果有如下的打印,表示USB Device已經被成功枚舉了。
設備端有如下的Kernel打印:
[ 583.827662] android_work: sent uevent USB_STATE=CONNECTED
[ 583.882924] android_work: sent uevent USB_STATE=DISCONNECTED
[ 583.955991] android_work: sent uevent USB_STATE=CONNECTED
[ 583.962337] android_usb gadget: high-speed config #1: android
[ 583.975454] android_work: sent uevent USB_STATE=CONFIGURED
USB Host端(PC 端)有如下的Kernel打印:
[26448.351367] usb 1-10: new high-speed USB device number 110 using xhci_hcd
[26448.485861] usb 1-10: New USB device found, idVendor=18d1, idProduct=0001
[26448.485867] usb 1-10: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[26448.485870] usb 1-10: Product: Android
[26448.485873] usb 1-10: Manufacturer: Android
[26448.485876] usb 1-10: SerialNumber: 0123456789ABCDEF
如果連接到PC端的Windows系統,會有如下提示:
5、使用adb命令
上述步驟執行完畢之後,就可以在USB Host端使用adb命令了。在PC端執行:
#adb devices
就會看到有一個adb設備已經連上。
Victor@ Victor-HP:~$ adb devices
List of devices attached
0123456789ABCDEF device
Victor @ Victor-HP:~$
四、發生的問題
1、枚舉失敗
直接#insmod /system/lib/modules/g_androidadb.ko
之後就去連接USB Device,會顯示枚舉失敗。
USB Device端會打印:
[ 75.042945] android_work: sent uevent USB_STATE=DISCONNECTED
[ 75.100372] android_work: sent uevent USB_STATE=CONNECTED
[ 75.155320] android_work: sent uevent USB_STATE=DISCONNECTED
[ 75.228037] android_work: sent uevent USB_STATE=CONNECTED
[ 75.283385] android_work: sent uevent USB_STATE=DISCONNECTED
[ 75.340042] android_work: sent uevent USB_STATE=CONNECTED
[ 75.395302] android_work: sent uevent USB_STATE=DISCONNECTED
[ 75.468176] android_work: sent uevent USB_STATE=CONNECTED
[ 75.523014] android_work: sent uevent USB_STATE=DISCONNECTED
[ 75.596234] android_work: sent uevent USB_STATE=CONNECTED
[ 75.651473] android_work: sent uevent USB_STATE=DISCONNECTED
[ 75.724236] android_work: sent uevent USB_STATE=CONNECTED
[ 75.729683] USB suspend. 8
[ 75.732834] usb_gadget_state_work: state unchange: suspended -> suspended
USB Host端會打印:
[ 9711.166372] usb 1-10: new high-speed USB device number 95 using xhci_hcd
[ 9711.294632] usb 1-10: no configurations
[ 9711.294636] usb 1-10: can't read configurations, error -22
[ 9711.406525] usb 1-10: new high-speed USB device number 96 using xhci_hcd
[ 9711.534741] usb 1-10: no configurations
[ 9711.534744] usb 1-10: can't read configurations, error -22
[ 9711.646669] usb 1-10: new high-speed USB device number 97 using xhci_hcd
[ 9711.668373] usb 1-10: no configurations
[ 9711.668376] usb 1-10: can't read configurations, error -22
[ 9711.834782] usb 1-10: new high-speed USB device number 98 using xhci_hcd
[ 9711.851051] usb 1-10: no configurations
[ 9711.851053] usb 1-10: can't read configurations, error -22
[ 9711.851072] usb usb1-port10: unable to enumerate USB device
這裏說明一下爲什麼會去嘗試枚舉4次。4次都沒有獲取到配置描述符,因此最後報告枚舉失敗。
嘗試枚舉4次是在Linux USB Hub的代碼中實現的,也就是在 <Kernel_Dir>/drivers/usb/core/hub.c
文件中實現。
#define SET_CONFIG_TRIES (2 * (use_both_schemes + 1))
宏SET_CONFIG_TRIES
決定循環的次數。
在 hub_port_connect_change()
中會有個for循環:for (i = 0; i < SET_CONFIG_TRIES; i++)
如果枚舉失敗則執行goto loop:
/* reset (non-USB 3.0 devices) and get descriptor */
status = hub_port_init(hub, udev, port1, i);
if (status < 0)
goto loop;
當最終4次都失敗的時候,會打印:usb usb1-port8: unable to enumerate USB device
。
很顯然,在USB Host的枚舉過程中沒有找到USB Device的configurations,因此枚舉失敗。
在一般情況下,USB Composite Driver中調用usb_composite_probe()
。並且實現了對應的struct usb_composite_driver
數據結構,那麼在 .bind
中會去調用usb_add_config()
添加configuration和調用usb_add_function()
添加function。但是在adb的驅動中的 .bind 並沒有實現這個功能,所以在枚舉時候沒有找到configuration。
那怎麼辦呢?就是得乖乖的按照上述的步驟去執行,”echo adb 到functions”,然後”echo 1 到enable”使能androidadb,最後執行adbd程序。這三個步驟就是添加adb的functions並且綁定function到configuration中去,這樣才能枚舉成功。
關於這一部分的內容,可以在我的另外一篇文章找到答案。
2、adb shell 執行失敗
當設備連接上了之後,我可以正確的執行#adb devices
等命令。但是當我執行#adb shell
的時候,USB Host那一端會做如下提示操作失敗:
- exec '/system/bin/sh' failed: No such file or directory (2) -
我都不知道這句話是USB Host端的adb service還是USB Device端的adbd打印出來的。後面想到我們有下載整個adb的源代碼,也就是<Project_Dir>/platform/system/core/adb/
這裏包括USB Host的adb service的代碼和USB Device adbd的代碼。於是就在代碼裏面搜索上面提示的關鍵字,最終找到了。在services.c
的文件中:
#if !ADB_HOST
static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
{
#ifdef HAVE_WIN32_PROC
D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
return -1;
#else /* !HAVE_WIN32_PROC */
char *devname;
int ptm;
......
// set OOM adjustment to zero
char text[64];
snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
int fd = adb_open(text, O_WRONLY);
if (fd >= 0) {
adb_write(fd, "0", 1);
adb_close(fd);
} else {
D("adb: unable to open %s\n", text);
}
execl(cmd, cmd, arg0, arg1, NULL);
fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
cmd, strerror(errno), errno);
exit(-1);
......
#endif /* !HAVE_WIN32_PROC */
}
很明顯,這是只有在USB Device中執行的 execl() 失敗的。也就是說在USB Device中找不到/system/bin/sh
的shell。
因爲在USB Device的Linux系統中,將sh的可執行文件放在 /bin/
目錄下,也就是 /bin/sh
。但是這裏要求要調用 /system/bin/sh
,那肯定是沒有的。解決方案就是在USB Device的Linux系統中將sh拷貝一份到 /system/bin/ 目錄下。
#cp -rf /bin/sh /system/bin/sh
當然,這個方案只能在開發的過程中去做。
上述執行完畢之後在USB Host再次敲入#adb shell就可以進入USB Device的shell窗口了。
3、adb shell訪問限制
當執行#adb shell的時候有如下提示:
error: insufficient permissions for device
解決方法是執行以下兩條命令:
#adb remount
#adb root
具體的原因分析可以參照:
https://stackoverflow.com/questions/5510284/adb-devices-command-not-working
五、參考資料
https://developer.android.com/studio/command-line/adb.html
http://blog.csdn.net/xiaojsj111/article/details/18599653
http://www.claudxiao.net/2011/05/adb_analysis_part1/