Skip to content

Commit f1e1fb0

Browse files
authored
Merge pull request didi#461 from wangfengye/master
线程启动日志打印功能
2 parents 724e365 + 515bb17 commit f1e1fb0

File tree

7 files changed

+272
-0
lines changed

7 files changed

+272
-0
lines changed

Android/doraemonkit-plugin/src/main/groovy/com/didichuxing/doraemonkit/plugin/DoKitPlugin.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.didichuxing.doraemonkit.plugin.transform.DokitBigImageTransform;
55
import com.didichuxing.doraemonkit.plugin.transform.DokitCommTransform;
66
import com.didichuxing.doraemonkit.plugin.transform.DokitSlowMethodTransform;
7+
import com.didichuxing.doraemonkit.plugin.transform.DokitThreadTransform;
78
import com.didichuxing.doraemonkit.plugin.transform.DokitUrlConnectionTransform;
89

910
import org.gradle.api.Action;
@@ -55,6 +56,8 @@ public void execute(Project project1) {
5556
appExtension.registerTransform(new DokitBigImageTransform(project), Collections.EMPTY_LIST);
5657
//慢函数
5758
appExtension.registerTransform(new DokitSlowMethodTransform(project), Collections.EMPTY_LIST);
59+
//线程启动日志
60+
appExtension.registerTransform(new DokitThreadTransform(project), Collections.EMPTY_LIST);
5861

5962
}
6063

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.didichuxing.doraemonkit.plugin.bytecode;
2+
3+
import com.didichuxing.doraemonkit.plugin.DokitExtUtil;
4+
import com.didichuxing.doraemonkit.plugin.bytecode.method.comm.ThreadLogAdapter;
5+
import com.didichuxing.doraemonkit.plugin.bytecode.method.thread.ThreadMethodAdapter;
6+
import com.didichuxing.doraemonkit.plugin.bytecode.method.urlconnection.UrlConnectionMethodAdapter;
7+
8+
import org.objectweb.asm.ClassVisitor;
9+
import org.objectweb.asm.MethodVisitor;
10+
import org.objectweb.asm.Opcodes;
11+
import org.objectweb.asm.Type;
12+
/**
13+
* ================================================
14+
* 作 者:maple
15+
* 版 本:1.0
16+
* 创建日期:2020-04-28
17+
* 描 述:类访问器
18+
* 修订历史:
19+
* ================================================
20+
*/
21+
public class DokitThreadClassAdapter extends ClassVisitor {
22+
/**
23+
* 当前类型
24+
*/
25+
private String className;
26+
27+
/**
28+
* @param cv cv 传进来的是 ClassWriter
29+
*/
30+
public DokitThreadClassAdapter(final ClassVisitor cv) {
31+
super(Opcodes.ASM7, cv);
32+
33+
}
34+
35+
@Override
36+
public void visit(int version, int access, String className, String signature, String superName, String[] interfaces) {
37+
super.visit(version, access, className, signature, superName, interfaces);
38+
this.className = className;
39+
}
40+
41+
42+
/**
43+
* Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor}
44+
* instance (or {@literal null}) each time it is called, i.e., it should not return a previously
45+
* returned visitor.
46+
*
47+
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
48+
* the method is synthetic and/or deprecated.
49+
* @param methodName the method's name.
50+
* @param desc the method's descriptor (see {@link Type}).
51+
* @param signature the method's signature. May be {@literal null} if the method parameters,
52+
* return type and exceptions do not use generic types.
53+
* @param exceptions the internal names of the method's exception classes (see {@link
54+
* Type#getInternalName()}). May be {@literal null}.
55+
* @return an object to visit the byte code of the method, or {@literal null} if this class
56+
* visitor is not interested in visiting the code of this method.
57+
*/
58+
@Override
59+
public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, String[] exceptions) {
60+
//从传进来的ClassWriter中读取MethodVisitor
61+
MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions);
62+
//开关被关闭 不插入代码
63+
if (!DokitExtUtil.getInstance().isDokitPluginSwitch()) {
64+
return mv;
65+
}
66+
//过滤所有类中当前方法中所有的字节码
67+
return mv == null ? null : new ThreadMethodAdapter(className, methodName, access, desc, mv);
68+
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.didichuxing.doraemonkit.plugin.bytecode.method.comm;
2+
3+
import org.objectweb.asm.MethodVisitor;
4+
import org.objectweb.asm.Opcodes;
5+
import org.objectweb.asm.commons.LocalVariablesSorter;
6+
7+
8+
public class ThreadLogAdapter extends LocalVariablesSorter implements Opcodes {
9+
public ThreadLogAdapter(int access, String desc, MethodVisitor mv) {
10+
super(org.objectweb.asm.Opcodes.ASM7, access, desc, mv);
11+
}
12+
//方法得开始
13+
@Override
14+
public void visitCode() {
15+
16+
super.visitCode();
17+
}
18+
19+
//方法结束
20+
public void visitInsn(int opcode) {
21+
//添加日志打印
22+
mv.visitVarInsn(ALOAD, 0);
23+
// mv.visitMethodInsn(INVOKESTATIC,"com/didichuxing/doraemonkit/aop/ThreadLog","log","(Ljava/lang/Thread;)V",false);
24+
super.visitInsn(opcode);
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.didichuxing.doraemonkit.plugin.bytecode.method.thread;
2+
3+
import org.objectweb.asm.MethodVisitor;
4+
import org.objectweb.asm.Opcodes;
5+
import org.objectweb.asm.commons.LocalVariablesSorter;
6+
/**
7+
* 方法访问,
8+
* 对所有start方法修改为 ThreadHook.start(this),
9+
* 这个静态方法,判断原函数的对象是Thread或其子类会打印日志,其他函数会不处理,调用原逻辑.
10+
*/
11+
public class ThreadMethodAdapter extends LocalVariablesSorter implements Opcodes {
12+
private String className;
13+
private String methodName;
14+
15+
public ThreadMethodAdapter(String className, String methodName, int access, String desc, MethodVisitor mv) {
16+
super(Opcodes.ASM7, access, desc, mv);
17+
this.className = className;
18+
this.methodName = methodName;
19+
}
20+
21+
@Override
22+
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
23+
if (!className.equals("com/didichuxing/doraemonkit/aop/ThreadHook") && opcode == Opcodes.INVOKEVIRTUAL
24+
&& name.equals("start") && desc.equals("()V")) {
25+
super.visitMethodInsn(INVOKESTATIC, "com/didichuxing/doraemonkit/aop/ThreadHook", "start", "(Ljava/lang/Object;)V", false);
26+
} else {
27+
super.visitMethodInsn(opcode, owner, name, desc, isInterface);
28+
}
29+
}
30+
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.didichuxing.doraemonkit.plugin.transform;
2+
3+
import com.android.build.api.transform.Context;
4+
import com.android.build.api.transform.TransformException;
5+
import com.android.build.api.transform.TransformInput;
6+
import com.android.build.api.transform.TransformOutputProvider;
7+
import com.android.build.gradle.AppExtension;
8+
import com.didichuxing.doraemonkit.plugin.DokitExtension;
9+
import com.didichuxing.doraemonkit.plugin.weaver.DokitThreadWeaver;
10+
import com.didichuxing.doraemonkit.plugin.weaver.DokitUrlConnectionWeaver;
11+
import com.quinn.hunter.transform.HunterTransform;
12+
import com.quinn.hunter.transform.RunVariant;
13+
14+
import org.gradle.api.Project;
15+
16+
import java.io.IOException;
17+
import java.util.Collection;
18+
19+
/**
20+
* ================================================
21+
* 作 者:maple
22+
* 版 本:1.0
23+
* 创建日期:2020-04-28
24+
* 描 述:Dokit 线程日志 字节码插装
25+
* 修订历史:
26+
* ================================================
27+
*/
28+
public class DokitThreadTransform extends HunterTransform {
29+
30+
private DokitExtension dokitExtension;
31+
private String extensionName = "dokitExt";
32+
private AppExtension appExtension;
33+
34+
public DokitThreadTransform(Project project) {
35+
super(project);
36+
this.appExtension = (AppExtension) project.getProperties().get("android");
37+
//创建自动的代码
38+
this.dokitExtension = (DokitExtension) project.getExtensions().getByName(extensionName);
39+
this.bytecodeWeaver = new DokitThreadWeaver(appExtension);
40+
this.bytecodeWeaver.setExtension(dokitExtension);
41+
}
42+
43+
@Override
44+
public void transform(Context context, Collection<TransformInput> inputs, Collection<TransformInput> referencedInputs, TransformOutputProvider outputProvider, boolean isIncremental) throws IOException, TransformException, InterruptedException {
45+
super.transform(context, inputs, referencedInputs, outputProvider, isIncremental);
46+
}
47+
48+
@Override
49+
protected RunVariant getRunVariant() {
50+
return dokitExtension.runVariant;
51+
}
52+
53+
@Override
54+
protected boolean inDuplcatedClassSafeMode() {
55+
return dokitExtension.duplcatedClassSafeMode;
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.didichuxing.doraemonkit.plugin.weaver;
2+
3+
import com.android.build.gradle.AppExtension;
4+
import com.didichuxing.doraemonkit.plugin.DokitExtension;
5+
import com.didichuxing.doraemonkit.plugin.bytecode.DokitBigImageClassAdapter;
6+
import com.didichuxing.doraemonkit.plugin.bytecode.DokitThreadClassAdapter;
7+
import com.quinn.hunter.transform.asm.BaseWeaver;
8+
9+
import org.objectweb.asm.ClassVisitor;
10+
import org.objectweb.asm.ClassWriter;
11+
/**
12+
* ================================================
13+
* 作 者:maple
14+
* 版 本:1.0
15+
* 创建日期:2020-04-28
16+
* 描 述:Dokit 线程日志 字节码插装
17+
* 修订历史:
18+
* ================================================
19+
*/
20+
public class DokitThreadWeaver extends BaseWeaver {
21+
private DokitExtension dokitExtension;
22+
23+
private AppExtension appExtension;
24+
25+
public DokitThreadWeaver(AppExtension appExtension) {
26+
this.appExtension = appExtension;
27+
}
28+
29+
@Override
30+
public void setExtension(Object extension) {
31+
if (extension == null) {
32+
return;
33+
}
34+
this.dokitExtension = (DokitExtension) extension;
35+
}
36+
37+
@Override
38+
protected ClassVisitor wrapClassWriter(ClassWriter classWriter) {
39+
//返回指定的ClassVisitor
40+
return new DokitThreadClassAdapter(classWriter);
41+
}
42+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.didichuxing.doraemonkit.aop;
2+
3+
4+
import android.util.Log;
5+
6+
import java.lang.reflect.Method;
7+
8+
/**
9+
* /**
10+
* * ================================================
11+
* * 作 者:maple
12+
* * 版 本:1.0
13+
* * 创建日期:2020-04-28
14+
* * 描 述:用来通过ASM在编译器进行hook,代理线程得start方法,打印startr日志
15+
* * 修订历史:
16+
* * ================================================
17+
* */
18+
19+
public class ThreadHook {
20+
21+
public static void log(Thread t) {
22+
Log.i("ThreadLog", Thread.currentThread().getName() + "("
23+
+ System.identityHashCode(Thread.currentThread()) + ")开启了新线程" + t.getName() + "(" + +System.identityHashCode(t) + ")");
24+
}
25+
26+
public static void start(Object t) {
27+
28+
if (t instanceof Thread) {
29+
log((Thread) t);
30+
((Thread) t).start();
31+
}else{//捕获了错误的start函数,调用原逻辑
32+
Class<?> clazz=t.getClass();
33+
try {
34+
Method m=clazz.getMethod("start");
35+
m.setAccessible(true);
36+
m.invoke(t);
37+
} catch (Exception e) {
38+
e.printStackTrace();
39+
}
40+
}
41+
42+
}
43+
}

0 commit comments

Comments
 (0)