Como compilar com o Jack

Ele era uma cadeia de ferramentas do Android que compilava fonte Java em bytecode dex do Android. Você não precisa fazer nada diferente para usar o Jack, apenas usar seus comandos makefile padrão para compilar a árvore ou o projeto. O Android 8.1 é a última versão que usa o Jack.

Sobre o Jack

O Jack funciona da seguinte maneira:

Visão geral do Jack
Figura 1. Visão geral do Jack

Formato da biblioteca do Jack

O Jack tem o próprio formato de arquivo .jack que contém o código dex pré-compilado para a biblioteca, possibilitando uma compilação mais rápida (pré-dex).

Conteúdo do arquivo da biblioteca do Jack
Figura 2. Conteúdo do arquivo da biblioteca do Jack

Jill

A ferramenta Jill converte as bibliotecas .jar existentes para o novo formato de biblioteca, como mostrado abaixo.

Como importar bibliotecas .jar com o Jill
Figura 3. Fluxo de trabalho para importar uma biblioteca .jar existente

Servidor de compilação do Jack

A primeira vez que o Jack é usado, ele abre um servidor de compilação Jack local no seu computador, que:

  • traz um aumento de velocidade intrínseco, porque evita a abertura de um novo host JRE JVM, o carregamento do código do Jack, a inicialização do Jack e o aquecimento do JIT a cada compilação. Ele também oferece tempos de compilação muito bons durante pequenas compilações (por exemplo, no modo incremental);
  • é uma solução de curto prazo para controlar o número de compilações Jack paralelas. Ele evita sobrecarregar seu computador (problema de memória ou de disco) porque limita o número de compilações paralelas.

O servidor Jack se desativa após um tempo ocioso sem nenhuma compilação. Ele usa duas portas TCP na interface do localhost e não está disponível externamente. Todos os parâmetros (número de compilações paralelas, tempo limite, número de portas etc.) podem ser modificados editando o arquivo $HOME/.jack.

Arquivo $HOME/.jack

O arquivo $HOME/.jack contém as seguintes configurações para as variáveis do servidor Jack em uma sintaxe bash completa:

  • SERVER=true. Ativa o recurso de servidor do Jack.
  • SERVER_PORT_SERVICE=8072. Define o número da porta TCP do servidor para fins de compilação.
  • SERVER_PORT_ADMIN=8073. Define o número da porta TCP do servidor para fins administrativos.
  • SERVER_COUNT=1. Não utilizado.
  • SERVER_NB_COMPILE=4. Define o número máximo de compilações paralelas permitidas.
  • SERVER_TIMEOUT=60. Define o número de segundos de ociosidade que o servidor precisa aguardar sem nenhuma compilação antes de se desativar.
  • SERVER_LOG=${SERVER_LOG:=$SERVER_DIR/jack-$SERVER_PORT_SERVICE.log}. Define o arquivo em que os logs do servidor são gravados. Por padrão, essa variável pode ser sobrecarregada por uma variável de ambiente.
  • JACK_VM_COMMAND=${JACK_VM_COMMAND:=java}. Define o comando padrão usado para abrir uma JVM no host. Por padrão, essa variável pode ser sobrecarregada pela variável de ambiente.

Solução de problemas de compilação do Jack

Problema Ação
Seu computador deixa de responder durante a compilação ou você percebe que as compilações do Jack falham com "Erro de falta de memória" É possível melhorar a situação reduzindo o número de compilações do Jack simultâneas editando $HOME/.jack e alterando SERVER_NB_COMPILE para um valor mais baixo.
As compilações estão falhando com "Não é possível iniciar o servidor em segundo plano" A causa mais provável é que as portas TCP já estão sendo usadas no seu computador. Altere as portas editando $HOME/.jack (as variáveis SERVER_PORT_SERVICE e SERVER_PORT_ADMIN). Para resolver a situação, desative o servidor de compilação do Jack editando $HOME/.jack e alterando SERVER para falso. Infelizmente, isso diminuirá significativamente a velocidade da sua compilação e poderá obrigar você a abrir make -j com controle de carga (opção -l de make).
A compilação é interrompida sem qualquer progresso Para resolver a situação, elimine o servidor em segundo plano do Jack usando jack-admin kill-server) e remova os diretórios temporários contidos em jack-$USER do seu diretório temporário (/tmp ou $TMPDIR).

Como encontrar o log do Jack

Se você executar um comando make com um destino dist, o log do Jack estará em $ANDROID_BUILD_TOP/out/dist/logs/jack-server.log. Caso contrário, você pode encontrar o log executando jack-admin server-log. Em caso de falhas do Jack reproduzíveis, veja um log mais detalhado definindo a seguinte variável:

export ANDROID_JACK_EXTRA_ARGS="--verbose debug --sanity-checks on -D sched.runner=single-threaded"

Use comandos makefile padrão para compilar a árvore (ou seu projeto) e anexar a saída padrão e o erro. Para remover os logs de criação detalhados, execute:

unset ANDROID_JACK_EXTRA_ARGS

Limitações do Jack

  • Por padrão, o servidor do Jack contém apenas um usuário e pode ser usado apenas por um usuário em um computador. Para aceitar mais usuários, selecione diferentes números de porta para cada um deles e ajuste o SERVER_NB_COMPILE corretamente. Também é possível desativar o servidor do Jack configurando SERVER=false em $HOME/.jack.
  • A compilação do CTS é lenta devido à integração atual do vm-tests-tf.
  • As ferramentas de manipulação de bytecode (como o JaCoCo) não são compatíveis.

Como usar o Jack

O Jack é compatível com a linguagem de programação Java 1.7 e integra os outros recursos descritos abaixo.

Pré-dexação

Ao gerar um arquivo de biblioteca do Jack, o .dex da biblioteca é gerado e armazenado dentro do arquivo de biblioteca .jack como um pré-dex. Durante a compilação, o Jack reutiliza o pré-dex de cada biblioteca. Todas as bibliotecas são pré-dexadas:

Bibliotecas do Jack com pré-dex
Figura 4. Bibliotecas do Jack com pré-dex

O Jack não reutiliza o pré-dex da biblioteca se for usado redução, ofuscação ou reempacotamento na compilação.

Compilação incremental

Compilação incremental significa que somente os componentes modificados desde a última compilação (e as dependências deles) são recompilados. A compilação incremental pode ser significativamente mais rápida do que uma compilação completa quando as alterações se limitam a um conjunto de componentes.

A compilação incremental não é ativada por padrão e é desativada automaticamente quando a redução, o ofuscamento, o reempacotamento ou o legado de multidex está habilitado. Para ativar compilações incrementais, inclua a linha a seguir no arquivo Android.mk do projeto que você quer criar de forma incremental:

LOCAL_JACK_ENABLED := incremental

Redução e ofuscação

O Jack usa arquivos de configuração para evitar a redução e a ofuscação.

Entre as opções comuns estão as seguintes:

  • @
  • -include
  • -basedirectory
  • -injars
  • -outjars // only 1 output jar supported
  • -libraryjars
  • -keep
  • -keepclassmembers
  • -keepclasseswithmembers
  • -keepnames
  • -keepclassmembernames
  • -keepclasseswithmembernames
  • -printseeds

Entre as opções de redução está a seguinte:

  • -dontshrink

Entre as opções de ofuscação estão as seguintes:

  • -dontobfuscate
  • -printmapping
  • -applymapping
  • -obfuscationdictionary
  • -classobfuscationdictionary
  • -packageobfuscationdictionary
  • -useuniqueclassmembernames
  • -dontusemixedcaseclassnames
  • -keeppackagenames
  • -flattenpackagehierarchy
  • -repackageclasses
  • -keepattributes
  • -adaptclassstrings

Entre as opções ignoradas estão as seguintes:

  • -dontoptimize // Jack does not optimize
  • -dontpreverify // Jack does not preverify
  • -skipnonpubliclibraryclasses
  • -dontskipnonpubliclibraryclasses
  • -dontskipnonpubliclibraryclassmembers
  • -keepdirectories
  • -target
  • -forceprocessing
  • -printusage
  • -whyareyoukeeping
  • -optimizations
  • -optimizationpasses
  • -assumenosideeffects
  • -allowaccessmodification
  • -mergeinterfacesaggressively
  • -overloadaggressively
  • -microedition
  • -verbose
  • -dontnote
  • -dontwarn
  • -ignorewarnings
  • -printconfiguration
  • -dump

Reempacotamento

O Jack usa arquivos de configuração jarjar para realizar o reempacotamento. Embora o Jack seja compatível com os tipos de regra "rule", ele não é compatível com os tipos de regra "zap" ou "keep".

Compatibilidade com multidex

O Jack oferece compatibilidade nativa e legada com multidex. Como os arquivos dex estão limitados a 65 mil métodos, os apps com mais do que isso precisam ser divididos em vários arquivos dex. Para ver mais detalhes, consulte Como criar apps com mais de 65 mil métodos.