使用 Jack for Android 6.0–8.1 编译

Jack 是一个将 Java 源代码编译成 Android dex 字节码的 Android 工具链。您不必做任何不同的事情来使用 Jack — 只需使用您的标准 makefile 命令来编译树或您的项目。 Android 8.1 是最后一个使用 Jack 的版本。

关于杰克

Jack 的工作方式如图 1 所示。

杰克概述
图 1. Jack 概览

杰克库格式

Jack 有自己的.jack文件格式,其中包含库的预编译 dex 代码,允许更快的编译(pre-dex)。

Jack 库文件内容
图 2. Jack 库文件内容

吉尔

Jill 工具将现有的.jar库转换为新的库格式,如下所示。

使用 Jill 导入 .jar 库
图 3.导入现有.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/.jackSERVER_PORT_SERVICESERVER_PORT_ADMIN变量)更改端口。要解除阻塞,请通过编辑$HOME/.jack并将SERVER更改为false来禁用 Jack 编译服务器。不幸的是,这会显着减慢您的编译速度,并可能迫使您使用负载控制启动make -j (选项-lmake )。
编译卡住没有任何进展要解除阻塞,请使用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。所有库都是预先索引的。

带有 pre-dex 的 Jack 库
图 4.带有 pre-dex 的 Jack 库

如果在编译中使用了压缩、混淆或重新打包,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