这两天顺着recovery模式下一个网络需求,
为了便于调试又在recovery下做了ADB功能. 在Android早期的如4.4版本,
recovery模式下支持ADB配置起来比较简单(支持adb devices/adb reboot/adb pull/push等常用指令),
但在Android
9.0下USB辅助设备一般都通过configfs的方式来配置了,
因此相对来说要适配的东西就多一些,
如果额外要适配adb shell命令,
则要修改adbd的源代码了.这篇文章就来看看如何在Recovery模式下解决这几个问题.
在进入正题之前, 先了解下USB相关的基础知识.
USB全称是Universal Serial Bus,
是一种广泛用于主机与外设之间的连接的串行总线.USB设备使用的是一种层级的结构,
最多可支持多达127个设备, 每个USB设备对应一个功能(function),
比如USB打印机提供了打印服务; 存储设备则提供了存储数据的功能.

Android中的USB支持OTG(On The Go),
因此有两种模式,
一种是Android自身作为host,可以接入其他USB设备;一种是Android作为peripheral设备,
Android可以连接到PC端, 比如要查看Android设备的存储内容时,
使用ADB时都必须将Android设置为peripheral模式.ADB是Android中用于开发调试的一个工具,
更详细的说明可以参考官网的说明Android
Debuge Bridge.
Recovery下的ADB
适配的第一步是首先看看源码.
进入Recovery的代码/bootable/recovery下面有一个README.md的文档,
里边有大致说明了如何在recovery下使用ADB.
对USESRDEBUG/ENG版本, 默认是启动了adbd,
并且对于recovery模式通过adb devices看到的是一个如下设备:
1 |
|
还需要明确的一点是, 在recovery模式下, 只有部分adb指令可用,
比如adb root/adb push/pull,
如果要使用adb shell需要把/system分区挂载上来.看起来一切都比较简单了,
可通过adb reboot recovery之后却无法找到设备,
在PC端查看dmesg也没有任何USB设备枚举上来.
继续看文档, 上面说到,
如果设备使用了configfs这个配置文件系统的话,
需要设置相关的配置.那问题可能就出在这里:
使用了configfs来配置USB设备,
但是在recovery模式没有正常配置.
1 |
|
简单来说, 在Linux中,
USB Gadget是一个具有UDC(USB Device Controller)的可以连接到一个USB
Host的设备, 其通常具有串口通讯/数据存储的功能.而对于Host来说,
一个USB Gadget就是一个配置的集合而已, 每个配置包含很多接口,
也被称为功能(functions).
目前Linux已经包含了很多功能供USB Gadgets使用,
具体可以参看Linux的源码/kernel/drivers/usb/gadget.
那么具体来说ADB适配要经历哪几个步骤了? 接下来就来看一看recovery下适配ADB需要做的事情.
Recovery下的ADB适配
- 挂载FunctionFs将USB用于ADB通信
在recovery代码目录/bootable/recovery/etc/init.rc中对ADB对应的FunctionFs做了配置:
1 |
|
这个有什么用了?看ADB的源码(/system/core/daemon),
大致可以看到, 只有挂载了functionfs,
ADB才能基于USB的ep0端口进行通讯:
1 |
|
需要了解USBFunctionFs的同学可以参考Linux的文档https://www.kernel.org/doc/Documentation/usb/functionfs.txt.
- 创建ADB相关的功能配置
挂载configfs到某个目录, 并生成ADB相关的配置,
主要是USB的ProductID/VendorID以及设备序列号等信息
1 |
|
配置完成后, /config/usb_gadget/g1目录下大致如下:

- 使能对应的USB Gadgets
在Android设备文件目录/sys/class/udc找到对应USB设备控制器的名称,
将其写入到对应的配置, 从而使得USB主机端可以正常枚举到该USB设备:
1 |
|
配置完成后, 重新打包下BOOT分区, 刷写后,
输入adb devices可以看到:
1 |
|
说明修改起作用了,
但目前输入adb shell还是会提示/system/bin/sh目前找不到的错误,
原因是recovery并没有正常挂载system分区,
那么有没有可能不挂载system分区同时又能使用adb shell了?
看/bootable/recovery/etc/init.rc,
recovery下实际有集成了一个命令工具集合busybox,
通过busybox我们应该也可以实现类似与正常模式下/system/bin/sh的功能,
这就需要修改Android中ADBD的源码了,
具体可以看下/system/core/adb/shell_serivce.cpp中的代码逻辑.
参考文献
- Linux USB相关的资料文档
- USB Nutshell
- USB Gadget Configfs
- https://www.kernel.org/doc/Documentation/usb/functionfs.txt