惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Stack Overflow Blog
Stack Overflow Blog
WordPress大学
WordPress大学
N
Netflix TechBlog - Medium
GbyAI
GbyAI
云风的 BLOG
云风的 BLOG
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
C
Cyber Attacks, Cyber Crime and Cyber Security
雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Threat Research - Cisco Blogs
NISL@THU
NISL@THU
Spread Privacy
Spread Privacy
P
Proofpoint News Feed
J
Java Code Geeks
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
MyScale Blog
MyScale Blog
T
Tor Project blog
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
P
Privacy & Cybersecurity Law Blog
MongoDB | Blog
MongoDB | Blog
Simon Willison's Weblog
Simon Willison's Weblog
C
Cybersecurity and Infrastructure Security Agency CISA
L
LINUX DO - 热门话题
小众软件
小众软件
G
GRAHAM CLULEY
P
Privacy International News Feed
AWS News Blog
AWS News Blog
Know Your Adversary
Know Your Adversary
P
Palo Alto Networks Blog
人人都是产品经理
人人都是产品经理
S
Schneier on Security
Scott Helme
Scott Helme
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
B
Blog RSS Feed
T
The Exploit Database - CXSecurity.com
Recent Announcements
Recent Announcements
E
Exploit-DB.com RSS Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
U
Unit 42
The Register - Security
The Register - Security
S
Securelist
Martin Fowler
Martin Fowler
Project Zero
Project Zero
大猫的无限游戏
大猫的无限游戏
Cisco Talos Blog
Cisco Talos Blog

博客园 - sheldon_blogs

Android设备搭建本地RTSP服务器(基于live555) Android上玩转TUN设备及rtsp传输 Android14 RK3588平台内核异常中断占用CPU问题排查 Android平台移植stress-ng工具及使用 Android OTA的两种方式:Non-A/B(recovery)和A/B系统升级 Android设备之间UVC Gadget bulk模式无法正常打开问题 Android的USB网络共享功能 Linux修改Swap分区大小及使用优先级 Android(S)系统属性服务详解 Android12 双屏异显/异触流程分析 Android Webview 调试总结 RK3588 Android12 编译打包私有ext4格式vendor.img并挂载到新增vendor_private分区 C++提取字符串中的整数 Android UVC Camera H.265帧序错乱问题 RK3588 Android12 一个固件兼容多个板型方案 全志A133 Android10 Display框架实践 Android编译脚本添加kernel编译选项传入宏定义 UAC实例分析-USB音响 Android USB之复合设备(gadget)详解
Android开放配件 (AOA) 协议
sheldon_blogs · 2023-11-29 · via 博客园 - sheldon_blogs

一、背景

  自Android 3.1之后的版本,Google引入了USB Accessories的概念,并提供了相关的开发库。Android3.1之后的版本不仅可以让Android设备作为USB Host的角色支持USB鼠标、键盘、游戏手柄等,还可以以USB Device的角色与一些具有USB Host功能,但却扮演着配件角色的设备相连,Google把这种设备称为“Accessory”(附件)。这类Accessory可能是如下设备:机器人控制器、Dock(基座)、诊断设备、音响设备、配电设备、读卡器等等。

  Google引入USB Accessory概念的原因应该主要有如下:

  • 非常多的Android设备不具有USB Host的功能而只具有USB Device功能(例如绝大部分Android手机),或者即使具备USB Host的功能,也承担不起对USB外设供电的任务,因为便携式Android设备本身的电池容量就很有限。
  • 原来的Android设备,作为USB Device所实现的功能相对比较简单,内置的功能只有U盘或ADB调试设备等,Google希望提供应用层的USB开发库,让更多的软硬件厂商来开发新的功能,比如说安装一个APK应用,然后通过USB连接到一个与电视机配套的Dock上,就可以让一台Android手机变身为一个电视机遥控器。

  以此借助一套标准的AOA(Android Open Accessory)协议,方便Android设备和外围设备通过USB进行交互,实现各种 Android 设备功能扩展。

二、Usb Accessory的设计实现

  Android 设备可以通过主机模式和配件模式和各种USB设备通信。

  • 主机模式 Host Mode : Android设备充当USB HOST,USB配件充当 USB DEVICE,Android 设备负责给总线供电及枚举。
  • 配件模式 Accessory Mode :USB配件充当USB HOST,Android设备充当USB DEVICE,USB配件为 Android 设备提供电源并进行枚举,与主机模式相反。

  两种模式如下图所示:

 软件架构图:

AOA 协议有 1.0 和 2.0 两个版本,2.0版本是对对1.0版本的补充,增加了对Audio和HID类Accessory设备的支持:

版本产品 ID通信说明
AOAv1 0x2D00 配件 提供两个批量端点,用于与 Android 应用通信。
0x2D01 配件 + adb 在配件开发过程中用于调试。仅当用户在 Android 设备设置中启用了“USB 调试”时才可用。
AOAv2 0x2D02 音频 将音频从 Android 设备流式传输至配件。
0x2D03 音频 + adb  
0x2D04 配件 + 音频  
0x2D05 配件 + 音频 + adb

AOA 协议将上述3种接口组合出6种 USB 接口层设备,这些USB设备的厂商 ID 统一为 0x18D1 (Google Inc)。如需确定连接的 Android 设备是否支持配件和支持的协议版本,该配件必须发送 getProtocol() 命令并检查结果。仅支持 AOAv1 功能的 Android 设备必须返回 1 作为协议版本,支持 AOAv2 的额外功能的设备必须返回 2 作为协议版本。AOAv2 向后兼容 AOAv1,因此基于原始配件协议设计的配件将可以兼容更高版本的 Android 设备。

注:音频输出在 Android 8.0 中已被弃用。谷歌官网 https://source.android.com/docs/core/interaction/accessories/aoa2?hl=zh-cn 中有详细介绍 

这里简单介绍一下USB Composite(复合)设备,对于大部分USB Device设备来说,它仅仅只有一个功能,比如大部分U盘,单个的USB鼠标等,但是也有些USB设备不止实现一个功能,比如某些USB上网卡有无线上网的功能,同时还有U盘存储的功能,又比如有的鼠标和键盘二合一设备,它只有一个USB接口,却同时支持了鼠标和键盘两个功能。这种一个USB接口扩展出多个设备功能的实现方法有两种,一种是在设备外部或内部加Hub扩展;另一种就是以Usb Composite Device方式实现(一般称为复合设备)。复合设备其实只是一个USB设备,只有一个USB设备地址,它实现多个功能的原因主要在于它扩展实现了多个USB接口,每个接口具有不同的设备类型。

Usb accessory模式也基于复合设备驱动实现,具体源码在内核的 drivers/usb/gadget/function/ 目录下,有 f_accessory.c 、f_audio_source.c、f_hid.c 等等,详细的驱动剖析可参考: Android USB之复合设备(gadget)详解 。

三、使用Usb Accessory模式

1.Device端, 也就是当前Android设备作为配件。

  原生就有配置,只要设置属性:setprop sys.usb.config accessory ,即可开启Accessory模式,对应的usb口要支持OTG功能,并且切成device模式。

  然后可以向驱动节点: /dev/usb_accessory  写入数据即可,会通过usb往外发送给Host端。参考如下3种测试方法:

echo "123" > /dev/usb_accessory  //echo字符串
cat /sdcard/DCIM/test.mp4 > /dev/usb_accessory  //cat文件,注意默认是一次写入4k大小,跟驱动缓存大小有关。
busybox dd if=/sdcard/DCIM/test.mp4 of=/dev/usb_accessory bs=128K count=100  // dd方式写入,可以随意指定每次写入的大小。

  App测试工程:https://github.com/dragonforgithub/AccessoryChart.git  

  也可以用C写个简单的demo,核心实现都是读写 /dev/usb_accessory 节点:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define DRIVER_NAME "/dev/usb_accessory"

#define MAX_USBFS_BUFFER_SIZE   16384

int open_accessory()
{
    int fd = open(DRIVER_NAME, O_RDWR);
    if (fd < 0) {
        fprintf(stderr, "Error: could not open %s\n", DRIVER_NAME);
        return -1;
    }
    return fd;
}

static void usb_accessory_read(int fd)
{
    char c;
    char buf[MAX_USBFS_BUFFER_SIZE];
    int n;
    while((n = read(fd, buf, MAX_USBFS_BUFFER_SIZE)) >= 0)
    {
        fprintf(stderr, "Error: %d\n", n);
        write(1, buf, n);
        putchar('\n');
    }
}

static void usb_accessory_write(int fd, char* buff, int length)
{
    char write_buff[MAX_USBFS_BUFFER_SIZE + 1] = {0x00};

    length = (length >= MAX_USBFS_BUFFER_SIZE) ? MAX_USBFS_BUFFER_SIZE : length;

    fprintf(stderr, "Error: length %d\n", length);
    memcpy(write_buff, buff, length);
    int result = write(fd, write_buff, length);
    fprintf(stderr, "Error: result %d\n", result);
}

int main()
{
    usb_accessory_write(open_accessory(), "123456789", 9);
    //usb_accessory_read(open_accessory());
    return 0;
}

2.Host端,也就是当前Android设备作为主设备,可以读写连接过来的配件。

  host端不需要额外的usb config, 只要确认同样支持对应版本AOA协议的版本, 测试demo可以是app 使用标准的API,也可以在native层基于libusbhost库实现。