Androidadb的編譯配置及常見問題

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/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章