Jack 是一個將 Java 源代碼編譯成 Android dex 字節碼的 Android 工具鏈。您不必做任何不同的事情來使用 Jack — 只需使用您的標準 makefile 命令來編譯樹或您的項目。 Android 8.1 是最後一個使用 Jack 的版本。
關於傑克
Jack 的工作方式如圖 1 所示。
傑克庫格式
Jack 有自己的.jack
文件格式,其中包含庫的預編譯 dex 代碼,允許更快的編譯(pre-dex)。
吉爾
Jill 工具將現有的.jar
庫轉換為新的庫格式,如下所示。
.jar
庫的工作流程傑克編譯服務器
第一次使用 Jack 時,它會在您的計算機上啟動本地 Jack 編譯服務器。該服務器:
- 帶來內在的加速,因為它避免了啟動新的主機 JRE JVM、加載 Jack 代碼、初始化 Jack 以及在每次編譯時預熱 JIT。它還在小型編譯期間提供了非常好的編譯時間(例如,在增量模式下)。
- 是控制並行 Jack 編譯數量的短期解決方案。服務器避免了計算機過載(內存或磁盤問題),因為它限制了並行編譯的數量。
Jack 服務器在沒有任何編譯的空閒時間後自行關閉。它在 localhost 接口上使用兩個 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 編譯因內存不足錯誤而失敗 | 通過編輯$HOME/.jack 並將SERVER_NB_COMPILE 更改為較低的值來減少同時進行 Jack 編譯的數量。 |
編譯失敗無法啟動後台服務器 | 最可能的原因是您的計算機上已使用 TCP 端口。通過編輯$HOME/.jack ( SERVER_PORT_SERVICE 和SERVER_PORT_ADMIN 變量)更改端口。要解除阻塞,請通過編輯$HOME/.jack 並將SERVER 更改為false 來禁用 Jack 編譯服務器。不幸的是,這會顯著減慢您的編譯速度,並可能迫使您使用負載控制啟動make -j (選項-l 的make )。 |
編譯卡住沒有任何進展 | 要解除阻塞,請使用jack-admin kill-server 殺死 Jack 後台服務器,然後刪除臨時目錄的jack-$USER 中包含的臨時目錄( /tmp 或$TMPDIR )。 |
尋找傑克日誌
如果您使用 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 支持 Java 編程語言 1.7 並集成了以下描述的附加功能。
預索引
生成 Jack 庫文件時,會生成庫的.dex
並將其作為 pre-dex 存儲在.jack
庫文件中。編譯時,Jack 重用每個庫中的 pre-dex。所有庫都是預先索引的。
如果在編譯中使用了壓縮、混淆或重新打包,Jack 不會重用庫 pre-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
(傑克不預先驗證) -
-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”規則類型不兼容。
多索引支持
Jack 提供原生和傳統的 multidex 支持。由於 dex 文件限制為 65K 方法,因此方法超過 65K 的應用必須拆分為多個 dex 文件。有關更多詳細信息,請參閱為具有超過 64K 方法的應用啟用 multidex 。