Android libusb
一、环境:配置NDK环境
1、下载libusb源码: https://github.com/libusb/libusb/releases,如下图所示

2、删除一些和Android平台无关的文件,删除后的文件如下图所示:

思考问题:
- Android是怎么获取usb设备?

如上图所示:连接adb shell,然后cd到/sys/bus/usb/devices/目录,命令ll可以看到里面有很多链接的文件,其实这些文件就代表设备或者功能,那么什么代表的是设备?什么代表的是功能呢?如上图,有冒号的且后面有数字的就代表的是功能接口,无冒号的就代表设备。如:1-0:1.0 就表示1号总线的0号端口设备,使用的1号配置,接口号为0。
所以,我们可以遍历此目录来获取usb设备,那么获取usb设备是怎么获取他们的信息的呢?继续向设备目录下面一层可以看到如下图所示:

里面有很多信息,包括设备的bcdDevice(usb版本)、idProduct(产品id)、idVendor(厂商id)、speed(usb传输速度)、descriptors(设备描述符)等,都可以在这里获取。
这样,我们最初始获取usb设备的问题就解决了。那么如果插拔usb设备,是不是一直都需要这样监听呢?
- Android是怎么检测usb设备插拔?
使用Netlink来实现接收内核消息,读取热插拔信息,它是特殊的socket,使用时设置特定的参数即可监听到内核uevent事件,从而区分插拔事件NETLINK_KOBJECT_UEVENT, groups = 1,如下图所示:

所以,在libusb中只要对此socket进行监听即可,如下图代码的监听:

- Android是怎么进行数据传输的?
- 拿到句柄fd,如下图中的目录文件中open操作

- 通过ioctl与内核通信(linux_usbfs.c中submit_bulk_transfer函数)

- 通过ioctl与内核通信,具体见如下kernel代码drivers/usb/core/devio.c

二、目录文件介绍(os目录下都是一些和平台相关的,os外面是通用的):
a. linux_netlink.c:主要负责socket连接和监听热插拔的消息。
b.linux_usbfs.c: 主要是对Linux的一些文件进行操作,包括打开文件、释放文件、获取设备信息、和内核进行通信等
c.poll_posix.c: linux:通信设置pipe信息
d.threads_posix.c:主要是封装了一下线程锁和等待的一些机制。
e.config.h:对libusb进行一些配置
f.core.c:对os中的linux_usbfs.c进一步的封装,提供给外界调用的一些接口,包括初始化、分配内存、释放内存、通信的封装等。
g.descriptor.c:主要是获取设备描述符的封装。
h.hotplug.c:主要是对热插拔函数的封装,可以注册和反注册热插拔函数。
i.io.c:主要是和usb通信的一些封装,这里的封装均是异步接口
j.libusb.h:主要是对外提供的接口
k.libusbi.h:libusb内部使用的接口
l.sync.c:同步传输的封装
三、libusb传输封装的介绍,这里只介绍内部实现的同步bulk传输
接口的调用libusb_bulk_transfer -> do_sync_bulk_transfer() ->libusb_fill_bulk_transfer()、libusb_submit_transfer()、sync_transfer_wait_for_completion()等待completed被设置为1后返回transfer的值,包括buffer和actual_length
四、libusb的demo
#include <stdio.h>
#include "libusb.h"
static void print_devs(libusb_device **devs)
{
libusb_device *dev;
int i = 0, j = 0;
uint8_t path[8];
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "failed to get device descriptor");
return;
}
printf("%04x:%04x (bus %d, device %d)",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
r = libusb_get_port_numbers(dev, path, sizeof(path));
if (r > 0) {
printf(" path: %d", path[0]);
for (j = 1; j < r; j++)
printf(".%d", path[j]);
}
printf("\n");
}
}
int main(void)
{
libusb_device **devs;
int r;
ssize_t cnt;
r = libusb_init(NULL);
if (r < 0)
return r;
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
return (int) cnt;
print_devs(devs);
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return 0;
}
五、开发中遇到的问题
1、我们知道发现设备是从/sys/bus/usb/devices/发现的,但是打开设备则是在/dev/bus/usb/xxx中打开的,如果一旦发现设置,就直接去打开,有可能会导致打开失败的情况,原因是这个设备节点还没有来得及创建,就去打开这个设备,现在修复有两种方式:
a.如果打开失败,则slee(1)秒,再去打开,如果这次再打开失败,则就真的失败了,这个方式亲测还是可以的,而且查看Android源码好像也是用这种方式
b.这个方法简单的验证了一下可行,但是不知道会不会导致其他问题,就是发现设备枚举的时候就去获取他的主设备号和次设备号,然后在打开的时候,发现没有这个设备,就手动的创建设备,如下代码,其中/dev/bus/usb/002/为设备节点的路径,243为设备相应的主设备号,0为设备相应的次设备号。
mknod("/dev/bus/usb/002", S_IFCHR | 0666, makedev(243, 0)) = 0
2、如果是基于libusb开发的异步传输,而且传输时有很多缓存,我们可能会向libusb提供的demo上面写的那样,直接在接收到设备拔出的消息之后立刻libusb_close(handle), 这样会有个问题,有可能你提交成功的transfer不会通过回调返回给你,导致这个transfer会丢失,最终就是内存泄漏了。那么怎么解决这个问题呢?有两个方案:均亲测可行
a. 在收到设备拔出的消息之后不要立刻libusb_close(handle);在其他的时机close就可以了
b. 如果一定要在拔出后立刻libusb_close(handle);,我们可以把提交成功的transfer加入到一个队列里,在合适的时候free掉这些队列的transfer,以及transfer里面的buffer。
Android libusb的更多相关文章
- android-serialport-api and libusb for android
libusb for android: Even if you get it compiled, Android is probably not going to let you access the ...
- libusb: android上集成libusb库
1. 下载libusb库. 可以到libusb库的官网(https://libusb.info/)或者是其官方的github仓库(https://github.com/libusb/libusb/re ...
- NFC:Arduino、Android与PhoneGap近场通信
NFC:Arduino.Android与PhoneGap近场通信(第一本全面讲解NFC应用开发的技术著作移动智能设备近距离通信编程实战入门) [美]Tom Igoe(汤姆.伊戈),Don Colema ...
- [安卓]windows下如何安装Android源码
本文改写于:http://www.cnblogs.com/skyme/archive/2011/05/14/2046040.html 1.下载并安装git: 在git-scm.com上下载并安装git ...
- android bluetooth蓝牙移植
http://blog.csdn.net/zhengmeifu/article/details/7705172 前段时间移植神念系统需要使用到bluetooth功能,现将移植过程中碰到的问题简要列一下 ...
- android source
h1 { margin-bottom: 0.21cm } h1.western { font-family: "Liberation Sans", sans-serif; font ...
- 翻译Android USB HOST API
翻译Android USB HOST API 源代码地址:http://developer.android.com/guide/topics/connectivity/usb/host.html 译者 ...
- libusb简介
概述 libusb是一个C库,它提供了通用的访问USB设备. 它的目的是供开发人员使用方便的生产与USB通信硬件的应用程序. 可移植的: 使用一个跨平台API,它提供了访问USB设备在Linux上,O ...
- fedora 挂载 小米手机 (估计其它android设备也是类似操作)
1 参考ubuntu挂载 在Ubuntu挂载使用MTP设备步骤如下: 1.将MTP设备连接至PC机 2.如果是第一次使用MTP设备需要安装以下软件,否则可以跳过此步骤: $ sudo apt-get ...
- Android USB Host框架
Android 下的usb框架及功能点:https://blog.csdn.net/tianruxishui/article/details/379029591.Android framework中* ...
随机推荐
- Docker PHP容器安装composer
1.进入php容器docker exec -it cb6c1fe83bff(php容器ID) bash2.安装composerphp -r "copy('https://install.ph ...
- Vue cil路由如何回到初始状态
前景:我们在网页里进入路由的地址后,会发现地址栏中会加上我们的路由地址,这样我就知道当前在哪个位置.但是这样子我们如何手动刷新浏览器,想要浏览器回到根路径的话,是无法直接回去的,因为地址没有更改.再怎 ...
- 一键导入抓包数据生成HTTP请求
Jmeter一键导入抓包数据生成HTTP请求.路径:工具->Import from cURL 在弹框里粘贴cURL,点击"Create Test Plan"会自动生成HTTP ...
- Python和RPA网页自动化-浏览器切换不同窗口页面
以百度为例,点击[BOSS直聘]词条会打开一个BOSS新窗口页面,分别使用Python和RPA网页自动化在不同的窗口页面来回切换窗口完成以下顺序步骤 1.Python代码如下 步骤:打开新窗口页面后, ...
- Apache COC闪电演讲总结【OSGraph】
大家能看到我最近一直在折腾与OSGraph这个产品相关的事情,之前在文章<妙用OSGraph:发掘GitHub知识图谱上的开源故事>中向大家阐述过这个产品的设计理念和应用价值.比方说以下问 ...
- 【Java】Collection 集合框架概述
Collection 集合框架概述 1.集合.数组都是为了存储数据而产生的 2.为什么需要集合?为了更灵活方便的存储数据,且集合能存储的容量比数组更大 3.存储的概念还停留在内存活动范围内,也只是短暂 ...
- 【ECharts】04 数据交互
ECharts 异步加载数据 ECharts 通常数据设置在 setOption 中,如果我们需要异步加载数据,可以配合 jQuery等工具,在异步获取数据后通过 setOption 填入数据和配置项 ...
- 工业机器人的力控(Force Control)
相关: https://baijiahao.baidu.com/s?id=1785676027803650068 机器人编程人员需要提前知道机器人的摩擦力.阻力.质量.重力,等数值,然后建立基于物理模 ...
- jax框架的 Pallas 方式的GPU扩展不可用
说下深度学习框架的GPU扩展功能的部分,也就是使用个人定制化的GPU代码编写方式来为深度学习框架做扩展. 深度学习框架本身就是一种对GPU功能的一种封装和调用,但是由于太high-level,因此就会 ...
- AI大模型 —— 国产大模型 —— 华为大模型
有这么一句话,那就是AI大模型分两种,一种是大模型:另一种是华为大模型. 如果从技术角度来分析,华为的技术不论是在软件还是硬件都比国外的大公司差距极大,甚至有些技术评论者认为华为的软硬件技术至少落后2 ...