这两天顺着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
中的代码逻辑.