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 命令从命令行终端调用客户端;

  • 后台程序:该组件在设备上运行命令。后台程序在每个模拟器或设备实例上作为后台进程运行;

  • 服务器:该组件管理客户端和后台程序之间的通信。服务器在开发计算机上作为后台进程运行;

/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系统,会有如下提示:
Androidadb的编译配置及常见问题_第1张图片


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的代码中实现的,也就是在 /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的源代码,也就是/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/

你可能感兴趣的:(Linux,Device,Driver,USB)