Android Qemu免Root直通USB设备
系统只因酱 Lv114514

文章代号:android-qemu-usb-withoutroot

教程部分操作参考: https://github.com/termux/termux-packages/issues/19635

视频教程

哔哩哔哩:BV1YSenefEo9

前言

几个月前我做过一期教程(BV1PZ42187NY)提供了一种在手机Qemu中直通USB的思路,不过呢那个条件有些苛刻,比如需要Root,这就已经将很多人“拒之门外”了;使用起来也有诸多限制,例如不支持热插拔(这个真的很烦,稍微不注意线碰掉了就得重开虚拟机),如果你用的VirtualHere方案的,系统要是Windows10 x64以上,还必须有WiFi网络。

前几天偶然发现Termux里有个名为termux-usb的软件包很有意思,使用Android的OTG API来不Root获取USB访问权限,就突发奇想:能不能和Qemu配合使用呢?答案是真的可以。而且不用网络不要求操作系统支持热插拔,你愿意的话还能直通局域网内其它设备的USB,所以即使你已经Root也可以用起来,比之前那个方法好用100倍。

(如果你已经Root的话,那就不用termux-usb了,同时系统也不必支持OTG API。把我教程的命令改一下使用sudo运行usbredicter再结合那个视频的方法自己研究。就不详细教学了,既然你已经Root了我相信这些小技能你还是会的)

大致原理如下: 使用一个名为usbredicter的软件包通过termux-usb API获取USB访问权限,在本地指定网络端口创建一个接口,proot容器里的Qemu通过这个网络接口获取USB使用权。

注意事项(一定要看)

  • 没有Root的话手机必须支持OTG API(只要不是特别古董的一般都会支持)

  • 如果你的手机是新款并且在接下来的某一步操作没反应,那可能是你的系统阉割了这个特性,这里建议刷类原生或者国际版

  • 设置里如果有开启OTG权限的选项一定要打开

  • 每次使用都要按照5.2的步骤重新授权

  • 如果有多个USB设备可以在屏幕左侧边缘一次性下滑再左滑呼出侧边栏,点击New Session创建新的终端并重复操作步骤

  • Qemu那里如果报Connection refused 就去检查下usbredirect进程是否意外退出

环境要求

建议在Termux中的Proot/Chroot容器中运行的原生Qemu

注:不支持Limbo虚拟机,因为Qemu版本太低了

(如果你因为这个教程入坑Termux,可以先看这篇专栏 进行配置再网上搜索“termux使用proot运行qemu教程”,然后到cv21056621 学一下如何启动qemu。前往F-droid下载Termux的APK安装包)

准备工作

1.到这里下载并安装Termux API的apk

2.有条件的打开你的梯子

正式部分

安装termux-usb

1
pkg install termux-api libusb clang -y

授权USB访问

连接你的USB设备,输入termux-usb -l列出设备。

输出示例:

[
  "/dev/bus/usb/001/003"
]

/dev/bus/usb/001/003代表USB设备的文件路径(Linux下一切皆文件),记住等下会用到

这里因人而异,记住你自己的

接着获取USB访问权限

1
termux-usb -r /dev/bus/usb/001/003

等一两秒会弹出一个授权框,点击确认。

如果输出Access granted代表授权成功;如果等了很久还是没有输出的话可以先按Ctrl+C然后参照Termux Wiki验证可访问性。

验证可访问性

先编译一下测试程序

1
wget 'https://gist.githubusercontent.com/bndeff/8c391bc3fd8d9f1dbd133ac6ead7f45e/raw/6d7174a129301eeb670fe808cd9d25ec261f7f9e/usbtest.c'
1
gcc usbtest.c -lusb-1.0 -o usbtest

接着运行,记得把路径改成自己的

1
termux-usb -e ./usbtest /dev/bus/usb/001/003

稍等片刻,会看到指定路径USB设备的基本信息,成功输出:

Vendor ID: 0781
Product ID: 5567
Manufacturer:  USB
Product:  SanDisk 3.2Gen1
Serial No: 0401d642696d418d92d6e77f095c4a788cba4feb64bafc16dd8b083c0746389ed8f40000000000000000000073564d92ff0e7f1867558107852f280a

编译并安装usbredicter

因为原版的usbredicter不支持termux-usb,尝试运行会输出Failed to init libusb错误,因此需要修改一下代码以适配termux-usb。

不过不必担心,已经有现成的修改代码(虽然不是我写的),我放在链接里了,文件名是usbredicter.c,先下载下来等会用。

使用git克隆usbredir仓库

先输入pkg install git -y安装git,然后克隆

1
git clone https://gitlab.freedesktop.org/spice/usbredir.git

复制以下命令安装meson和ninja

1
2
pkg install python3 ninja -y
pip install meson

修改源代码

复制你下载下来的usbredirect.c的完整路径(可以使用MT管理器查看文件属性,在弹出的窗口长按文件路径获取),然后使用mv将其覆盖,例如

1
mv /storage/emulated/0/Download/usbredirect.c usbredir/tools/usbredirect.c

使用nano编辑器(可以输入pkg install nano -y安装)编辑meson.build

1
nano usbredir/meson.build

使用方向键移动光标,定位到第7行的warning_level=1,将1改为0

依次按Ctrl+XY回车保存并退出。

编译usbredir

1
2
3
4
5
mkdir usbredir/build
cd usbredir/build
meson ..
meson compile
chmod +x tools/usbredirect

运行~/usbredir/build/tools/usbredirect ,正常会输出一段帮助文本。

注意不要移动任何可执行文件,否则会报错。

创建USB设备网络接口

使用termux-usb运行usbredirect:

1
termux-usb -e  "/data/data/com.termux/files/home/usbredir/build/tools/usbredirect --device /dev/bus/usb/001/003 --as 127.0.0.1:23456" /dev/bus/usb/001/003

注意路径要改成自己的,两处都要改;网络端口在1024-65535之间随便取一个即可。

等大约半分钟,看到终端输出USB设备的基本信息即为创建成功。

配置Qemu启动脚本

在屏幕左侧边缘一次性下滑再左滑呼出侧边栏,点击New Session创建新的终端,在新的终端下,进入你的容器,并编辑Qemu启动脚本

在启动脚本末尾加上:

1
2
3
-monitor stdio \
-chardev socket,host=127.0.0.1,port=23456,id=usbredirchardev1 \
-device usb-redir,chardev=usbredirchardev1,id=usbredirdev1,debug=3

-chardev选项中,将port替换为自己的端口号。如果有多个USB设备,需要为每个设备添加一行-chardev配置。

id字段用来为每个设备指定一个名称。你可以自由选择这个名称。请确保在-device选项中,chardev=后面的名称与-chardev选项中指定的名称一致。

-device选项中的id是另一个独立的标识符。请确保这个id-chardev选项中的id不同,以避免冲突。

以上所有id都要记住,等下热插拔的时候要用

注意要给Qemu一个USB控制器。

启动Qemu

保存退出后,运行你的启动脚本。

启动的时候如果看到qemu-system-x86_64: usb-redir: attaching high speed device 0781:5567 version 1.0 class 00,那么恭喜你,成功了!

按下回车后,可以查看qemu内usb设备的基本信息

1
(qemu) info usb

示例输出:

Device 0.1, Port 1, Speed 480 Mb/s, Product QEMU USB Tablet
Device 0.2, Port 2, Speed 480 Mb/s, Product USB Redirection Device, ID: usbredirdev1

USB Redirection Device就是你的USB设备,注意前面的speed如果不是480而是1.5,说明USB设备可能断开连接了,重复教程的步骤重新连接。

一切顺利的话,开机后就能看到你的USB设备啦!

image

附:热插拔

如果你在虚拟机运行的时候把USB设备拔掉并重新插回来的时候,你会发现Qemu无法识别了!这是因为当你拔掉时,Android会撤销Termux对这个USB设备的访问权限,所以当你这个时候回到终端时就会看到usbredicter报错退出了。别担心,重新授权一遍即可。

不过呢,你也需要在QEMU Monitor中删除现有的USB Redictertion设备设备并重新添加。

步骤如下:

(qemu) device_del usbredirdev1
(qemu) chardev-add socket,host=127.0.0.1,port=23456,id=usbredirchardev2
(qemu) device_add usb-redir,chardev=usbredirchardev2,id=usbredirdev1,debug=3

懒得打字了,让chatgpt帮我解释下命令吧:

  • (qemu) device_del usbredirdev1

    • 作用: 删除一个叫做 usbredirdev1 的 USB 设备。
    • 解释: 如果你有一个 USB 设备在虚拟机里运行,这个命令会把它移除掉。
  • (qemu) chardev-add socket,host=127.0.0.1,port=23456,id=usbredirchardev2

    • 作用: 创建一个新的通信通道,用来连接虚拟机和主机。
    • 解释: 这个命令设置了一个新的连接方式,虚拟机将通过这个连接方式与主机上的服务进行交流。连接的地址是 127.0.0.1,端口号是 23456,这个通道的名字叫 usbredirchardev2
  • (qemu) device_add usb-redir,chardev=usbredirchardev1,id=usbredirdev1,debug=3

    • 作用: 添加一个新的 USB 设备到虚拟机。
    • 解释: 这个命令把一个新的 USB 设备添加到虚拟机中。这个设备通过之前设置的连接通道 usbredirchardev1 与主机上的服务沟通。这个设备的名字是 usbredirdev1,并且设置了更详细的调试信息以帮助解决问题。

注意,在使用 chardev-add 时,ID 必须取一个另外的,否则会报Duplicate ID。而 device_add 的 ID 则可以与启动脚本中的相同。

每次拔出设备后usbredirect就会退出,要手动回到之前的那个终端运行。

 评论
评论插件加载失败
正在加载评论插件