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
檔案以完整 bash 語法包含下列 Jack 伺服器變數的設定:
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 編譯失敗 | 如要減少同時進行的 Jack 編譯作業數,請編輯 $HOME/.jack ,並將 SERVER_NB_COMPILE 變更為較低的值。 |
編譯在無法啟動背景伺服器上失敗 | 最有可能的原因是電腦已使用 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
。您也可以停用 Jack 伺服器,方法是在 $HOME/.jack
中設定 SERVER=false
。由於目前的 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」一文。