KUNST TI

In Android 8.0 und höher stellt das ART Tooling Interface (ART TI) bestimmte Laufzeitinterna bereit und ermöglicht Profilern und Debuggern, das Laufzeitverhalten von Apps zu beeinflussen. Damit können modernste Performance-Tools implementiert werden, die für die Implementierung nativer Agenten auf anderen Plattformen bereitgestellt werden.

Laufzeitinterna werden Agenten ausgesetzt, die in den Laufzeitprozess geladen wurden. Diese kommunizieren mit dem ART über direkte Anrufe und Rückrufe. Die Laufzeit unterstützt mehrere Agenten, sodass verschiedene orthogonale Profilierungsprobleme getrennt werden können. Agenten können entweder beim Start der Laufzeit bereitgestellt werden (wenn dalvikvm oder app_process aufgerufen werden) oder an einen bereits laufenden Prozess angehängt werden.

Da die Möglichkeit, App- und Laufzeitverhalten zu instrumentieren und zu modifizieren, sehr leistungsfähig ist, wurden zwei Sicherheitsmaßnahmen in den ART TI integriert:

  • Erstens wird der Code, der die Agentenschnittstelle, JVMTI, verfügbar macht, als Laufzeit-Plugin und nicht als Kernkomponente der Laufzeit implementiert. Das Laden von Plugins kann eingeschränkt sein, sodass Agenten daran gehindert werden können, einen der Schnittstellenpunkte zu finden.
  • Zweitens ermöglichen sowohl die ActivityManager Klasse als auch der Laufzeitprozess Agenten nur das Anhängen an debuggbare Apps. Debugbare Apps wurden von ihren Entwicklern zur Analyse und Instrumentierung freigegeben und werden nicht an Endbenutzer verteilt. Der Google Play Store erlaubt die Verbreitung von debuggbaren Apps nicht. Dadurch wird sichergestellt, dass normale Apps (einschließlich Kernkomponenten) nicht instrumentiert oder manipuliert werden können.

Design

Der allgemeine Ablauf und die Verbindung in einer instrumentierten App sind in Abbildung 1 dargestellt.

Flow and interconnection in an instrumented app
Abbildung 1. Ablauf und Verbindung einer instrumentierten App

Das ART-Plugin libopenjdkjvmti stellt den ART TI zur Verfügung, der auf die Anforderungen und Einschränkungen der Plattform zugeschnitten ist:

  • Die Klassenneudefinition basiert auf Dex Dateien, die nur eine einzige Klassendefinition enthalten, anstelle von Klassendateien.
  • Java-APIs für Instrumentierung und Neudefinition werden nicht verfügbar gemacht.

Der ART TI unterstützt auch Android Studio-Profiler.

Laden Sie einen Agenten oder hängen Sie ihn an

Um beim Laufzeitstart einen Agenten anzuhängen, verwenden Sie diesen Befehl, um sowohl das JVMTI-Plugin als auch den angegebenen Agenten zu laden:

dalvikvm -Xplugin:libopenjdkjvmti.so -agentpath:/path/to/agent/libagent.so …

Wenn ein Agent beim Start der Laufzeit geladen wird, sind keine Sicherheitsmaßnahmen vorhanden. Bedenken Sie daher, dass eine manuell gestartete Laufzeit vollständige Änderungen ohne Sicherheitsmaßnahmen ermöglicht. (Dies ermöglicht ART-Tests.)

Hinweis: Dies gilt nicht für normale Apps (einschließlich des Systemservers) auf einem Gerät. Apps werden von einer bereits ausgeführten Zygote abgespalten und ein Zygote-Prozess darf keine Agenten laden.

Um einen Agenten an eine bereits ausgeführte App anzuhängen, verwenden Sie diesen Befehl:

adb shell cmd activity attach-agent [process]
/path/to/agent/libagent.so[=agent-options]

Wenn das JVMTI-Plugin noch nicht geladen wurde, werden beim Anhängen eines Agenten sowohl das Plugin als auch die Agentenbibliothek geladen.

Ein Agent darf nur an eine laufende App angehängt werden, die als debuggbar markiert ist (Teil des Manifests der App, wobei das Attribut android:debuggable auf dem App-Knoten auf true gesetzt ist). Sowohl die ActivityManager Klasse als auch ART führen Prüfungen durch, bevor sie das Anhängen eines Agenten zulassen. Die ActivityManager- Klasse überprüft die aktuellen App-Informationen (abgeleitet aus den PackageManager- Klassendaten) auf den debuggbaren Status, und die Laufzeit überprüft ihren aktuellen Status, der beim Start der App festgelegt wurde.

Agentenstandorte

Die Laufzeit muss Agenten in den aktuellen Prozess laden, damit sich der Agent direkt an ihn binden und mit ihm kommunizieren kann. Der ART selbst ist unabhängig von dem konkreten Standort, von dem der Agent stammt. Die Zeichenfolge wird für einen dlopen -Aufruf verwendet. Dateisystemberechtigungen und SELinux-Richtlinien schränken das tatsächliche Laden ein.

Gehen Sie wie folgt vor, um Agenten bereitzustellen, die von einer debuggbaren App ausgeführt werden können:

  • Betten Sie den Agenten in das Bibliotheksverzeichnis des APK der App ein.
  • Verwenden Sie run-as , um den Agenten in das Datenverzeichnis der App zu kopieren.

APIs

Die folgende Methode wurde zu android.os.Debug hinzugefügt.

/**
     * Attach a library as a jvmti agent to the current runtime, with the given classloader
     * determining the library search path.
     * Note: agents may only be attached to debuggable apps. Otherwise, this function will
     * throw a SecurityException.
     *
     * @param library the library containing the agent.
     * @param options the options passed to the agent.
     * @param classLoader the classloader determining the library search path.
     *
     * @throws IOException if the agent could not be attached.
     * @throws a SecurityException if the app is not debuggable.
     */
    public static void attachJvmtiAgent(@NonNull String library, @Nullable String options,
            @Nullable ClassLoader classLoader) throws IOException {

Andere Android-APIs

Der Befehl „attach-agent“ ist öffentlich sichtbar. Dieser Befehl fügt einen JVMTI-Agenten an einen laufenden Prozess an:

adb shell 'am attach-agent com.example.android.displayingbitmaps
\'/data/data/com.example.android.displayingbitmaps/code_cache/libfieldnulls.so=Ljava/lang/Class;.name:Ljava/lang/String;\''

Die Befehle am start -P und am start-profiler/stop-profiler ähneln dem Befehl attachment-agent.

JVMTI

Diese Funktion macht die JVMTI-API für Agenten verfügbar (nativer Code). Zu den wichtigen Funktionen gehören:

  • Eine Klasse neu definieren.
  • Verfolgung der Objektzuordnung und Speicherbereinigung.
  • Iterieren Sie alle Objekte in einem Heap und folgen Sie dabei dem Referenzbaum der Objekte.
  • Untersuchen von Java-Aufrufstapeln.
  • Alle Threads werden angehalten (und fortgesetzt).

Auf verschiedenen Android-Versionen stehen möglicherweise unterschiedliche Funktionen zur Verfügung.

Kompatibilität

Für diese Funktion ist Kernlaufzeitunterstützung erforderlich, die nur auf Android 8.0 und höher verfügbar ist. Gerätehersteller müssen keine Änderungen vornehmen, um diese Funktion zu implementieren. Es ist Teil von AOSP.

Validierung

CTS testet Folgendes auf Android 8 und höher:

  • Testet, dass Agenten eine Verbindung zu debuggbaren Apps herstellen und keine Verbindung zu nicht debuggbaren Apps herstellen können.
  • Testet alle implementierten JVMTI-APIs
  • Testet, ob die Binärschnittstelle für Agenten stabil ist

Zusätzliche Tests wurden zu Android 9 und höher hinzugefügt und sind in den CTS-Tests für diese Versionen enthalten.