Jack 是 Android 6.0 至 8.1 的預設 Android 建構工具鍊,用於將 Java 來源編譯為 Android dex 位元碼,如圖 1 所示:
圖 1. Jack 總覽。
.jack 檔案格式包含程式庫的預先編譯 dex 程式碼,可加快編譯速度 (dex 前置處理)。
圖 2. Jack 程式庫檔案內容。
Jill 工具
如圖 3 所示,Jill 工具會將現有的 .jar 程式庫轉換為新的 .jack 程式庫格式:
圖 3. 匯入現有 .jar 程式庫的工作流程。
Jack 編譯伺服器
第一次使用 Jack 時,系統會在電腦上啟動本機 Jack 編譯伺服器。此伺服器會:
- 可避免在每次編譯時啟動新的主機 JRE JVM、載入 Jack 程式碼、初始化 Jack,以及預熱 JIT,因此可大幅提升速度。此外,在小型編譯期間 (例如在累加模式下),編譯時間也相當短。
- 這是短期解決方案,可控制平行 Jack 編譯的數量。伺服器會限制平行編譯的數量,避免電腦超載 (記憶體或磁碟問題)。
如果閒置一段時間後沒有任何編譯作業,Jack 伺服器就會自行關閉。這項服務會使用本機介面上的兩個 TCP 通訊埠,且無法從外部存取。您可以編輯 $HOME/.jack 檔案,修改所有參數 (例如平行編譯數、逾時和連接埠號碼)。
$HOME/.jack 檔案
$HOME/.jack 檔案包含 Jack 伺服器變數的下列設定,並採用完整 Bash 語法:
SERVER=true可啟用 Jack 的伺服器功能。SERVER_PORT_SERVICE=8072會設定伺服器的 TCP 通訊埠號碼,以供編譯。SERVER_PORT_ADMIN=8073會設定伺服器的 TCP 通訊埠編號,以供管理用途。SERVER_COUNT=1未使用。SERVER_NB_COMPILE=4會設定允許的平行編譯數量上限。SERVER_TIMEOUT=60會設定伺服器必須等待的閒置秒數,之後才會關閉自身。SERVER_LOG=${SERVER_LOG:=$SERVER_DIR/jack-$SERVER_PORT_SERVICE.log}設定伺服器記錄的寫入檔案。根據預設,這個變數可由環境變數多載。JACK_VM_COMMAND=${JACK_VM_COMMAND:=java}會設定用於在主機上啟動 JVM 的預設指令。根據預設,這個變數可以由環境變數過載。
排解 Jack 編譯問題
| 問題 | 動作 |
|---|---|
| 編譯期間電腦沒有回應,或發生 Out of memory 錯誤,導致 Jack 編譯失敗 | 編輯 $HOME/.jack,將 SERVER_NB_COMPILE 變更為較低的值,減少同時編譯的 Jack 數量。 |
| 無法啟動背景伺服器,導致編譯失敗 | 最可能的原因是電腦上的 TCP 連接埠已在使用中。如要變更通訊埠,請編輯 $HOME/.jack (SERVER_PORT_SERVICE 和 SERVER_PORT_ADMIN 變數)。如要解除封鎖,請編輯 $HOME/.jack 並將 SERVER 變更為 false,藉此停用 Jack 編譯伺服器。很抱歉,這會大幅減緩編譯速度,您可能必須使用載入控制項 (make 的選項 -l) 啟動 make -j。 |
| 編譯作業停滯,沒有任何進展 | 如要解除封鎖,請使用 jack-admin kill-server 終止 Jack 背景伺服器,然後移除臨時目錄 (/tmp 或 $TMPDIR) 的 jack-$USER 中所含的臨時目錄。 |
尋找 Jack 記錄
如果您使用 dist 目標執行 make 指令,Jack 記錄檔會位於 $ANDROID_BUILD_TOP/out/dist/logs/jack-server.log。否則,您可以執行 jack-admin server-log 找出記錄。如果 Jack 失敗可重現,您可以設定下列變數,取得更詳細的記錄:
export ANDROID_JACK_EXTRA_ARGS="--verbose debug --sanity-checks on -D sched.runner=single-threaded"
使用標準 makefile 指令編譯樹狀結構 (或專案),並附加標準輸出和錯誤。如要移除詳細的建構記錄,請執行:
unset ANDROID_JACK_EXTRA_ARGS
耳機插孔限制
根據預設,電腦上只有一位使用者可以存取 Jack 伺服器。如要支援更多使用者,請為每位使用者選取不同的連接埠號碼,並相應調整 SERVER_NB_COMPILE。您也可以在 $HOME/.jack 中設定 SERVER=false,停用 Jack 伺服器。由於目前的 vm-tests-tf 整合,CTS 編譯速度緩慢。不支援位元碼操控工具 (例如 JaCoCo)。
使用 Jack
Jack 支援 Java 程式設計語言 1.7,並整合本節所述的其他功能。使用標準 makefile 指令編譯樹狀結構或專案。
Pre-dex
產生 Jack 程式庫檔案時,系統會產生程式庫的 .dex,並以 DEX 前置處理的形式儲存在 .jack 程式庫檔案中。編譯時,Jack 會重複使用每個程式庫的 DEX 前置處理。所有程式庫都已預先 dex 化。
圖 4. 使用預先 Dex 的 Jack 程式庫。
如果編譯時使用縮減、模糊處理或重新封裝,Jack 就不會重複使用程式庫預先 dex。
增量編譯
增量編譯是指只重新編譯上次編譯後變更的元件 (及其依附元件)。如果變更僅限於一組元件,增量編譯的速度會比完整編譯快上許多。
增量編譯功能預設為停用 (啟用縮減、混淆、重新封裝或多重 DEX 舊版功能時,系統會自動停用增量編譯功能)。如要啟用漸進式建構作業,請在要漸進式建構的專案 Android.mk 檔案中加入下列程式碼:
LOCAL_JACK_ENABLED := incremental
縮減和模糊處理
Jack 會使用 ProGuard 設定檔啟用縮減和模糊處理功能。常見選項包括:
@-include-basedirectory-injars-outjars(僅支援 1 個輸出 JAR)-libraryjars-keep-keepclassmembers-keepclasseswithmembers-keepnames-keepclassmembernames-keepclasseswithmembernames-printseeds
縮減選項包括:
-dontshrink
混淆處理選項包括:
-dontobfuscate-printmapping-applymapping-obfuscationdictionary-classobfuscationdictionary-packageobfuscationdictionary-useuniqueclassmembernames-dontusemixedcaseclassnames-keeppackagenames-flattenpackagehierarchy-repackageclasses-keepattributes-adaptclassstrings
系統會忽略下列選項:
-dontoptimize(Jack 未最佳化)-dontpreverify(Jack 不會預先驗證)-skipnonpubliclibraryclasses-dontskipnonpubliclibraryclasses-dontskipnonpubliclibraryclassmembers-keepdirectories-target-forceprocessing-printusage-whyareyoukeeping-optimizations-optimizationpasses-assumenosideeffects-allowaccessmodification-mergeinterfacesaggressively-overloadaggressively-microedition-verbose-dontnote-dontwarn-ignorewarnings-printconfiguration-dump
重新包裝
Jack 會使用 jarjar 設定檔重新封裝。Jack 與 rule 規則類型相容,但與 zap 或 keep 規則類型不相容。
支援 Multidex
Jack 提供內建和舊版 multidex 支援。由於 dex 檔案最多只能有 65,000 個方法,因此如果應用程式的方法超過 65,000 個,就必須分割成多個 dex 檔案。詳情請參閱「針對使用超過 64K 方法的應用程式啟用 Multidex」。