I managed to answer my question. For what I could understand from the source code, there are 3 possible entry points for java calls:
- ArtMethod :: Invoke (art / runtime / mirror / art_method.cc)
- Execution (art / runtime / interpreter / interpreter.cc)
- DoCall (art / runtime / interpreter / interpreter_common.cc)
ArtMethod :: Invoke, apparently, is used to reflect and to directly call a method with a pointer to a section of the OAT code. (Again, there is no documentation, it may be inaccurate).
Execution ultimately calls DoCall.
There are several ART optimizations that make it difficult to learn Java calls, such as the inline method and direct address call.
The first step is to disable these optimizations:
In the device / company name /model/device.mk (in my case, the device /lge/hammerhead/device.mk for communication 5):
Add the interpretation-only option to dex2oat. With this option, ART only compiles the download path, so applications will not be compiled into OAT.
PRODUCT_PROPERTY_OVERRIDES := \ dalvik.vm.dex2oat-filter=interpret-only
The second step is to disable the attachment in art / compiler / 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;
The last step is to disable the direct code offset call in the art / compiler / driver / compiler_driver.cc file:
-bool use_dex_cache = GetCompilerOptions().GetCompilePic(); +bool use_dex_cache = true;
With these changes, all the various calls will fall into the DoCall function, where we can finally add our target logging procedure.
In art / runtime / interpreter / interpreter_common.h, add include at the beginning:
#ifdef HAVE_ANDROID_OS #include "cutils/properties.h" #endif
In art / runtime / interpreter / interpreter_common.cc add the DoCall function at the beginning:
#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
To target the application, I use a property that sets the target pid. To do this, we need lib system / core / libcutils, and this library is only available if AOSP is compiled for a real phone (without interacting with the current make files).
Thus, the solution will not work for the emulator. ( Just guess, I never tried EDIT: confirmed, "cutils / properties.h" cannot be added to the emulator assembly).
After compiling and blinking the fixed AOSP, start the ps | grep to find the PID and set the property in the root:
shell@android :/ # ps | grep contacts u0_a2 4278 129 1234668 47356 ffffffff 401e8318 S com.android.contacts shell@android :/ # setprop target.app.pid 4278 shell@android :/ # 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>() [...]
When will it end:
shell@android :/ # setprop target.app.pid 0
Voilà!
Overload is not noticeable from the point of view of the user, but logcat will be quickly filled.
PS: The paths and file names correspond to the version of Android 5 (Lollipop), they are likely to differ from the best versions.
PS ': If you want to print the arguments of the methods, I would advise him to look at art / runtime / utils.cc for the PrettyArguments method and find some practical implementation somewhere in the code.