赞
踩
最近在查阅ADB源码,对ADB的工作原理有了些了解,于是就想利用libusb实现ADB的部分功能,加深理解。
ADB(Android Debug Bridge)即是安卓调试桥,是一个专门为Android系统打造的命令行调试工具。平时我们在电脑上使用的adb.exe就是这个工具,在shell中输入命令实现对手机的各种操作。
ADB采用C/S架构来设计,C即是Client,客户端,运行在我们的电脑上,S即是Server,服务端,运行在我们的Android手机中。客户端与服务端可以通过有线(USB)和无线(TCP)的方式进行通信。
(1)数据帧格式
struct amessage {
uint32_t command; //命令标识符常量
uint32_t arg0; //参数1
uint32_t arg1; //参数2
uint32_t data_length; //有效数据长度(允许为 0)
uint32_t data_check; //有效数据校验和
uint32_t magic; //命令标识符校验
};
struct apacket {
amessage msg; //数据头
uint8_t data[MAX_PAYLOAD]; //数据
};
(2)设备的ADB接口类
#define ADB_CLASS 0xff
#define ADB_SUBCLASS 0x42
#define ADB_PROTOCOL 0x01
(3)ADB接口使用BULK传输模式
libusb是一个用C语言编写的USB接口库,它对底层的驱动代码做了封装,用户只需调用API就能实现USB通信,具有较好的移植性,可跨Linux、Windows、macOS、Android等平台。
//初始化libusb
int libusb_init(libusb_context **ctx);
//退出libusb
void libusb_exit(libusb_context *ctx);
//获取设备列表
ssize_t libusb_get_device_list(libusb_context*ctx, libusb_device ***list);
//释放设备列表
void libusb_free_device_list(libusb_device **list, int unref_devices);
//获取设备描述符
int libusb_get_device_descriptor(libusb_device *dev, struct libusb_device_descriptor *desc);
//获取配置描述符
int libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config);
//通过vid和pid打开设备
libusb_device_handle *libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id, uint16_t product_id);
//注册通信接口
int libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number);
//BULK模式传输
int libusb_bulk_transfer(libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *data, int length, int *actual_length, unsigned int timeout);
编译环境使用的是VS2019,解决方案平台为X86
该工程使用的是dll动态链接库
(1)下载libusb库
(2)解压libusb后复制相应环境的libusb.lib到工程目录,并添加libusb.h到工程
(3)在链接器中添加libusb.lib,以Debug为例,添加路径为相对路径,其中 “ . .\” 表示在工程文件(.vcxproj)的上一级目录,“.\”则表示和工程文件(.vcxproj)在同一级目录,如下图所示
(4)除以上操作外,还需要添加libusb.dll到输出文件目录下(与生成的.exe同目录)
(1)匹配ADB接口,一个USB设备可以有多个ADB接口,可以通过ADB接口的类、子类和协议进行判断。
代码如下(示例):
/*
* 函数名 : match_with_interface
* 函数功能 : 匹配ADB接口
* 输入 : handle:ADB结构体
* 输出 : 无
*/
void match_with_interface(adb_handle* handle)
{
libusb_device** devs;
libusb_device* dev;
ssize_t cnt;
uint8_t num = 0;
int r;
cnt = libusb_get_device_list(NULL, &devs); //获取设备列表
if (cnt < 0) {
printf("failed to libusb_get_device_list\n");
return;
}
while ((dev = devs[num++]) != NULL) { //遍历设备列表
uint8_t i, j;
struct libusb_device_descriptor desc;
struct libusb_config_descriptor* config;
struct libusb_interface_descriptor interface;
r = libusb_get_device_descriptor(dev, &desc); //获取设备描述符
if (r < 0) {
printf("failed to get device descriptor\n");
return;
}
r = libusb_get_config_descriptor(dev, 0, &config); //获取配置描述符
if (r < 0) {
printf("failed to get config descriptor\n");
return;
}
for (i = 0; i < config->bNumInterfaces; i++) { //遍历设备接口,找到ADB接口;一个设备可有多个不同功能的接口
for (j = 0; j < config->interface[i].num_altsetting; j++) {
if (is_adb_interface(config->interface[i].altsetting[j].bInterfaceClass,
config->interface[i].altsetting[j].bInterfaceSubClass,
config->interface[i].altsetting[j].bInterfaceProtocol)) {
interface = config->interface[i].altsetting[j];
if (2 != interface.bNumEndpoints) { //判断端点数是否满足,一个收,一个发
return;
}
if (match_with_endpoint(handle, &interface)) { //匹配读写端点
handle->zero_mask = interface.endpoint[0].wMaxPacketSize - 1;
handle->dev_handle = libusb_open_device_with_vid_pid(NULL, desc.idVendor, desc.idProduct); //通过idVendor和idProduct打开设备
printf("idVendor:%04x, idProduct:%04x\n", desc.idVendor, desc.idProduct);
if (handle->dev_handle != NULL) {
r = libusb_claim_interface(handle->dev_handle, interface.bInterfaceNumber); //注册ADB接口,只有注册成功才能进行通信
if (r < 0) {
printf("*** libusb_claim_interface failed! \n");
return;
}
handle->state = INIT_DONE;
return;
}
}
}
}
}
}
}
/*
* 函数名 : is_adb_interface
* 函数功能 : 判断是否是ADB接口
* 输入 : usb_class:USB类;usb_subclass:USB子类;usb_protocol:USB协议
* 输出 : 成功:0;失败:-1
*/
static int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol)
{
if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL) {
return 1;
}
return 0;
}
(2)匹配ADB接口的通信端点,UBS通信就是通过这些端点进行通信的,其实质是FIFO缓冲区,其地址高位为1是输入,否则为输出。
代码如下(示例):
/*
* 函数名 : match_with_endpoint
* 函数功能 : 匹配端点
* 输入 : handle:ADB结构体;interface:ADB接口号
* 输出 : 成功:1;失败:0
*/
int match_with_endpoint(adb_handle* handle, const struct libusb_interface_descriptor* interface)
{
uint8_t i;
uint8_t ret = 0;
for (i = 0; i < interface->bNumEndpoints; i++) {
if (interface->endpoint[i].bEndpointAddress & 0x80) { //端点地址高位为1
ret |= 1;
handle->adb_read_pipe = interface->endpoint[i].bEndpointAddress; //读端点地址
}
else {
ret |= 2;
handle->adb_write_pipe = interface->endpoint[i].bEndpointAddress; //写端点地址
}
}
if (ret == 3) {
return 1;
}
else {
return 0;
}
}
(3)底层通信,通过调用libusb_bulk_transfer函数向ADB设备读或写数据,端点传输模式为BULK,块传输。
代码如下(示例):
/*
* 函数名 : usb_read
* 函数功能 : USB读取数据
* 输入 : data:数据指针; len:数据量
* 输出 : 成功:0;失败:-1
*/
int usb_read(adb_handle* handle, void* data, int len)
{
int ret;
if (NULL != handle) {
int xfer = (len > MAX_PAYLOAD) ? MAX_PAYLOAD : len; //判断缓冲区大小是否超过最大负载
ret = libusb_bulk_transfer(handle->dev_handle,
handle->adb_read_pipe, //读端点地址
(uint8_t*)data, //读数据缓冲区
xfer, //缓冲区大小
NULL,
0);
if (ret == 0) {
return 0;
}
}
return -1;
}
/*
* 函数名 : usb_write
* 函数功能 : USB发送数据
* 输入 : handle:ADB结构体;data:数据指针; len:数据长度
* 输出 : 成功:0;失败:-1
*/
int usb_write(adb_handle* handle, const void* data, int len) {
int ret;
if (NULL != handle) {
ret = libusb_bulk_transfer(handle->dev_handle,
handle->adb_write_pipe, //写端点地址
(uint8_t*)data,
len,
NULL,
0);
if (ret == 0) {
if (handle->zero_mask && (len & handle->zero_mask) == 0) { //确保数据发送完
libusb_bulk_transfer(handle->dev_handle,
handle->adb_write_pipe,
(uint8_t*)data,
0,
NULL,
0);
}
return 0;
}
}
return -1;
}
(4)通信协议,调用底层通信函数进行读写数据包。
代码如下(示例):
/*
* 函数名 : remote_read
* 函数功能 : 读取数据包
* 输入 : handle:ADB结构体;p:数据包指针
* 输出 : 成功:0;失败:-1
*/
int remote_read(adb_handle* handle, apacket* p)
{
if (usb_read(handle, &p->msg, sizeof(amessage))) { //接收数据头
return -1;
}
printf("remote_read p->cmd:%04x\n", p->msg.command);
if (check_header(p)) { //检验数据头
return -1;
}
if (p->msg.data_length) {
if (usb_read(handle, p->data, p->msg.data_length)) { //接收数据
return -1;
}
printf("remote_read p->data:%s\n", p->data);
if (check_data(p)) { //检验数据
return -1;
}
}
return 0;
}
/*
* 函数名 : remote_write
* 函数功能 : 发送数据头和数据
* 输入 : handle:ADB结构体;p:数据包指针
* 输出 : 成功:0;失败:-1
*/
int remote_write(adb_handle* handle, apacket* p)
{
uint16_t len = p->msg.data_length;
if (usb_write(handle, &p->msg, sizeof(amessage))) { //发送数据头
return -1;
}
printf("remote_write p->cmd:%04x\n", p->msg.command);
if (p->msg.data_length == 0) {
return 0;
}
if (usb_write(handle, p->data, len)) { //发送数据
return -1;
}
printf("remote_write p->data:%s\n", p->data);
return 0;
}
(5)USB调试权限申请和ADB命令传输函数。
代码如下(示例):
/*
* 函数名 : send_auth_remote
* 函数功能 : 发送auth key,向设备申请USB调试权限
* 输入 : handle:ADB结构体;key:auth key(任意字符串即可)
* 输出 : 成功:0;失败:-1
*/
int send_auth_remote(adb_handle* handle, const char* key)
{
int r;
apacket* p = get_apacket(); //数据包内存分配
uint16_t len = (uint16_t)strlen(key) + 1;
if (len > (MAX_PAYLOAD - 1)) {
printf("destination oversized\n");
return -1;
}
do {
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
p->msg.arg1 = 0;
p->msg.data_length = len;
strcpy((char*)p->data, key);
send_packet_remote(handle, p); //发送AUTH KEY,向Android设备申请权限
do {
memset(p, 0, sizeof(apacket));
r = remote_read(handle, p);
} while (!(r == 0));
} while (!(p->msg.command == A_CNXN)); //阻塞式读取,直到设备应答A_CNXN,表示申请成功
put_apacket(p); //释放数据包内存
return 0;
}
/*
* 函数名 : send_cmd_remote
* 函数功能 : 发送shell命令行
* 输入 : handle:ADB结构体;cmd:命令行字符串
* 输出 : 成功:0;失败:-1
*/
int send_cmd_remote(adb_handle* handle, const char* cmd)
{
apacket* p = get_apacket();
uint16_t len = (uint16_t)strlen(cmd) + 1;
if (len > (MAX_PAYLOAD - 1)) {
printf("destination oversized\n");
return -1;
}
p->msg.command = A_OPEN;
p->msg.arg0 = A_VERSION;
p->msg.arg1 = 0;
p->msg.data_length = len;
strcpy((char*)p->data, cmd);
send_packet_remote(handle, p); //发送ADB命令
do {
memset(p, 0, sizeof(apacket));
remote_read(handle, p);
} while (!(p->msg.command == A_OKAY)); //阻塞式读取,直到设备应答A_OKAY,表示成功执行命令
put_apacket(p);
return 0;
}
(6)主函数功能,屏幕输入字符a,发送熄屏命令,手机熄屏。
代码如下(示例):
int main(void)
{
int r;
char ch;
adb_handle* handle = (adb_handle*)malloc(sizeof(adb_handle));
r = libusb_init(NULL); //初始化libusb
if (r < 0) {
printf("libusb_init faild\r\n");
return -1;
}
match_with_interface(handle); //匹配ADB接口
if (handle->state != INIT_DONE) {
printf("match_with_interface faild\r\n");
return -1;
}
while (1) {
switch (handle->state) {
case INIT_DONE:
printf("start get cmd\n");
handle->state = SEND_AUTH;
break;
case SEND_AUTH: //发送AUTH KEY 申请USB调试权限
r = send_auth_remote(handle, AUTH_KEY);
if (r < 0) {
printf("*** send_auth_remote failed! \n");
break;
}
handle->state = SEND_CMD;
break;
case SEND_CMD:
printf("请输入字符'a'测试:");
scanf("%c", &ch);
getchar();
switch (ch)
{
case 'a':
r = send_cmd_remote(handle, "shell:input keyevent 26"); //熄屏命令
if (r < 0) {
printf("get_logcat_remote faild\r\n");
}
break;
default:
break;
}
default:
break;
}
}
libusb_exit(NULL);
free(handle);
return 0;
}
(1)手机USB连接电脑
(2)电脑上运行程序
(3)手机上确认USB调试授权
(4)在程序屏幕输入字符’a’
(5)手机自动熄屏
注意:手机需要先开启USB调试模式
利用libusb实现ADB的部分功能让我对ADB的工作原理有了更深层次的理解。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。