vysor原理代码实现

看过 vysor原理以及Android同屏方案 , 我突然想到整个过程应该如何验证的问题。于是反编译了vysor 最新的apk, 其中的代码逻辑依然具有很强的借鉴意义。其中通过 shell 环境下调用 adb 获取截屏权限成为了全篇的亮点所在。以下文字简要地记录了个人的理解过程,同时希望增进对Android Framework 的理解。

0. 背景介绍

关于App的创建

由于 Zygote 在系统启动时冷启动了一个Dalvik / ART VM, 并开启对创建新APP请求的监听。随后所有新的应用进程都由Zygote 执行 fork 操作而创建的。具体流程如下所述:

Linux内核启动后,就开始了初始化 Android 系统(init process)的过程。/system/bin/app_process 运行并启动了 Android运行时(AndroidRuntime.start()),在这期间运行时启动了Dalvik 虚拟机,并且创建了zygote进程,以及开启com.android.server.SystemServer 系统服务进程。Zygote将在有新的应用启动时被激活,为了加速应用启动的过程,Zygote会预加载公用的Java类和资源到RAM中,以供应用在实际运行时使用。最终,Zygote将fork自己并启动这一新的应用进程。

Android Boot Sequence (from Embedded Android)

Java 应用与 Android app的差异

典型 Android 应用模块的构建流程

从以上Android APP的编译流程上,我们也不难看出:由于Android 平台使用了一个不同于一般 JVM 的虚拟机,这就使得Java class 文件需要额外的处理(即 dex化)之后才能运行。

作为一个"推进器",上述 app_process 除了启动 Zygote进程外,还可以创建其它进程。有兴趣的读者可以进一步参考链接中的 Run a Java main on Android 部分, 在命令行中实际编译Java代码,dex 处理以及通过 adb shell 命令打印出 Android 平台上的"Hello World"。

1. 实现

先上一个截取屏幕并在浏览器中显示的效果图:


Screen Shot.png

1.0 与截屏的相关API

在OS 4.3 之前有标注为(@hide)的API android.view.Surface.screenshot (); 而4.3之后API变为 android.view.SurfaceControl.screenshot(). 非root的设备上,一般的APP是没有权限调用以上的接口的。而在shell 环境下确实具备权限的,而这正一点好成为了一个突破口。

1.1 代码入口方法

Java 类Main的静态方法 main() 中简单实现了一个 HandlerThread (可类比源码中ActivityThread.main())。在looper 正在开始处理消息前,启动本地的server, 并设置对screenshot GET请求的回调方法。回调处理过程使用上述的 screenshot() 方法进行屏幕截图,并设置Bitmap数据为对应的 HTTP response。最后设置 adb forward tcp:53516 tcp:53516 将PC上所有 53516 端口通信数据重定向到手机端 53516 端口server上。

1.2 调用隐藏的API

在App内部,通常在有 Context 的情况下我们可以很方便地获取系统服务:

WindowManager window = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

而此时的入口 Main 是由 app_process 启动的一个独立进程。于是问题就出现了,如何获取当前屏幕的宽和高呢?想想框架中的 Java 部分代码是如何进行进程间通信的,常见的 AIDL 成为了一个较好的方案。同样利用框架提供的WINDOW_SERVICE, 我们可以将系统源码中的 IWindowManager.aidl 拷贝到工程目录中,利用对应生成的 local stub 通过编译,运行时通过反射调用对应所需的服务。

1.3 自动化ADB设置的命令行工具

类Unix系统上的工具 [cmd_runner.c] (https://github.com/rayworks/DroidCast/blob/master/cmd_tool/cmd_runner.c#L284).

为达到跨平台功能,最近更新的 python 脚本 (Python 2.7.15)
已实现了自动化启用截图功能,其中包括 adb forward/unforward PC网络请求,通过管道 (pipe) 跨进程通信得到已安装APP的实际路径,以及 shell 环境下调用 app_process 启动内部截图服务等。

对于已连接的单台设备/模拟器,默认调用:

python scripts/automation.py

即可在自动打开的默认浏览器中查看已连接设备的瞬时截图。

2. 源码

目前代码已经放在github DroidCast,欢迎大家 star 和 fork,并与我交流。

3. 最近更新

  • 2019-12-9 使用 ip 命令替换ifconfig获取设备IP地址,避免执行时的权限问题

  • 2019-11-5 独立脚本支持Python 3.6+

  • 2019-9-11 迁移到 AndroidX

  • 2019-8-22 利用Python 2to3 转换工具,支持Python 3.6+

  • 2019-5-30 Python 脚本中支持在有多个连接的设备时,对选定设备进行操作。

  • 2019-5-18 用 Python 脚本自动化实现 adb 命令相关的设定和自动重置,以及打开默认浏览器查看截图

  • 2019-5-7 增加对 websocket 的支持,在屏幕旋转后 web 页面自动刷新显示新截图

  • 2019-4-14 支持不同格式的image请求(png, jpeg, webp)以及屏幕旋转后的截图

  • 2019-2-28 适配 Android Pie

  • 2019-2-16 更新命令行工具,实现自动打开默认浏览器查看截图

  • 2018-11-7 支持通过指定的大小截屏并显示图片

  • 2018-10-30 增加adb设置说明,支持(相同网段WIFI环境下)无线使用场景

  • 2018-9-5 更新了命令行工具,使其能定位安装到设备上的 apk 位置,解决 OS 4.3及以下的设备上出现的无法找到 class 导致的 crash。

  • 2018-4-5 增加 *nix 环境下 command line tool (C 程序) 简化对 adb 命令相关的设定和自动重置

  • 2018-3-28 解决OS 8.0 下 加载 base.apk 失败的问题

  • You can no longer assume that APKs reside in directories whose names end in -1 or -2. Apps should use sourceDir to get the directory, and not rely on the directory format directly.

4. 参考引用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,451评论 25 707
  • Android Studio JNI流程首先在java代码声明本地方法 用到native关键字 本地方法不用去实现...
    MigrationUK阅读 11,839评论 7 123
  • 1:InputChannel提供函数创建底层的Pipe对象 2: 1)客户端需要新建窗口 2)new ViewRo...
    自由人是工程师阅读 5,246评论 0 18
  • 我不想象牲口一样活下去时,人己到中年。华服、美食、灯红酒绿尽管日日在城市上演喜剧,内心深处向往的依然是一片空远辽...
    绿木木子阅读 305评论 0 1
  • 1. 我梦中遇见你 你叫等等 爱涂绿色的面膜 喜欢和我一起吃火锅 我上班迟到了 因为梦境中的路和现实中的不一样 梦...
    小红帽Jane阅读 647评论 0 3