Jack 是 Android 6.0 至 8.1 的預設 Android 建構工具鍊
Jack 是 Android 工具鍊,可將 Java 來源編譯為 Android dex 位元碼。使用 Jack 時,您不必採取任何其他行動,只要使用標準的 makefile 指令編譯樹狀結構或專案即可。Android 8.1 是最後一個使用 Jack 的版本。
關於 Jack
插孔的運作方式如圖 1 所示。
圖 1. Jack 總覽。
Jack 程式庫格式
Jack 有自己的 .jack 檔案格式,其中包含程式庫的預先編譯 dex 程式碼,可加快編譯速度 (預先 dex)。
圖 2. Jack 程式庫檔案內容。
Jill
如下圖所示,Jill 工具會將現有的 .jar 程式庫轉換為新的程式庫格式。
圖 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 記錄
如果您使用發布目標執行 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,並整合下列其他功能。
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 支援「規則」規則類型,但不支援「Zap」或「保留」規則類型。
支援 Multidex
Jack 提供內建和舊版 multidex 支援。由於 dex 檔案最多只能有 65,000 個方法,因此如果應用程式的方法超過 65,000 個,就必須分割成多個 dex 檔案。詳情請參閱「針對使用超過 64K 方法的應用程式啟用 Multidex」