vysor原理代码实现(V2.0)
看過 vysor原理以及Android同屏方案 , 我突然想到整個(gè)過程應(yīng)該如何驗(yàn)證的問題。于是反編譯了vysor 最新的apk, 其中的代碼邏輯依然具有很強(qiáng)的借鑒意義。其中通過 shell 環(huán)境下調(diào)用 adb 獲取截屏權(quán)限成為了全篇的亮點(diǎn)所在。以下文字簡(jiǎn)要地記錄了個(gè)人的理解過程,同時(shí)希望增進(jìn)對(duì)Android Framework 的理解。
0. 背景介紹
關(guān)于App的創(chuàng)建
由于 Zygote 在系統(tǒng)啟動(dòng)時(shí)冷啟動(dòng)了一個(gè)Dalvik / ART VM, 并開啟對(duì)創(chuàng)建新APP請(qǐng)求的監(jiān)聽。隨后所有新的應(yīng)用進(jìn)程都由Zygote 執(zhí)行 fork 操作而創(chuàng)建的。具體流程如下所述:
Linux內(nèi)核啟動(dòng)后,就開始了初始化 Android 系統(tǒng)(init process)的過程。/system/bin/app_process 運(yùn)行并啟動(dòng)了 Android運(yùn)行時(shí)(AndroidRuntime.start()),在這期間運(yùn)行時(shí)啟動(dòng)了Dalvik 虛擬機(jī),并且創(chuàng)建了zygote進(jìn)程,以及開啟com.android.server.SystemServer 系統(tǒng)服務(wù)進(jìn)程。Zygote將在有新的應(yīng)用啟動(dòng)時(shí)被激活,為了加速應(yīng)用啟動(dòng)的過程,Zygote會(huì)預(yù)加載公用的Java類和資源到RAM中,以供應(yīng)用在實(shí)際運(yùn)行時(shí)使用。最終,Zygote將fork自己并啟動(dòng)這一新的應(yīng)用進(jìn)程。
?
Android Boot Sequence (from Embedded Android)
?
Java 應(yīng)用與 Android app的差異
典型 Android 應(yīng)用模塊的構(gòu)建流程
?
從以上Android APP的編譯流程上,我們也不難看出:由于Android 平臺(tái)使用了一個(gè)不同于一般 JVM 的虛擬機(jī),這就使得Java class 文件需要額外的處理(即 dex化)之后才能運(yùn)行。
作為一個(gè)"推進(jìn)器",上述 app_process 除了啟動(dòng) Zygote進(jìn)程外,還可以創(chuàng)建其它進(jìn)程。有興趣的讀者可以進(jìn)一步參考鏈接中的 Run a Java main on Android 部分, 在命令行中實(shí)際編譯Java代碼,dex 處理以及通過 adb shell 命令打印出 Android 平臺(tái)上的"Hello World"。
1. 實(shí)現(xiàn)
先上一個(gè)截取屏幕并在瀏覽器中顯示的效果圖:
?
Screen Shot.png
1.0 與截屏的相關(guān)API
在OS 4.3 之前有標(biāo)注為(@hide)的API android.view.Surface.screenshot (); 而4.3之后API變?yōu)?android.view.SurfaceControl.screenshot(). 非root的設(shè)備上,一般的APP是沒有權(quán)限調(diào)用以上的接口的。而在shell 環(huán)境下確實(shí)具備權(quán)限的,而這正一點(diǎn)好成為了一個(gè)突破口。
1.1 代碼入口方法
Java 類Main的靜態(tài)方法 main() 中簡(jiǎn)單實(shí)現(xiàn)了一個(gè) HandlerThread (可類比源碼中ActivityThread.main())。在looper 正在開始處理消息前,啟動(dòng)本地的server, 并設(shè)置對(duì)screenshot GET請(qǐng)求的回調(diào)方法?;卣{(diào)處理過程使用上述的 screenshot() 方法進(jìn)行屏幕截圖,并設(shè)置Bitmap數(shù)據(jù)為對(duì)應(yīng)的 HTTP response。最后設(shè)置 adb forward tcp:53516 tcp:53516 將PC上所有 53516 端口通信數(shù)據(jù)重定向到手機(jī)端 53516 端口server上。
1.2 調(diào)用隱藏的API
在App內(nèi)部,通常在有 Context 的情況下我們可以很方便地獲取系統(tǒng)服務(wù):
WindowManager window = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
而此時(shí)的入口 Main 是由 app_process 啟動(dòng)的一個(gè)獨(dú)立進(jìn)程。于是問題就出現(xiàn)了,如何獲取當(dāng)前屏幕的寬和高呢?想想框架中的 Java 部分代碼是如何進(jìn)行進(jìn)程間通信的,常見的 AIDL 成為了一個(gè)較好的方案。同樣利用框架提供的WINDOW_SERVICE, 我們可以將系統(tǒng)源碼中的 IWindowManager.aidl 拷貝到工程目錄中,利用對(duì)應(yīng)生成的 local stub 通過編譯,運(yùn)行時(shí)通過反射調(diào)用對(duì)應(yīng)所需的服務(wù)。
1.3 自動(dòng)化ADB設(shè)置的命令行工具
有關(guān)命令行工具的實(shí)現(xiàn) cmd_runner.c
已實(shí)現(xiàn)自動(dòng)化的任務(wù)包括 forward/unforward PC網(wǎng)絡(luò)請(qǐng)求,通過管道 (pipe) 跨進(jìn)程通信得到已安裝APP的實(shí)際路徑,以及shell 環(huán)境下調(diào)用 app_process 啟動(dòng)內(nèi)部截圖服務(wù)等。
2. 源碼
目前的源碼已經(jīng)放在github DroidCast,歡迎大家 star 和 fork,并與我交流。
3. 最近更新
-
2018-11-7 支持通過指定的大小截屏并顯示圖片
-
2018-10-30 增加adb設(shè)置說明,支持(相同網(wǎng)段WIFI環(huán)境下)無線使用場(chǎng)景
-
2018-9-5 更新了命令行工具,使其能定位安裝到設(shè)備上的 apk 位置,解決 OS 4.3及以下的設(shè)備上出現(xiàn)的無法找到 class 導(dǎo)致的 crash。
-
2018-4-5 增加 *nix 環(huán)境下 command line tool (C 程序) 簡(jiǎn)化對(duì) adb 命令相關(guān)的設(shè)定和自動(dòng)重置
-
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. 參考引用
-
隱藏的API
截屏相關(guān)(以O(shè)S 5.1.1為例) -
zygote有關(guān)
zygote
understanding android zygote and dalvik vm -
adb forward 命令
http://blog.csdn.net/mars5337/article/details/6395232 -
Network library: AndroidAsync
?
作者:raywalker
鏈接:https://www.jianshu.com/p/791a3ed2a348
來源:簡(jiǎn)書
簡(jiǎn)書著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者獲得授權(quán)并注明出處。
總結(jié)
以上是生活随笔為你收集整理的vysor原理代码实现(V2.0)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android截屏方法总结
- 下一篇: 【译】Introducing scrcp