Android 6.0~8.1 での Jack を使用したコンパイル

Jack は Java ソースを Android dex バイトコードにコンパイルする Android ツールチェーンです。Jack を使用するために特別なことをする必要はありません。標準の makefile コマンドを使用して、ツリーやプロジェクトをコンパイルできます。Jack を使用する最後のリリースは、Android 8.1 です。

Jack について

Jack は図 1 のように動作します。

Jack の概要
図 1. Jack の概要

Jack のライブラリ形式

Jack には、独自の .jack ファイル形式があり、ライブラリ用にあらかじめコンパイルされた dex コードを含んでいます。これにより、コンパイルが高速化します(pre-dex)。

Jack のライブラリ ファイルの内容
図 2. Jack のライブラリ ファイルの内容

Jill

以下のように、Jill ツールは既存の .jar ライブラリを新しいライブラリ形式に変換します。

Jill を使用した .jar ライブラリのインポート
図 3. 既存の .jar ライブラリをインポートするワークフロー

Jack コンパイル サーバー

初めて Jack を使用する場合、コンピュータでローカル Jack コンパイル サーバーが起動します。このサーバーは次のような特長を備えています。

  • 新しいホスト JRE JVM の起動、Jack コードの読み込み、Jack の初期化、各コンパイル時の JIT のウォームアップを避けられるため、本質的な高速化が可能です。また、小規模なコンパイル(インクリメンタル モードなど)の場合には、コンパイル時間が非常に短くなります。
  • Jack での並列コンパイル数を制御するための短期的なソリューションです。このサーバーは、並列コンパイル数を制限するので、コンピュータ(メモリあるいはディスク)への過負荷を避けられます。

Jack サーバーは、コンパイル作業のないアイドル状態の後、シャットダウンします。localhost インターフェースでは 2 つの 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/.jackSERVER_PORT_SERVICE および SERVER_PORT_ADMIN 変数)を編集してポートを変更します。状況を打開するために、$HOME/.jack を編集して SERVERfalse にすることで、Jack コンパイル サーバーを無効にします。これにより、残念ながらコンパイルが大幅に遅くなり、負荷制御(make のオプション -l)を使用して make -j を強制的に実行せざるを得ない場合があります。
コンパイルがスタックして進まない 状況を打開するには、jack-admin kill-server を使用して Jack のバックグラウンド サーバーを強制終了します。その後、ユーザーの一時ディレクトリ(/tmp または $TMPDIR)内の jack-$USER に含まれる一時ディレクトリを削除します。

Jack ログの検索

make コマンドを dist ターゲットで実行する場合、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 の制限

  • デフォルトでは、Jack サーバーは 1 台のコンピュータ上の 1 人のユーザーのみが使用できます。ユーザーを追加するには、ユーザーごとに異なるポート番号を選択し、SERVER_NB_COMPILE を調整します。また、$HOME/.jackSERVER=false を設定して、Jack サーバーを無効にできます。
  • 現在、vm-tests-tf 統合により CTS コンパイルは低速です。
  • バイトコード操作ツール(JaCoCo など)はサポートされていません。

Jack の使用

Jack は Java プログラミング言語 1.7 をサポートしており、以下で説明する追加機能を備えています。

pre-dex

Jack ライブラリ ファイルを生成すると、ライブラリの .dex が生成され、.jack ライブラリ ファイル内に pre-dex として保存されます。コンパイル時には、各ライブラリの pre-dex が再利用されます。すべてのライブラリは pre-dex されています。

pre-dex を使用する Jack ライブラリ
図 4. pre-dex を使用する Jack ライブラリ

コンパイルで縮小、難読化、再パッケージ化が指定される場合、pre-dex ライブラリは再利用されません。

インクリメンタル コンパイル

インクリメンタル コンパイルとは、最後にコンパイルした後に変更されたコンポーネントとその依存関係のみを再コンパイルすることです。変更がコンポーネント セットのみの場合、インクリメンタル コンパイルによってフルコンパイルに比べ大幅な高速化が可能です。

インクリメンタル コンパイルは、デフォルトでは無効です。また、縮小、難読化、再パッケージ化、multi-dex レガシーが有効になると、自動的に無効化されます。インクリメンタル ビルドを有効にするには、インクリメンタル ビルドを行うプロジェクトの Android.mk ファイルに次の行を追加します。

LOCAL_JACK_ENABLED := incremental

縮小と難読化

Jack では、縮小と難読化の有効化に ProGuard 構成ファイルが使用されます。

一般的なオプションは次のとおりです。

  • @
  • -include
  • -basedirectory
  • -injars
  • -outjars(サポートされる出力 jar は 1 つのみ)
  • -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 ファイルは 65K メソッドに制限されているため、65K メソッドを超えるアプリは複数の dex ファイルに分割する必要があります。詳細については、64K を超えるメソッドを使用するアプリ向けに multidex を有効化するをご覧ください。