Sono riuscito a rispondere alla mia domanda. Per quello che ho potuto capire dal codice sorgente Ci sono 3 possibili punti di ingresso per le chiamate Java:
- ArtMethod :: Invoke (arte/runtime/mirror/art_method.cc)
- Execute (art/runtime /interpreter/interpreter.cc)
- DoCall (arte/runtime/interprete/interpreter_common.cc)
ArtMethod :: Invoke sembra essere usato per la riflessione e per chiamare il metodo direttamente con un puntatore al OAT sezione di codice. (Ancora una volta, nessuna documentazione, può essere inesatta).
Execute end up chiama DoCall in generale.
Esistono alcune ottimizzazioni di ART che rendono difficile lo studio delle chiamate Java, come l'inlining dei metodi e il richiamo degli indirizzi di offset diretto.
il primo passo è la disabilitazione di queste ottimizzazioni:
Nel dispositivo/marca/modello/device.mk (nel mio caso dispositivo/LGE/martello/device.mk per un Nexus 5):
Aggiungere l'opzione "solo interpretazione" a dex2oat. Con questa opzione, ART compila solo il percorso di classe di avvio, quindi le applicazioni non verranno compilate in OAT.
PRODUCT_PROPERTY_OVERRIDES := \
dalvik.vm.dex2oat-filter=interpret-only
Il secondo passo è disattivare espansione in arte/compilatore/dex/frontend.cc:
Uncomment "kSuppressMethodInlining".
/* Default optimizer/debug setting for the compiler. */
static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations
(1 << kLoadStoreElimination) |
// (1 << kLoadHoisting) |
// (1 << kSuppressLoads) |
// (1 << kNullCheckElimination) |
// (1 << kClassInitCheckElimination) |
(1 << kGlobalValueNumbering) |
// (1 << kPromoteRegs) |
// (1 << kTrackLiveTemps) |
// (1 << kSafeOptimizations) |
// (1 << kBBOpt) |
// (1 << kMatch) |
// (1 << kPromoteCompilerTemps) |
// (1 << kSuppressExceptionEdges) |
(1 << kSuppressMethodInlining) |
0;
L'ultimo passo è disattivare compensare codice invocazione diretta nell'arte/compilatore/driver/compiler_driver.cc:
-bool use_dex_cache = GetCompilerOptions().GetCompilePic();
+bool use_dex_cache = true;
Con queste modifiche tutte diverse chiamate cadranno nella funzione DoCall dove possiamo infine aggiungere la nostra routine di registrazione mirata.
Nell'arte/runtime/interprete/interpreter_common.h, aggiungi all'inizio del include:
#ifdef HAVE_ANDROID_OS
#include "cutils/properties.h"
#endif
Nell'arte/runtime/interprete/interpreter_common.cc, aggiungere all'inizio della funzione DoCall:
#ifdef HAVE_ANDROID_OS
char targetAppVar[92];
property_get("target.app.pid", targetAppVar, "0");
int targetAppPID = atoi(targetAppVar);
if(targetAppPID != 0 && targetAppPID == getpid())
LOG(INFO) << "DoCall - " << PrettyMethod(method, true);
#endif
Per il targeting dell'applicazione utilizzo una proprietà che imposta il pid di destinazione. Per questo abbiamo bisogno del sistema lib/core/libcutils e questa lib è disponibile solo quando l'AOSP è compilato per un telefono reale (senza scherzare con i makefile correnti).
Quindi la soluzione non funzionerà per un emulatore. (
Solo ipotesi, mai provato
EDIT: confermato, "cutils/properties.h" non può essere aggiunto alla build di un emulatore).
Dopo aver compilato e visualizzato l'AOSP con patch, avviare un'app, ps | grep per trovare il PID e impostare la proprietà di root:
[email protected]:/ # ps | grep contacts
u0_a2 4278 129 1234668 47356 ffffffff 401e8318 S com.android.contacts
[email protected]:/ # setprop target.app.pid 4278
[email protected]:/ # logcat
[...]
I/art (4278): DoCall - int android.view.View.getId()
I/art (4278): DoCall - void com.android.contacts.activities.PeopleActivity$ContactsUnavailableFragmentListener.onCreateNewContactAction()
I/art (4278): DoCall - void android.content.Intent.<init>(java.lang.String, android.net.Uri)
I/art (4278): DoCall - void android.app.Activity.startActivity(android.content.Intent)
I/ActivityManager( 498): START u0 {act=android.intent.action.INSERT dat=content://com.android.contacts/contacts cmp=com.android.contacts/.activities.ContactEditorActivity} from uid 10002 on display 0
V/WindowManager( 498): addAppToken: AppWindowToken{3a82282b token=Token{dc3f87a ActivityRecord{c0aaca5 u0 com.android.contacts/.activities.ContactEditorActivity t4}}} to stack=1 task=4 at 1
I/art (4278): DoCall - void android.app.Fragment.onPause()
I/art (4278): DoCall - void com.android.contacts.common.list.ContactEntryListFragment.removePendingDirectorySearchRequests()
I/art (4278): DoCall - void android.os.Handler.removeMessages(int)
I/art (4278): DoCall - void com.android.contacts.list.ProviderStatusWatcher.stop()
I/art (4278): DoCall - boolean com.android.contacts.list.ProviderStatusWatcher.isStarted()
I/art (4278): DoCall - void android.os.Handler.removeCallbacks(java.lang.Runnable)
I/art (4278): DoCall - android.content.ContentResolver com.android.contacts.ContactsActivity.getContentResolver()
I/art (4278): DoCall - void android.content.ContentResolver.unregisterContentObserver(android.database.ContentObserver)
I/art (4278): DoCall - void android.app.Activity.onPause()
I/art (4278): DoCall - void android.view.ViewGroup.drawableStateChanged()
I/art (4278): DoCall - void com.android.contacts.ContactsActivity.<init>()
I/art (4278): DoCall - void com.android.contacts.common.activity.TransactionSafeActivity.<init>()
I/art (4278): DoCall - void android.app.Activity.<init>()
I/art (4278): DoCall - void com.android.contacts.util.DialogManager.<init>(android.app.Activity)
I/art (4278): DoCall - void java.lang.Object.<init>()
[...]
quando è finita:
[email protected]:/ # setprop target.app.pid 0
Voilà!
Il sovraccarico non è visibile da un punto di vista dell'utente, ma il logcat verrà riempito rapidamente.
PS: percorsi di file e nomi corrispondono alla versione Android 5 (Lollipop), saranno probabilmente diversi con versioni superiori.
PS ': Se uno vorrebbe stampare gli argomenti dei metodi, consiglierei di guardare art/runtime/utils.cc per il metodo PrettyArguments e di trovare qualche implementazione pratica da qualche parte nel codice.
Grazie tanto per spiegare questo. Ho una domanda. Se voglio applicare il patch al codice AOSP come hai spiegato e creare un'immagine del sistema Android per un emulatore, dovrei aggiungere l'opzione "solo-interpretabile"? Non sono riuscito a trovare il file device.mk per l'emulatore. Gentilmente fammi sapere. – aMa
Qual è il tuo dispositivo di destinazione? Il mio era un nexus 5 hammerhead quindi il mio percorso è /device/lge/hammerhead/device.mk. –
Sry, ho letto troppo velocemente. Non ho mai provato un emulatore e probabilmente avrai problemi con libcutils per la funzione property_get. Hai già provato senza le modifiche di device.mk? Dovrebbe funzionare senza di esso nel peggiore dei casi. Senza di esso la cosa peggiore che può accadere è che ti manca alcune delle chiamate. –