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
Android调试桥(Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试应用,并提供对 Unix shell(可用来在模拟器或连接的设备上运行各种命令)的访问。该工具作为一个客户端-服务器程序,包括三个组件:
客户端:该组件发送命令。客户端在开发计算机上运行。您可以通过发出 adb 命令从命令行终端调用客户端;
后台程序:该组件在设备上运行命令。后台程序在每个模拟器或设备实例上作为后台进程运行;
服务器:该组件管理客户端和后台程序之间的通信。服务器在开发计算机上作为后台进程运行;
在
文件中简单介绍了adb的功能、组件、通信协议。
在xxx_deconfig文件中添加CONFIG_USB_ANDROIDADB=m
的配置就行了,就会编译androidadb.c
文件,在该文件的开头会去#include "f_adb.c"
文件。最后该目录下会生成 g_androidadb.ko
文件,g_ 的开头表示这是一个gadget的驱动文件。
只要下载了 adb/ 目录,这个目录的源代码包括USB Host所需要的adb service,以及USB Device所需要的adbd。我们这里只要编译USB Device的adbd就行了。编译就会生成一个adbd(adb daemon,adb守护进程),这个adbd只能运行在USB设备端。
执行命令#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
#echo adb > /sys/class/android_usb/android0/functions
这条命令是添加名为”adb”的function name到链表中。
#echo 1 > /sys/class/android_usb/android0/enable
将应用程序编译生成的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
上述步骤执行完毕之后,就可以在USB Host端使用adb命令了。在PC端执行:
#adb devices
就会看到有一个adb设备已经连上。
Victor@ Victor-HP:~$ adb devices
List of devices attached
0123456789ABCDEF device
Victor @ Victor-HP:~$
直接#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的代码中实现的,也就是在
文件中实现。
#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中去,这样才能枚举成功。
关于这一部分的内容,可以在我的另外一篇文章找到答案。
当设备连接上了之后,我可以正确的执行#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的源代码,也就是
这里包括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窗口了。
当执行#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/