ART TI

Unter Android 8.0 und höher stellt die ART Tooling Interface (ART TI) bestimmte interne Laufzeitinformationen bereit und ermöglicht es Profilern und Debuggern, das Laufzeitverhalten von Apps zu beeinflussen. So können Sie moderne Leistungstools implementieren, die für die Implementierung nativer Kundenservicemitarbeiter auf anderen Plattformen bereitgestellt werden.

Laufzeitinterne Daten sind für Agenten verfügbar, die in den Laufzeitprozess geladen wurden. Diese kommunizieren über direkte Aufrufe und Rückrufe mit der ART. Die Laufzeit unterstützt mehrere Agenten, damit verschiedene orthogonale Profiling-Aspekte getrennt werden können. Agenten können entweder zu Beginn der Laufzeit (wenn dalvikvm oder app_process aufgerufen werden) bereitgestellt oder an einen bereits laufenden Prozess angehängt werden.

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

  • Erstens: Der Code, der die Agent-Schnittstelle JVMTI freigibt, wird als Laufzeit-Plug-in und nicht als Kernkomponente der Laufzeit implementiert. Das Laden von Plug-ins kann eingeschränkt werden, sodass Kundenservicemitarbeiter keine der Benutzeroberflächen finden können.
  • Zweitens: Sowohl die ActivityManager-Klasse als auch der Laufzeitprozess erlauben es nur, dass sich Agenten an debuggbare Apps anhängen. Debuggbare Apps wurden von ihren Entwicklern zur Analyse und Instrumentierung freigegeben und werden nicht an Endnutzer verteilt. Im Google Play Store ist die Bereitstellung von Apps, die debuggt werden können, nicht zulässig. So wird sichergestellt, dass normale Apps (einschließlich Kernkomponenten) nicht manipuliert werden können.

Design

Der allgemeine Ablauf und die Verknüpfung in einer instrumentierten App sind in Abbildung 1 dargestellt.

Aufrufabfolge und Verknüpfung in einer instrumentierten App
Abbildung 1. Ablauf und Verknüpfung einer instrumentierten App

Das ART-Plug-in libopenjdkjvmti stellt die ART-TI bereit, die auf die Anforderungen und Einschränkungen der Plattform zugeschnitten ist:

  • Die Klassenneudefinition basiert auf Dex-Dateien, die nur eine einzelne Klassendefinition enthalten, anstatt auf Klassendateien.
  • Java-APIs für Instrumentierung und Neudefinition werden nicht freigegeben.

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

Agent laden oder anhängen

Wenn Sie einen Agenten beim Start der Laufzeit anhängen möchten, laden Sie mit diesem Befehl sowohl das JVMTI-Plug-in als auch den angegebenen Agenten:

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

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

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

Wenn Sie einen Kundenservicemitarbeiter an eine bereits laufende App anhängen möchten, verwenden Sie diesen Befehl:

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

Wenn das JVMTI-Plug-in noch nicht geladen wurde, werden beim Anhängen eines Agents sowohl das Plug-in als auch die Agentbibliothek geladen.

Ein Agent kann nur an eine laufende App angehängt werden, die als debugfähig gekennzeichnet ist (Teil des Manifests der App, wobei das Attribut android:debuggable auf dem App-Knoten auf true festgelegt ist). Sowohl die ActivityManager-Klasse als auch die ART führen Prüfungen durch, bevor ein Kundenservicemitarbeiter hinzugefügt werden kann. Die Klasse ActivityManager prüft die aktuellen App-Informationen (abgeleitet aus den Daten der Klasse PackageManager) auf den Status „debuggable“ (debugfähig). Die Laufzeit prüft den aktuellen Status, der beim Starten der App festgelegt wurde.

Standorte von Kundenservicemitarbeitern

Die Laufzeit muss Agenten in den aktuellen Prozess laden, damit der Agent direkt mit ihm verbunden werden und mit ihm kommunizieren kann. Die ART selbst ist unabhängig vom Standort des Kundenservicemitarbeiters. Der String wird für einen dlopen-Aufruf verwendet. Dateisystemberechtigungen und SELinux-Richtlinien beschränken das tatsächliche Laden.

So stellen Sie Bots bereit, die von einer debuggbaren App ausgeführt werden können:

  • Binden Sie den Agenten in das Bibliotheksverzeichnis des APK der App ein.
  • Kopieren Sie den Agenten mit run-as in das Datenverzeichnis der App.

APIs

Der folgenden Methode wurde 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. Mit diesem Befehl wird ein JVMTI-Agent an einen laufenden Prozess angehängt:

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 „attach-agent“.

JVMTI

Mit dieser Funktion wird die JVMTI API für Agenten (nativer Code) freigegeben. Zu den wichtigsten Funktionen gehören:

  • Eine Klasse neu definieren
  • Objektzuweisung und Garbage Collection erfassen
  • Iteration über alle Objekte in einem Heap, wobei der Referenzbaum der Objekte verfolgt wird.
  • Java-Callstacks prüfen
  • Alle Threads anhalten und fortsetzen

Je nach Android-Version sind möglicherweise unterschiedliche Funktionen verfügbar.

Kompatibilität

Für diese Funktion ist eine Kernlaufzeit erforderlich, die nur unter 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.

Zertifizierungsstufe

Der CTS-Test umfasst unter Android 8 und höher Folgendes:

  • Hier wird getestet, ob sich die Kundenservicemitarbeiter mit debugfähigen Apps verbinden können, aber nicht mit nicht debugfähigen Apps.
  • Alle implementierten JVMTI-APIs werden getestet.
  • Prüft, ob die binäre Schnittstelle für Kundenservicemitarbeiter stabil ist

Für Android 9 und höher wurden zusätzliche Tests hinzugefügt, die in den CTS-Tests für diese Releases enthalten sind.