首页 > 其他分享 >Android开放配件 (AOA) 协议

Android开放配件 (AOA) 协议

时间:2023-11-29 12:34:23浏览次数:36  
标签:usb AOA accessory 配件 Android 设备 USB

一、背景

  自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方式写入,可以随意指定每次写入的大小。

  也可以写个简单的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库实现。

 

标签:usb,AOA,accessory,配件,Android,设备,USB
From: https://www.cnblogs.com/blogs-of-lxl/p/17864147.html

相关文章

  • Android之 看“马达”如何贯通Android系统 (从硬件设计 --> 驱动 --> HAL --> JNI -->
    Android之看“马达”如何贯通Android系统(从硬件设计-->驱动-->HAL-->JNI-->Framework-->Application)-如果天空不死-博客园https://www.cnblogs.com/skywang12345/p/3404808.html  在Android2.3(Gingerbread)系统的时候,我写过一篇关于“Android震动马达......
  • Android Compose 的分页(Paging3)
    Overview官方链接:https://developer.android.com/topic/libraries/architecture/paging/v3-overview需要注意的是,Paging库的组件在应用程序的三层中运行,Paging在三层的架构如下图:存储库层ViewModel层用户界面层在三层的数据传递如下图:方法/接口官方链接:https://dev......
  • Realtek蓝牙Android10.0移植结束后的基本测试和常见问题分析
    基本测试主要包括配置检查和BT测试两大部分配置检查:为了进一步确保porting没有问题,在测试之前先确认fw以及config文件是否存在。adbshell到测试平台的根目录,检查测试平台的vendor/firmware/目录中rtlxxxx_fw以及rtlxxxx_config文件是否存在(xxxx为BTChip型号)......
  • 直播系统代码,Android自定义View实现呼吸灯效果
    直播系统代码,Android自定义View实现呼吸灯效果自定义View的属性定义attrs.xml如下: <resources>  <declare-styleablename="BreathView">    <attrname="centerCircleRadius"format="dimension"/>    <attrname="circleCol......
  • 解决AndroidStudio 模拟器无网络连接
    解决AndroidStudio模拟器无网络连接主要原因是安卓模拟器的dns和电脑的dns不一致引起的,可以修改安卓模拟器的dns即可找到安卓模拟器的名字修改安卓模拟器dns命令 #Pixel7_API_30_fei这个是你自己模拟器的名字,也就是第一步中找的的模拟器名字./emulator-avdPixel......
  • android创建平板的分页页码
    在横向平板显示分页页码的时候,要实现下面的效果当默认分页超过5个之后中间显示...然后两边的页码按钮点击之后移动页码,点击1、2页码不移动,点击了第3页之后,左边移动到2、3、4页面,如下使用RecyclerView列表实现,通过对Item的type进行分类来实现页码按钮和省略号,下面是分页列表......
  • Android开发App回到桌面但不退出APP的实现
    方法1:Intentintent=newIntent();//创建Intent对象intent.setAction(Intent.ACTION_MAIN);//设置Intent动作intent.addCategory(Intent.CATEGORY_HOME);//设置Intent种类intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//标记context.startActivity(intent);方法2:......
  • 客户端相关知识学习(三)之Android原生与H5交互的实现
     Android原生与H5交互的实现H5调用原生的方式方式可能有多种,根据开发经验,接触过两种方式。方法一:Android向H5注入全局js对象,也就是H5调Android1.首先对WebView进行初始化WebSettingssettings=webview.getSettings();settings.setJavaScriptEnabled(true);//允......
  • 客户端相关知识学习(八)之Android“.9.png”
    客户端相关知识学习(八)之Android“.9.png” 参考Android中.9图片的含义及制作教程.9.pngAndroid.9.png的介绍......
  • 客户端相关知识学习(十一)之Android H5交互Webview实现localStorage数据存储
      前言最近有一个需求是和在app中前端本地存储相关的,所以恶补了一下相关知识webView开启支持H5 LocalStorage存储有些时候我们发现写的本地存储没有起作用,那是因为默认WebView没有开启LocalStorage存储。开启方法如下首先得有Webview控件:有人问我是不是需要写布局文件......