Kompilieren mit Jack

Jack war die Standard-Android-Build-Toolchain für Android 6.0 bis 8.1, mit der Java-Quellcode in Android-Dex-Bytecode kompiliert wurde, wie in Abbildung 1 dargestellt:

Übersicht über die Buchsen.

Abbildung 1 : Übersicht über Jack.

Das .jack-Dateiformat enthält den vorkompilierten Dex-Code für die Bibliothek, was eine schnellere Kompilierung ermöglicht (Pre-Dex).

Inhalt der Jack-Bibliotheksdatei.

Abbildung 2 : Inhalt der Jack-Bibliotheksdatei.

Jill-Tool

Das Jill-Tool übersetzt vorhandene .jar-Bibliotheken in das neue .jack-Bibliotheksformat, wie in Abbildung 3 dargestellt:

Workflow zum Importieren einer vorhandenen JAR-Bibliothek.

Abbildung 3 : Workflow zum Importieren einer vorhandenen .jar-Bibliothek.

Jack-Kompilierungsserver

Wenn Jack zum ersten Mal verwendet wird, startet es einen lokalen Jack-Kompilierungsserver auf Ihrem Computer. Dieser Server übernimmt folgende Aufgaben:

  • Er sorgt für eine schnellere Kompilierung, da er vermeidet, dass bei jeder Kompilierung eine neue Host-JRE-JVM gestartet, Jack-Code geladen, Jack initialisiert und JIT aufgewärmt wird. Außerdem bietet er sehr gute Kompilierungszeiten bei kleinen Kompilierungen (z. B. im inkrementellen Modus).
  • Er ist eine kurzfristige Lösung, um die Anzahl der parallelen Jack-Kompilierungen zu steuern. Der Server vermeidet eine Überlastung Ihres Computers (Speicher- oder Festplattenproblem), da er die Anzahl der parallelen Kompilierungen begrenzt.

Der Jack-Server wird nach einer Leerlaufzeit ohne Kompilierung automatisch heruntergefahren. Er verwendet zwei TCP-Ports auf der Localhost-Schnittstelle und ist nicht extern verfügbar. Alle Parameter (z. B. Anzahl der parallelen Kompilierungen, Zeitüberschreitung und Portnummern) können durch Bearbeiten der Datei $HOME/.jack geändert werden.

Datei „$HOME/.jack“

Die Datei $HOME/.jack enthält die folgenden Einstellungen für Jack-Servervariablen in vollständiger Bash-Syntax:

  • SERVER=true aktiviert die Serverfunktion von Jack.
  • SERVER_PORT_SERVICE=8072 legt die TCP-Portnummer des Servers für Kompilierungszwecke fest.
  • SERVER_PORT_ADMIN=8073 legt die TCP-Portnummer des Servers für Verwaltungszwecke fest.
  • SERVER_COUNT=1 wird nicht verwendet.
  • SERVER_NB_COMPILE=4 legt die maximale Anzahl zulässiger paralleler Kompilierungen fest. SERVER_TIMEOUT=60 legt die Anzahl der Leerlaufsekunden fest, die der Server ohne Kompilierung warten muss, bevor er sich herunterfährt. SERVER_LOG=${SERVER_LOG:=$SERVER_DIR/jack-$SERVER_PORT_SERVICE.log} legt die Datei fest, in die Serverlogs geschrieben werden. Standardmäßig kann diese Variable durch eine Umgebungsvariable überschrieben werden.
  • JACK_VM_COMMAND=${JACK_VM_COMMAND:=java} legt den Standardbefehl fest, der zum Starten einer JVM auf dem Host verwendet wird. Standardmäßig kann diese Variable durch eine Umgebungsvariable überschrieben werden.

Probleme bei Jack-Kompilierungen beheben

Problem Aktion
Ihr Computer reagiert während der Kompilierung nicht mehr oder bei Jack-Kompilierungen tritt der Fehler Out of memory (Nicht genügend Arbeitsspeicher) auf. Reduzieren Sie die Anzahl der gleichzeitigen Jack-Kompilierungen, indem Sie $HOME/.jack bearbeiten und SERVER_NB_COMPILE auf einen niedrigeren Wert ändern.
Bei Kompilierungen tritt der Fehler Cannot launch background server (Hintergrundserver kann nicht gestartet werden) auf. Die wahrscheinlichste Ursache ist, dass die TCP-Ports bereits auf Ihrem Computer verwendet werden. Ändern Sie die Ports, indem Sie $HOME/.jack bearbeiten (SERVER_PORT_SERVICE und SERVER_PORT_ADMIN-Variablen). Um die Situation zu beheben, deaktivieren Sie den Jack-Kompilierungsserver, indem Sie $HOME/.jack bearbeiten und SERVER in false ändern. Leider verlangsamt dies die Kompilierung erheblich und Sie müssen möglicherweise make -j mit Last steuerung starten (Option -l von make).
Die Kompilierung bleibt ohne Fortschritt hängen. Um die Situation zu beheben, beenden Sie den Jack-Hintergrundserver mit jack-admin kill-server und entfernen Sie dann die temporären Verzeichnisse in jack-$USER Ihres temporären Verzeichnisses (/tmp oder $TMPDIR).

Jack-Logdatei finden

Wenn Sie einen make-Befehl mit einem Dist-Ziel ausgeführt haben, befindet sich die Jack-Logdatei unter $ANDROID_BUILD_TOP/out/dist/logs/jack-server.log. Andernfalls können Sie die Logdatei mit jack-admin server-log finden. Bei reproduzierbaren Jack-Fehlern können Sie eine detailliertere Logdatei abrufen, indem Sie die folgende Variable festlegen:

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

Verwenden Sie Standard-Makefile-Befehle, um die Struktur (oder Ihr Projekt) zu kompilieren und die Standardausgabe und -fehler anzuhängen. Führen Sie Folgendes aus, um detaillierte Build-Logs zu entfernen:

unset ANDROID_JACK_EXTRA_ARGS

Anschluss-Einschränkungen

Standardmäßig kann der Jack-Server nur von einem Nutzer auf einem Computer verwendet werden. Wenn Sie zusätzliche Nutzer unterstützen möchten, wählen Sie für jeden Nutzer unterschiedliche Portnummern aus und passen Sie SERVER_NB_COMPILE entsprechend an. Sie können den Jack-Server auch deaktivieren, indem Sie in $HOME/.jack SERVER=false festlegen. Die CTS-Kompilierung ist aufgrund der aktuellen vm-tests-tf-Integration langsam. Tools zur Bytecode-Manipulation (z. B. JaCoCo) werden nicht unterstützt.

Jack verwenden

Jack unterstützt die Java-Programmiersprache 1.7 und integriert die in diesem Abschnitt beschriebenen zusätzlichen Funktionen. Verwenden Sie Standard-Makefile-Befehle, um die Struktur oder Ihr Projekt zu kompilieren.

Pre-Dex

Beim Generieren einer Jack-Bibliotheksdatei wird die .dex-Datei der Bibliothek generiert und als Pre-Dex in der .jack-Bibliotheksdatei gespeichert. Beim Kompilieren verwendet Jack die Pre-Dex-Datei aus jeder Bibliothek wieder. Alle Bibliotheken werden vorab in Dex-Code umgewandelt.

Jack-Bibliotheken mit vorab ausgeführter Dex-Kompilierung.

Abbildung 4 : Jack-Bibliotheken mit Pre-Dex.

Jack verwendet die Pre-Dex-Datei der Bibliothek nicht wieder, wenn bei der Kompilierung Shrinking, Obfuscation oder Repackaging verwendet wird.

Inkrementelle Kompilierung

Bei der inkrementellen Kompilierung werden nur die Komponenten, die seit der letzten Kompilierung geändert wurden (und ihre Abhängigkeiten), neu kompiliert. Die inkrementelle Kompilierung kann deutlich schneller sein als eine vollständige Kompilierung, wenn sich die Änderungen auf eine Reihe von Komponenten beschränken.

Die inkrementelle Kompilierung ist standardmäßig deaktiviert (und wird automatisch deaktiviert, wenn Shrinking, Obfuscation, Repackaging oder Multi-Dex Legacy aktiviert ist). Wenn Sie inkrementelle Builds aktivieren möchten, fügen Sie der Datei Android.mk des Projekts, das Sie inkrementell erstellen möchten, die folgende Zeile hinzu:

LOCAL_JACK_ENABLED := incremental

Shrinking und Obfuscation

Jack verwendet ProGuard-Konfigurationsdateien, um Shrinking und Obfuscation zu aktivieren. Gängige Optionen sind:

  • @
  • -include
  • -basedirectory
  • -injars
  • -outjars (nur 1 Ausgabearchiv unterstützt)
  • -libraryjars
  • -keep
  • -keepclassmembers
  • -keepclasseswithmembers
  • -keepnames
  • -keepclassmembernames
  • -keepclasseswithmembernames
  • -printseeds

Optionen für Shrinking sind:

  • -dontshrink

Optionen für Obfuscation sind:

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

Ignorierte Optionen sind:

  • -dontoptimize (Jack optimiert nicht)
  • -dontpreverify (Jack führt keine Vorabprüfung durch)
  • -skipnonpubliclibraryclasses
  • -dontskipnonpubliclibraryclasses
  • -dontskipnonpubliclibraryclassmembers
  • -keepdirectories
  • -target
  • -forceprocessing
  • -printusage
  • -whyareyoukeeping
  • -optimizations
  • -optimizationpasses
  • -assumenosideeffects
  • -allowaccessmodification
  • -mergeinterfacesaggressively
  • -overloadaggressively
  • -microedition
  • -verbose
  • -dontnote
  • -dontwarn
  • -ignorewarnings
  • -printconfiguration
  • -dump

Repackaging

Jack verwendet jarjar-Konfigurationsdateien für das Repackaging. Jack ist zwar mit rule-Regeltypen kompatibel, aber nicht mit zap- oder keep-Regeltypen.

Multidex-Unterstützung

Jack bietet integrierte und Legacy-Multidex-Unterstützung. Da Dex-Dateien auf 65.000 Methoden beschränkt sind, müssen Apps mit mehr als 65.000 Methoden in mehrere Dex-Dateien aufgeteilt werden. Weitere Informationen finden Sie unter Multidex für Apps mit mehr als 64.000 Methoden.