編譯 Jack (Android 開放原始碼計畫 6.0 - 8.1)

Jack 是 Android 6.0 至 8.1 的預設 Android 建構工具鍊

Jack 是 Android 工具鍊,可將 Java 來源編譯為 Android DEX 位元碼。您不必採取任何其他動作即可使用 Jack,只要使用標準的 makefile 指令編譯樹狀結構或專案即可。Android 8.1 是最後一個使用 Jack 的版本。

關於 Jack

Jack 的運作方式如圖 1 所示。

Jack 簡介。

圖 1. Jack 簡介。

Jack 程式庫格式

Jack 有自己的 .jack 檔案格式,其中包含程式庫的預先編譯 dex 程式碼,可加快編譯作業 (預先 dex)。

Jack 程式庫檔案內容。

圖 2. Jack 程式庫檔案內容。

Jill

如下圖所示,Jill 工具會將現有的 .jar 程式庫轉譯為新的程式庫格式。

匯入現有 `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_SERVICESERVER_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。

使用預先 Dex 的 Jack 程式庫。

圖 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