Deep Dive into ASM for Android Bytecode Instrumentation and OkHttp Monitoring
This article explains how to use ASM to instrument Android bytecode for automatic click event tracking and OkHttp network request monitoring, detailing the Transform API, AOP/ASM techniques, custom ClassVisitor and MethodVisitor implementations, code injection strategies, and provides a complete open‑source example on GitHub.
Project background : Following the QAPM client performance monitoring system, developers needed to add network monitoring for okhttp. The article shares the technologies, simple entry to automatic instrumentation, and challenges encountered when hooking okhttp3 methods.
Related technologies : Android Gradle Plugin Transform API, which allows custom processing of compiled .class files before they are converted to .dex. The article also introduces Aspect‑Oriented Programming (AOP) and the ASM library as the underlying bytecode manipulation mechanism.
Entry practice – using ASM to count View click events :
public class TestClass implements View.OnClickListener {
View view;
void test(){
view.setOnClickListener(this);
}
@Override
public void onClick(View view) {
System.out.println("我处理View点击事件");
}
}To achieve unified click tracking, the original setOnClickListener call is replaced with a custom RecodeOnClickListener wrapper:
public class RecodeOnClickListener implements View.OnClickListener {
View.OnClickListener listener;
public RecodeOnClickListener(View.OnClickListener listener){
this.listener = listener;
}
@Override
public void onClick(View view) {
if (listener != null) {
listener.onClick(view);
}
System.out.println("我记录了View点击事件");
}
}The ASM transformation inserts the creation of RecodeOnClickListener before the original setOnClickListener call:
mv.visitTypeInsn(NEW, "com/mqunar/qapm/okhttp/RecodeOnClickListener");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "com/mqunar/qapm/okhttp/RecodeOnClickListener", "<init>", "(Landroid/view/View$OnClickListener;)V", false);OkHttp client monitoring : The article shows how to intercept OkHttp requests by replacing new OkHttpClient() (or new OkHttpClient.Builder()) with a custom utility that adds an interceptor:
public static OkHttpClient getOkHttpClient(){
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(new QOkHttpInterceptor());
return builder.build();
}The corresponding ASM change swaps the object creation with a static method call:
mv.visitMethodInsn(INVOKESTATIC, "com/mqunar/qapm/okhttp/OkHttpUtils", "getOkHttpClient", "()Lokhttp3/OkHttpClient;", false);Hook design : To support more complex scenarios where a single method call expands into multiple instructions, the article proposes a two‑phase approach – first marking the bytecode locations that need hooking, then performing the actual injection. Custom HookInitMethodClassVisitor and HookInitMethodVisitor classes record indices of NEW and DUP instructions and decide whether to skip or replace them.
Key snippets of the custom visitors:
class HookInitMethodClassVisitor extends ClassVisitor {
// ... constructor stores class name and context
@Override
MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor originMv = super.visitMethod(access, name, desc, signature, exceptions);
if (hook) {
// find matching method in context and return custom visitor
return new HookInitMethodVisitor(originMv, matchingMethod);
}
return originMv;
}
}
class HookInitMethodVisitor extends GeneratorAdapter implements Opcodes {
@Override
void visitTypeInsn(int opcode, String type) {
if (opcode == NEW && hook && method.newVisiTypeInsnIndexs.contains(currentIndex)) {
return; // skip original NEW
}
super.visitTypeInsn(opcode, type);
}
@Override
void visitInsn(int opcode) {
if (opcode == DUP && hook && method.dupVisiInsnIndexs.contains(currentDupIndex)) {
return; // skip original DUP
}
super.visitInsn(opcode);
}
@Override
void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
// replace setOnClickListener or OkHttp constructor with custom logic
super.visitMethodInsn(...);
}
}The full implementation, along with additional network monitoring features, is available in the open‑source GitHub repository linked at the end of the article.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
