How to swap method bodies under Android

624 Views Asked by At

In pure Java, using intrumentation and java agents, there is a way to replace the body of a method at runtime.

Unfrotunately java.lang.instrument.Instrumentation is not available under Android.

I have checked all other alternatives, like the one described here in stackoverflow, which directs to the obsolete javassist-android implementation. Which surprisingly works, but only for new classes.

There's also an article named Hot swapping code in Android which describes how again to load classes at runtime, not how to replace existing methods of classes.

The only article dealing with this issue is an article named Android hacking: replacing system classes methods with your own, which misses the source code and refers to Dalvik, not ART (so it won't work on modern hardware).

So, is there any way to do so?

...

Bottom line: the reason I want this is to trace specific method calls in my application, like just when this method is called (and do some action before it) and just when this method exits (and also do some action on it). These methods are defined at runtime, so there's no way to know them in advance, at compile time.

2

There are 2 best solutions below

0
On

Although the j.l.instrument APIs were never added to android the underlying JVMTI apis that were used to implement them were added in Android O. For example here is a test JVMTI agent that will redefine listed classes and add a single nop to the beginning of every method: https://android.googlesource.com/platform/art/+/refs/heads/master/tools/jvmti-agents/simple-force-redefine/

0
On

One of the new features in Android Studio 3.5 is Apply Changes, which basically performs similar logic to what you're looking to achieve:

".. we rely on runtime instrumentation that is supported in Android 8.0 (Oreo) and newer devices and emulators to redefine classes on the fly."


Also, in episode 108 of ADB Podcast Esteban de la Canal mentioned:

".. In Android Oreo (8.0), the platform implemented bytecode instrumentation on the fly, so we can actually change the dexed class of a running app.. by attaching, basically, an equivalent of JVMTI in Java, so we can attach an agent and say: can you swap this class with this one. "


Start with reading the art/openjdkjvmti sources, i.e. the readme documents the following:

openjdkjvmti plugin
This is a partial implementation of the JVMTI v1.2 interface for the android runtime as a plugin. This allows the use of agents that can modify the running state of the program by modifying dex files in memory and performing other operations on the global runtime state.


Once Android Studio 3.5's sources will be released, see how they used those new APIs in Apply Changes implementation.