一,背景
自己无意见发现虫洞这个软件,PC可以控制android,发现FPS 非常流程,于是触发我的好奇心,研究几天,大概知道商业用哪种技术。
二,思路
1,网上直接找就是adb shell screencap -p /stcard/xx.png,然后拉取图片,显示图片
这种用我自己的手机测试大概是2秒左右,太迟太大,结合我自己写的c语言的代码,每次启动一个新的adb来截图,所以时间基本更长。
2:上面进化版本 adb exec-out screencap -p > test.png
在手机端不存放普通,通过adb传送数据,写到本地磁盘,这个方案大概1秒左右。但还是像PPT,起码要20FPS稍微流畅一点。不能用adb shell screencap 因为控制台输出,会导致数据不对,貌似换行符号导致。我也是在google好久才找到这个办法。
3:使用ADB协议,不用每次截图启动进程,
我用的node js adbkit,实现ADB协议,貌似各种语言的都有,用脚本或者c#感觉比较方便一些。这个时候我就抛弃了c++,因为对一些图像渲染不熟悉,我把一个老外的sdl1版本改成sdl2,增加模拟点击算法,但用起来nodejs 就简单更多,直接用html 加载 base64 image即可。这个消耗时间大概260ms,所以看起来大概有一秒左右延迟,但只是偶尔棘突,采用这个方案未必不是好事情,因为不需要那么流程。而且类库很少就是使用adb 协议即可。简单远程也没有太多问题。【有时间我整理一下这个代码,直接丢出来,给有用的人,起码不要自己研究了】
4:使用adbkit frambuffer 接口,获取原始图像的数据(rgba)
貌似他这个有bug,代码肯定不对,只能拿到元素rgba的数据,他虽然提供格式png等等,但貌似代码是错误的,他根本就没有传送原始流,貌似接口回调跟他们文档对不上,我自己用jimp转换成png,然后传给网页,结果延迟大概要5秒,因为原始流没有压缩,我自己用小米10,得到元素流有8M,加上转换,传送发送5秒左右,难道adbkit 说screencap 接口比frambuffer快几倍。这个时候我在如果在android获取原始像素,然后压缩png或者其他格式,传送是不是快很多。
5:使用Minicap,达到实时传送【基本0延迟】
github上面有他们代码,我直接用airtest编译好的,用他们工具,他直接会放到local\tmp目录,我主要嫌弃编译麻烦,自己对android ndk编译没有玩过。你可以用airtest直接跑,直接连接设备,就可以点击。然后我使用了一下命令测试一下,基本实时。
三,minicap大概原理
调用aosp 私有API 获取屏幕像是图像,因为用私有API,所以必须编译aosp ,导出SO,给minicap调用,github libs里面含有到29的版本,网易的airtest到30版本了,不同android 必须编译对应so. 这个是我的理解,具体很深细节不太了解。
我思考一个技术实现,通过ADB开启远程调试,然后在android用java实现一个adb协议读取framebuffer数据然后压缩再传送给PC端,这样子延迟不是慢不慢,但不知道用adb 读取framebuffer到底慢不慢。
实现远程点击坐标转换很简单,x1/x2 = y1 /y2 ,只要计算比例即可,显示图片大小与手机大小比就可以了,html 直接监听点击转换手机坐标即可。
上面我心理路程全部写了,如果想实现实时控制手机,基本用minicap就可以了,其他方案都太慢了。这里前提是使用adb 模拟点击,你用辅助服务器 加上android 5.0 截图 api 那是另外一种事情
更新:
minicap 编译是可执行程序,可以直接adb shell 执行指定程序,然后利用编译android 底层so,调用私有api,每个版本android都要单独编译,如果系统魔改估计会有问题,毕竟二进制不一样。adnroid c++底层比较不是给外部用的,这个比java 非SDK api稳定性差多了。
srccpy 和 vysor 用的是java 层的反射 + 加上 app_process【获取高级权限】,这个就不用底层系统so,而且这些软件基本采用录屏,具体逻辑和细节在下一篇文章
我后面分析虫洞他的技术用的就是srccpy开源代码改的【基本差不多】