Android libusb

news/2024/9/18 3:46:16/文章来源:https://www.cnblogs.com/linhaostudy/p/18368190

一、环境:配置NDK环境

1、下载libusb源码: https://github.com/libusb/libusb/releases,如下图所示

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

思考问题:

  1. 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设备,是不是一直都需要这样监听呢?

  1. Android是怎么检测usb设备插拔?
    使用Netlink来实现接收内核消息,读取热插拔信息,它是特殊的socket,使用时设置特定的参数即可监听到内核uevent事件,从而区分插拔事件NETLINK_KOBJECT_UEVENT, groups = 1,如下图所示:

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

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

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

  1. 通过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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/784005.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《花100块做个摸鱼小网站! 》第三篇—热搜表结构设计和热搜数据存储

⭐️基础链接导航⭐️ ☁️ 阿里云活动地址 🐟 上班摸鱼小网站地址 💻 源码库地址一、前言 大家好呀,我是summo,第一篇已经教会大家怎么去阿里云买服务器,以及怎么搭建JDK、Redis、MySQL这些环境。第二篇我们把后端的应用搭建好了,并且完成了第一个爬虫(抖音)。那么这一…

关于STM32H750打破flash--2M限制的简单办法

STM32H750VBTx的flash官方规定只能使用128K的flash,但是其实是可以绕过限制,使用其片内2M的flash空间。 这里介绍一种较为简单的实现的办法,这个办法不同网络上介绍的办法,可以在keil上较轻松地实现。因为它可以使用较高STM32CubeMX(6.12.0)和keil(5.29)的版本。 首先按…

c语言中读入整型数据和浮点型数据

001、读入整型数据[root@PC1 test]# ls test.c [root@PC1 test]# cat test.c ## 测试脚本 #include <stdio.h>int main(void) {int i; //声明整型变量puts("please input an integer.");printf("input an i…

CSP24

学了些DP 学校题库有\(BUG\)首先要满足条件\(x,y\)的二进制有1的位必然包含\(a\),然后让\(s-2a\),也就是除去二进制包含\(a\)有1的位,然后\(<0\)肯定无解,其次是如果有与\(a\)同一级的含\(1\)二进制位也不合法点击查看代码 #include <bits/stdc++.h> #define speed()…

用for循环输出数组与初识增强for循环

1.定义一个数组2.使用for循环设置编码3.输出带有编码的数组使用增强for循环输出数组 1.依旧是定义数组 2.设置一个新的变量x用于替代数组 3.直接输出变量x即可

线程不安全问题实例

package com.shujia.day19.sellTickets;/*使用Runnable的方式实现为了模拟更加真实的售票情况,我们加入延迟问题:我们加入了延迟之后,发现a. 有重复售卖同一张票的情况(原因1)b. 还出现了一个不该出现的票数据,比如第0张票,第-1张票(原因2)原因:1. cpu小小的时间片,…

24年首批!上海通管通报违规app涉及欧莱雅、玛莎拉蒂

8月16日上海市通信管理局官方微信公众号“上海通信圈”发布《上海市通信管理局关于侵害用户权益行为app的通报(2024年第一批)》。本次app通报为2024年第一批。内容显示本次共通报26款移动互联网应用程序涉及app和小程序。 应用来源:本次检测的应用来源均为主流分发平台如应用…

ControlNeXt: Powerful and Efficient Control for Image and Video Generation(2024,8)

ControlNeXt: Powerful and Efficient Control for Image and Video Generation(2024,8) paper Github 进一步在ControlNet上进行了改进,主要针对一下两点对于每一个模块添加一个Zero-Conv也会占用很多显存. Zero-Conv两个模态的输出的mean、var具有差异,导致收敛很慢.针对1,使…

033、Vue3+TypeScript基础,路由传参时候把层级脱掉

01、Datail.vue代码如下:<template><ul class="news-list"><li>编号:{{ route.query.id }}</li><li>编号:{{ route.query.title }}</li><li>编号:{{ route.query.content }}</li></ul> </template>…

Tarjan 之 SCC 与 缩点

这篇文章将讲述作者对 Tarjan求SCC与缩点(不是割点)的理解 让我们开始吧! Tarjan SCC 与 缩点 既然要求 \(SCC\) 那我们先要弄明白 什么是 SCC SCC 指的是强连通分量 强连通指的是若一张有向图的节点两两互相可达,则这张图是强连通的 而强连通分量 指的是一个极大的连通子图…

马哥教育 c10网络安全 第二周作业 2024/8/17

1、使用 html 写一个网页,要求满足以下条件: (1)网页中含有任意一张图片,图片路径使用绝对路径,鼠标悬停在图片时出现“马哥教育”文本,且点击图片可跳转至马哥教育官方页面 (2)网页中包含账号、密码登录,且账号提前定义好是 admin 且不可更改,输入密码时显示加密形…

FinalShell工具的使用

第1篇 FinalShell工具的使用1.介绍 xshell作为Linux远程连接的工具,教程请看《通过xshell远程连接ubuntu》。但是,xshell是付费软件。于是,找到一个finalshell作为其替换软件。 FinalShell是一体化的的服务器,网络管理软件,不仅是ssh客户端,还是功能强大的开发,运维工具,充分…