Jack 是 Android 6.0 至 8.1 的預設 Android 建構工具鍊
Jack 是 Android 工具鍊,可將 Java 來源編譯為 Android DEX 位元碼。您不必採取任何其他動作即可使用 Jack,只要使用標準的 makefile 指令編譯樹狀結構或專案即可。Android 8.1 是最後一個使用 Jack 的版本。
關於 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 編譯問題
問題 | 動作 |
---|---|
電腦在編譯期間無回應,或是 Jack 編譯作業因記憶體不足錯誤而失敗 | 編輯 $HOME/.jack 並將 SERVER_NB_COMPILE 變更為較低的值,即可減少同時進行的 Jack 編譯作業數量。 |
編譯作業無法成功,因為無法啟動背景伺服器 | 最可能的原因是電腦上已使用 TCP 通訊埠。如要變更連接埠,請編輯 $HOME/.jack (SERVER_PORT_SERVICE 和 SERVER_PORT_ADMIN 變數)。如要解除封鎖,請編輯 $HOME/.jack 並將 SERVER 變更為 false ,藉此停用 Jack 編譯伺服器。很抱歉,這會大幅減緩編譯速度,並可能迫使您使用負載控制項啟動 make -j (make 的 -l 選項)。 |
編譯作業卡住,沒有任何進度 | 如要解除封鎖狀態,請使用 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,並整合下文所述的其他功能。
DEX 前置處理
產生 Jack 程式庫檔案時,程式庫的 .dex
會產生並儲存在 .jack
程式庫檔案中,做為前置 DEX。在編譯時,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」