ARTE TI

In Android 8.0 e versioni successive, ART Tooling Interface (ART TI) espone alcuni elementi interni di runtime e consente ai profiler e ai debugger di influenzare il comportamento di runtime delle app. Questo può essere utilizzato per implementare strumenti di prestazioni all'avanguardia forniti per l'implementazione di agenti nativi su altre piattaforme.

I componenti interni del runtime sono esposti agli agenti che sono stati caricati nel processo di runtime. Questi comunicano con l'ART tramite chiamate dirette e richiamate. Il runtime supporta più agenti in modo che i diversi problemi di profilazione ortogonale possano essere separati. Gli agenti possono essere forniti all'avvio del runtime (quando vengono richiamati dalvikvm o app_process ) o collegati a un processo già in esecuzione.

Poiché la capacità di strumentare e modificare il comportamento delle app e del runtime è molto potente, nell'ART TI sono state integrate due misure di sicurezza:

  • Innanzitutto, il codice che espone l'interfaccia dell'agente, JVMTI, è implementato come plug-in di runtime, non come componente principale del runtime. Il caricamento del plugin può essere limitato, in modo che agli agenti possa essere impedito di trovare qualsiasi punto di interfaccia.
  • In secondo luogo, sia la classe ActivityManager che il processo runtime consentono agli agenti solo di collegarsi ad app di cui è possibile eseguire il debug. Le app di debug sono state approvate dai rispettivi sviluppatori per essere analizzate e strumentate e non vengono distribuite agli utenti finali. Il Google Play Store non consente la distribuzione di app di cui è possibile eseguire il debug. Ciò garantisce che le normali app (inclusi i componenti principali) non possano essere strumentate o manipolate.

Progetto

Il flusso generale e l'interconnessione in un'app strumentata sono illustrati nella Figura 1 .

Flow and interconnection in an instrumented app
Figura 1. Flusso e interconnessione di un'app strumentata

Il plugin ART libopenjdkjvmti espone ART TI, progettato per soddisfare le esigenze e i vincoli della piattaforma:

  • La ridefinizione delle classi si basa sui file Dex , contenenti solo una singola definizione di classe, anziché sui file di classe.
  • Le API in linguaggio Java per la strumentazione e la ridefinizione non vengono esposte.

ART TI supporta anche i profiler Android Studio.

Carica o collega un agente

Per collegare un agente all'avvio del runtime, utilizzare questo comando per caricare sia il plug-in JVMTI che l'agente specificato:

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

Non sono previste misure di sicurezza quando un agente viene caricato all'avvio del runtime, quindi tieni presente che un runtime avviato manualmente consente la modifica completa senza misure di sicurezza. (Ciò consente il test ART.)

Nota: questo non è applicabile alle normali app (incluso il server di sistema) su un dispositivo. Le app vengono biforcate da uno zigote già in esecuzione e a un processo zigote non è consentito caricare gli agenti.

Per collegare un agente a un'app già in esecuzione, utilizza questo comando:

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

Se il plug-in JVMTI non è stato ancora caricato, collegando un agente vengono caricati sia il plug-in che la libreria dell'agente.

Un agente può essere collegato solo a un'app in esecuzione contrassegnata come debuggabile (parte del manifest dell'app, con l'attributo android:debuggable impostato su true sul nodo dell'app). Sia la classe ActivityManager che ART eseguono controlli prima di consentire il collegamento di un agente. La classe ActivityManager controlla le informazioni correnti sull'app (derivate dai dati della classe PackageManager ) per lo stato di debug e il runtime controlla il relativo stato corrente, che è stato impostato all'avvio dell'app.

Posizioni degli agenti

Il runtime deve caricare gli agenti nel processo corrente, in modo che l'agente possa collegarsi direttamente e comunicare con esso. L'ART stessa è agnostica per quanto riguarda il luogo specifico da cui proviene l'agente. La stringa viene utilizzata per una chiamata dlopen . I permessi del file system e le policy SELinux limitano il caricamento effettivo.

Per fornire agenti che possono essere eseguiti da un'app di cui è possibile eseguire il debug, procedere come segue:

  • Incorpora l'agente nella directory della libreria dell'APK dell'app.
  • Utilizzare run-as per copiare l'agente nella directory dei dati dell'app.

API

Il seguente metodo è stato aggiunto ad android.os.Debug .

/**
     * 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 {

Altre API Android

Il comando attach-agent è visibile pubblicamente. Questo comando collega un agente JVMTI a un processo in esecuzione:

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;\''

I comandi am start -P e am start-profiler/stop-profiler sono simili al comando attach-agent.

JVMTI

Questa funzionalità espone l'API JVMTI agli agenti (codice nativo). Le funzionalità importanti includono:

  • Ridefinire una classe.
  • Monitoraggio dell'allocazione degli oggetti e della garbage collection.
  • Iterazione su tutti gli oggetti in un heap, seguendo l'albero di riferimento degli oggetti.
  • Ispezione degli stack di chiamate Java.
  • Sospendere (e riprendere) tutti i thread.

Funzionalità diverse potrebbero essere disponibili su diverse versioni di Android.

Compatibilità

Questa funzionalità richiede il supporto runtime di base disponibile solo su Android 8.0 e versioni successive. I produttori di dispositivi non devono apportare alcuna modifica per implementare questa funzionalità. Fa parte dell'AOSP.

Validazione

CTS testa quanto segue su Android 8 e versioni successive:

  • Verifica che gli agenti si collegano alle app di cui è possibile eseguire il debug e non riescono a collegarsi alle app non di cui è possibile eseguire il debug.
  • Testa tutte le API JVMTI implementate
  • Verifica che l'interfaccia binaria per gli agenti sia stabile

Sono stati aggiunti ulteriori test ad Android 9 e versioni successive e sono inclusi nei test CTS per tali versioni.