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操作生成子程序,並啟動這一新的應用程序。
Java 應用與 Android app的差異
從以上Android APP的編譯流程上,我們也不難看出:由於Android 平臺使用了一個不同於一般 JVM 的虛擬機器,這就使得Java class 檔案需要額外的處理(即 dex化)之後才能執行。作為一個"推進器",上述 app_process
除了啟動 Zygote
程序外,還可以建立其它程序。有興趣的讀者可以進一步參考連結中的 Run a Java main on Android 部分, 在命令列中實際編譯Java程式碼,dex
adb shell
命令打印出 Android 平臺上的"Hello World"。
1. 實現
先上一個擷取螢幕並在瀏覽器中顯示的效果圖:
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設定的命令列工具
有關命令列工具的實現 cmd_runner.c
已實現自動化的任務包括 forward/unforward PC網路請求,通過管道 (pipe) 跨程序通訊得到已安裝APP的實際路徑,以及shell 環境下呼叫 app_process
啟動內部截圖服務等。
2. 原始碼
目前的原始碼已經放在github DroidCast,歡迎大家 star 和 fork,並與我交流。
3. 最近更新
-
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. 參考引用
-
隱藏的API 截圖相關(以OS 5.1.1為例)
-
adb forward 命令 blog.csdn.net/mars5337/ar…