1. 程式人生 > >Android原始碼編譯得到的adb為什麼不識別裝置?

Android原始碼編譯得到的adb為什麼不識別裝置?

編譯Android原始碼得到的adb不識別裝置,現在把解決過程記錄下來,希望對其他人有所幫助。

現象:

Ubuntu 16.04系統,在Android 5.0.2原始碼上,修改adb原始碼,編譯得到adb,執行adb devices不識別裝置,而且adb kill-server後adb start-server總是出現“ADB server didn't ACK”,“cannot connect to daemon”。但SDK自帶的adb卻能識別。這是什麼情況?

分析:

難道是修改錯了?看了修改的部分,不會導致這個問題。

正好本地有Android 4.4的原始碼,試下吧:不經修改得到的adb,仍然不識別裝置。

也就是說兩套原始碼都編譯成功了,卻不好用,這。。。

百度了一下沒找到提過這個問題的,Stackoverflow上也沒發現。。。

試試Windows版本的吧,SDK依舊識別,自己編譯的adb還是不識別。。。。一點安慰是:Windows上adb start-server不提示無法連線ADB server了。

再回到Ubuntu上吧:

如果server沒有啟動,自然不能識別到裝置,先解決這個問題:adb start-server再adb devices發現,ADB server啟動了,只是啟動的晚了一些。

現在接著解決不識別裝置的問題:想一想,adb原始碼不至於有問題,網上只有編譯adb的方法,沒有提到執行出問題的。

想一想這麼一個工具都弄不明白,這挫敗感頓時爆棚。

上Github看一看吧,搜了下adb,排第一的是下面這個專案:

https://github.com/karfield/adb

介紹說是自定義的獨立版本adb,應該是可用的,開啟先看說明,看到下面的介紹:

=== adb is a useful tool for debugging android devices, you can download the binary from google/android.com(mostly), but it
only supports small amount devices. To support some specific android device, you need to add the VID, add udev rule, etc. If
you want to support your devices natively of adb, you should change the usb_vendors.c code, then build the whole android
source to get the adb tool. It cause too much to gain the benity.

需要修改usb_vendors.c,好吧,看一下:

裡面果然有一個VendorID列表:builtInVendorIds,用巨集定義了若干廠商,確實沒有我這臺裝置的廠商。

按照格式在內建VID列表中把測試裝置的VID填進去(這個VID通過lsusb命令可以獲得),然後重新編譯,執行adb devices可以看到裝置啦!!!

Android的adb對廠商的支援:

在usb_vendors_init(void)方法裡,用這個內建列表加上從檔案讀取的第三方列表組成最終的adb支援裝置的VID列表:vendorIds,這個檔案是HOME環境變數的目錄(或者/tmp目錄)下的.android/adb_usb.ini檔案,每行一個VendorID。

transport_usb.c中的is_adb_interface()函式,會遍歷支援的VID列表,如果不在裡面,就不會顯示該裝置。
int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
{
    unsigned i;
    for (i = 0; i < vendorIdCount; i++) {
        if (vid == vendorIds[i]) {
            if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS &&
                    usb_protocol == ADB_PROTOCOL) {
                return 1;
            }

            return 0;
        }
    }

    return 0;
}

為什麼這麼設計?為了方便除錯?比如PC同時連線多臺裝置,只想操作一臺裝置,而不想每次都adb -s制定序列號或者export ANDROID_SERIAL設定序列號。

原因不得而知,可SDK裡的adb是怎麼支援的呢?沒有發現有一個超全的VID列表檔案呀(因為本地的只有一個VID檔案,而且裡面沒有填VID),難道填在了內建的VID列表裡,每次更新SDK順便更新?好像很不方便。

看看原始碼吧,是不是內建了:在AndroidXRef原始碼網站上,發現5.0、5.1都有這個usb_vendors.c檔案,但6.0、7.0、7.1都沒有這個檔案,看一下做判斷的transport_usb.cpp檔案,6.0之後已經刪除了對VID的判斷:

http://androidxref.com/7.1.1_r6/xref/system/core/adb/transport_usb.cpp

97 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol)
98 {
99    return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL);
100}

原來Android也認為沒這個必要,因此6.0之後,adb在不需要修改原始碼或者VID檔案的情況下,就可以識別裝置了。