{@link DroidAssistExecutor#execute} process files specifically
98 | */
99 | void onTransform(
100 | Context gradleContext,
101 | Collection It provides the ability to handle classes, see {@link #executeClass}
20 | */
21 | abstract class InputTask See for details {@link InputTask#executeClass}
30 | */
31 | void execute() {
32 | JarInput input = taskInput.input
33 | File inputJar = input.file
34 | if (taskInput.incremental) {
35 | if (input.status != Status.NOTCHANGED) {
36 | Logger.info("Jar incremental build: \ninput:${ taskInput.input.name} \npath: ${IOUtils.getPath(inputJar)} \ndest:${taskInput.dest} \nstatus:${input.status}")
37 | FileUtils.deleteQuietly(taskInput.dest)
38 | } else {
39 | Logger.info("${IOUtils.getPath(inputJar)} not changed, skip.")
40 | return
41 | }
42 | }
43 |
44 | if (input.status != Status.REMOVED) {
45 | def written = false
46 | ZipUtils.collectAllClassesFromJar(inputJar).forEach {
47 | written = executeClass(it, temporaryDir) || written
48 | }
49 | if (written) {
50 | ZipUtils.zipAppend(inputJar, taskInput.dest, temporaryDir)
51 | } else {
52 | FileUtils.copyFile(inputJar, taskInput.dest)
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/ExprExecTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform;
2 |
3 |
4 | import com.google.common.collect.Sets;
5 |
6 | import java.util.Set;
7 | import java.util.concurrent.atomic.AtomicBoolean;
8 |
9 | import javassist.CannotCompileException;
10 | import javassist.CtBehavior;
11 | import javassist.CtClass;
12 | import javassist.CtConstructor;
13 | import javassist.CtMethod;
14 | import javassist.Modifier;
15 | import javassist.NotFoundException;
16 | import javassist.expr.ConstructorCall;
17 | import javassist.expr.ExprEditor;
18 | import javassist.expr.FieldAccess;
19 | import javassist.expr.MethodCall;
20 | import javassist.expr.NewExpr;
21 |
22 | @SuppressWarnings("RedundantThrows")
23 | public abstract class ExprExecTransformer extends SourceTargetTransformer {
24 |
25 | protected static final String CONSTRUCTOR_CALL = "ConstructorCall";
26 | protected static final String METHOD_CALL = "MethodCall";
27 | protected static final String FIELD_ACCESS = "FieldAccess";
28 | protected static final String NEW_EXPR = "NewExpr";
29 |
30 | protected static final String METHOD = "method";
31 | protected static final String INITIALIZER = "initializer";
32 | protected static final String CONSTRUCTOR = "constructor";
33 |
34 | public static final String TRANSFORM_EXEC = "exec";
35 | public static final String TRANSFORM_EXPR = "expr";
36 |
37 |
38 | class Editor extends ExprEditor {
39 | CtBehavior behavior;
40 | AtomicBoolean modified;
41 | }
42 |
43 | protected abstract String getExecuteType();
44 |
45 | protected Set There are five major categories of {@link com.didichuxing.tools.droidassist.transform.around.AroundTransformer},
18 | * {@link com.didichuxing.tools.droidassist.transform.enhance.TimingTransformer},
19 | * {@link com.didichuxing.tools.droidassist.transform.enhance.TryCatchTransformer},
20 | * {@link com.didichuxing.tools.droidassist.transform.insert.InsertTransformer},
21 | * {@link com.didichuxing.tools.droidassist.transform.replace.ReplaceTransformer}
22 | * and 28 implementation class.
23 | */
24 | @SuppressWarnings("WeakerAccess")
25 | public abstract class Transformer {
26 | public ClassPool classPool;
27 | public ClassFilterSpec classFilterSpec = new ClassFilterSpec();
28 | protected boolean abortOnUndefinedClass = false;
29 |
30 | //Transformer name
31 | public String getName() {
32 | return "Transformer";
33 | }
34 |
35 | //Category name that transformer belongs to
36 | public String getCategoryName() {
37 | return "Transformer";
38 | }
39 |
40 | public String getPrettyName() {
41 | return "Transformer";
42 | }
43 |
44 | protected abstract boolean onTransform(
45 | CtClass inputClass,
46 | String inputClassName)
47 | throws NotFoundException, CannotCompileException;
48 |
49 | public boolean performTransform(
50 | CtClass inputClass,
51 | String className)
52 | throws NotFoundException, CannotCompileException {
53 |
54 | inputClass.stopPruning(true);
55 | if (inputClass.isFrozen()) {
56 | inputClass.defrost();
57 | }
58 | beforeTransform();
59 | return onTransform(inputClass, className);
60 | }
61 |
62 | protected void beforeTransform() {
63 | }
64 |
65 | public boolean classAllowed(String className) {
66 | return classFilterSpec.classAllowed(className);
67 | }
68 |
69 | public Transformer setClassPool(ClassPool classPool) {
70 | this.classPool = classPool;
71 | return this;
72 | }
73 |
74 | public ClassPool getClassPool() {
75 | return classPool;
76 | }
77 |
78 | public void check() {
79 | }
80 |
81 | public boolean isAbortOnUndefinedClass() {
82 | return abortOnUndefinedClass;
83 | }
84 |
85 | public Transformer setAbortOnUndefinedClass(boolean abortOnUndefinedClass) {
86 | this.abortOnUndefinedClass = abortOnUndefinedClass;
87 | return this;
88 | }
89 |
90 | //Get class in the class pool
91 | protected CtClass tryGetClass(String className, String loc) {
92 | CtClass ctClass = classPool.getOrNull(className);
93 | if (ctClass == null) {
94 | String msg = "cannot find " + className + " in " + loc;
95 | if (abortOnUndefinedClass) {
96 | throw new DroidAssistNotFoundException(msg);
97 | } else {
98 | Logger.warning(msg);
99 | }
100 | } else {
101 | return ctClass;
102 | }
103 | return null;
104 | }
105 |
106 | protected Boolean isInterface(CtClass inputClass) {
107 | try {
108 | return inputClass.isInterface();
109 | } catch (Exception ignore) {
110 | return null;
111 | }
112 | }
113 |
114 | //Get all interfaces of the specified class
115 | protected CtClass[] tryGetInterfaces(CtClass inputClass) {
116 | try {
117 | return inputClass.getInterfaces();
118 | } catch (NotFoundException e) {
119 | String msg = "Cannot find interface " + e.getMessage() + " in " + inputClass.getName();
120 | if (abortOnUndefinedClass) {
121 | throw new DroidAssistNotFoundException(msg);
122 | } else {
123 | Logger.warning(msg);
124 | }
125 | }
126 | return new CtClass[0];
127 | }
128 |
129 | //Get all declared methods of the specified class
130 | protected CtMethod[] tryGetDeclaredMethods(CtClass inputClass) {
131 | CtMethod[] declaredMethods = new CtMethod[0];
132 | try {
133 | declaredMethods = inputClass.getDeclaredMethods();
134 | } catch (Exception e) {
135 | String msg = "Cannot get declared methods " + " in " + inputClass.getName();
136 | if (abortOnUndefinedClass) {
137 | throw new DroidAssistNotFoundException(msg);
138 | } else {
139 | Logger.warning(msg);
140 | }
141 | }
142 | return declaredMethods;
143 | }
144 |
145 | //Get all declared constructors of the specified class
146 | protected CtConstructor[] tryGetDeclaredConstructors(CtClass inputClass) {
147 | CtConstructor[] declaredConstructors = new CtConstructor[0];
148 | try {
149 | declaredConstructors = inputClass.getDeclaredConstructors();
150 | } catch (Exception e) {
151 | String msg = "Cannot get declared constructors " + " in " + inputClass.getName();
152 | if (abortOnUndefinedClass) {
153 | throw new DroidAssistNotFoundException(msg);
154 | } else {
155 | Logger.warning(msg);
156 | }
157 | }
158 | return declaredConstructors;
159 | }
160 |
161 | //Get initialization method of the specified class
162 | protected CtConstructor tryGetClassInitializer(CtClass inputClass) {
163 | CtConstructor initializer = null;
164 | try {
165 | initializer = inputClass.getClassInitializer();
166 | } catch (Exception e) {
167 | String msg = "Cannot get class initializer " + " in " + inputClass.getName();
168 | if (abortOnUndefinedClass) {
169 | throw new DroidAssistNotFoundException(msg);
170 | } else {
171 | Logger.warning(msg);
172 | }
173 | }
174 | return initializer;
175 | }
176 |
177 |
178 | @Override
179 | public String toString() {
180 | return getName() + "{" +
181 | "filterClass=" + classFilterSpec +
182 | '}';
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/around/AroundTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.around;
2 |
3 | import com.didichuxing.tools.droidassist.transform.ExprExecTransformer;
4 |
5 | /**
6 | * An abstract transform that adds code before and after the target pointcut simultaneously.
7 | *
8 | * See {@link ConstructorCallAroundTransformer}, {@link ConstructorExecutionAroundTransformer},
9 | * {@link FieldAccessAroundTransformer}, {@link InitializerExecutionAroundTransformer},
10 | * {@link MethodCallAroundTransformer}, {@link MethodExecutionAroundTransformer}
11 | */
12 | public abstract class AroundTransformer extends ExprExecTransformer {
13 |
14 | private String targetBefore;
15 |
16 | private String targetAfter;
17 |
18 | public String getTargetBefore() {
19 | return targetBefore;
20 | }
21 |
22 | public AroundTransformer setTargetBefore(String targetBefore) {
23 | this.targetBefore = targetBefore.endsWith(";") ? targetBefore : targetBefore + ";";
24 | return this;
25 | }
26 |
27 | public String getTargetAfter() {
28 | return targetAfter;
29 | }
30 |
31 | public AroundTransformer setTargetAfter(String targetAfter) {
32 | this.targetAfter = targetAfter.endsWith(";") ? targetAfter : targetAfter + ";";
33 | return this;
34 | }
35 |
36 | @Override
37 | public String getName() {
38 | return "AroundTransformer";
39 | }
40 |
41 | @Override
42 | public String getCategoryName() {
43 | return "Around";
44 | }
45 |
46 | @Override
47 | protected String getAnnotationTarget() {
48 | return targetBefore + targetAfter;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return getName() + "\n{" +
54 | "\n source='" + getSource() + '\'' +
55 | "\n targetBefore='" + targetBefore + '\'' +
56 | "\n targetAfter='" + targetAfter + '\'' +
57 | "\n filterClass=" + classFilterSpec +
58 | "\n}";
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/around/ConstructorCallAroundTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.around;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.NewExpr;
9 |
10 | /**
11 | * Transform that adds code before and after the constructor method call simultaneously.
12 | */
13 | public class ConstructorCallAroundTransformer extends AroundTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "ConstructorCallAroundTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return NEW_EXPR;
28 | }
29 |
30 | @Override
31 | protected boolean filterClass(CtClass inputClass, String inputClassName) {
32 | return !isMatchSourceClassName(inputClassName);
33 | }
34 |
35 | @Override
36 | protected boolean execute(
37 | CtClass inputClass,
38 | String inputClassName,
39 | NewExpr expr)
40 | throws CannotCompileException, NotFoundException {
41 |
42 | String insnClassName = expr.getClassName();
43 | String insnSignature = expr.getSignature();
44 |
45 | if (!isMatchConstructorSource(insnClassName, insnSignature)) {
46 | return false;
47 | }
48 |
49 | String before = getTargetBefore();
50 | String after = getTargetAfter();
51 | // "$_=$proceed($$);" represents the original method body
52 | String statement = "{" + before + "$_=$proceed($$);" + after + "}";
53 | String replacement = replaceInstrument(inputClassName, expr, statement);
54 |
55 | Logger.warning(getPrettyName() + " by: " + replacement
56 | + " at " + inputClassName + ".java" + ":" + expr.getLineNumber());
57 | return true;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/around/ConstructorExecutionAroundTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.around;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtConstructor;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that adds code before and after the constructor execute simultaneously.
13 | */
14 | public class ConstructorExecutionAroundTransformer extends AroundTransformer {
15 |
16 | @Override
17 | public String getName() {
18 | return "ConstructorExecutionAroundTransformer";
19 | }
20 |
21 | @Override
22 | protected String getTransformType() {
23 | return TRANSFORM_EXEC;
24 | }
25 |
26 | @Override
27 | protected String getExecuteType() {
28 | return CONSTRUCTOR;
29 | }
30 |
31 | @Override
32 | protected boolean execute(
33 | CtClass inputClass,
34 | String inputClassName,
35 | CtConstructor constructor)
36 | throws CannotCompileException, NotFoundException {
37 |
38 | if (!isMatchConstructorSource(inputClassName, constructor)) {
39 | return false;
40 | }
41 | String before = getTargetBefore();
42 | String after = getTargetAfter();
43 |
44 | ClassUtils.newConstructorDelegate(
45 | classPool,
46 | inputClass,
47 | constructor,
48 | (source, result) -> {
49 | String body = "{" + before + source + after + "}";
50 | return getReplaceStatement(inputClassName, (CtConstructor) result.getSource(), body);
51 | }
52 | );
53 |
54 | Logger.warning(getPrettyName() + " by: " + before + " $proceed($$) "
55 | + after + " at " + inputClassName + ".java" + ":" + constructor.getName());
56 | return true;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/around/FieldAccessAroundTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.around;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.FieldAccess;
9 |
10 | /**
11 | * Transform that adds code before and after the field access simultaneously.
12 | */
13 | public class FieldAccessAroundTransformer extends AroundTransformer {
14 |
15 | //When fieldWrite is true, representing variable is written.
16 | private boolean fieldWrite = false;
17 |
18 | @Override
19 | public String getName() {
20 | return "FieldAccessAroundTransformer";
21 | }
22 |
23 | @Override
24 | protected String getTransformType() {
25 | return TRANSFORM_EXPR;
26 | }
27 |
28 | @Override
29 | protected String getExecuteType() {
30 | return FIELD_ACCESS;
31 | }
32 |
33 | @Override
34 | protected boolean filterClass(CtClass inputClass, String inputClassName) {
35 | return !isMatchSourceClassName(inputClassName);
36 | }
37 |
38 | @Override
39 | protected boolean execute(
40 | CtClass inputClass,
41 | String inputClassName,
42 | FieldAccess fieldAccess)
43 | throws CannotCompileException, NotFoundException {
44 |
45 | String insnClassName = fieldAccess.getClassName();
46 | String insnSignature = fieldAccess.getSignature();
47 | String insnFieldName = fieldAccess.getFieldName();
48 |
49 | if (!isMatchFieldSource(insnClassName, insnSignature, insnFieldName)
50 | || !meetConditions(fieldAccess)) {
51 | return false;
52 | }
53 |
54 | String before = getTargetBefore();
55 | String after = getTargetAfter();
56 |
57 | String proceed = fieldAccess.isWriter() ? "$proceed($$);" : "$_=$proceed($$);";
58 | String statement = "{" + before + proceed + after + "}";
59 | String replacement = replaceInstrument(inputClassName, fieldAccess, statement);
60 |
61 | Logger.warning(getPrettyName() + " by: " + replacement
62 | + " at " + inputClassName + ".java" + ":" + fieldAccess.getLineNumber());
63 | return true;
64 | }
65 |
66 | private boolean meetConditions(FieldAccess fieldAccess) {
67 | return fieldAccess.isWriter() == fieldWrite;
68 | }
69 |
70 | public FieldAccessAroundTransformer setFieldWrite(boolean write) {
71 | this.fieldWrite = write;
72 | return this;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/around/InitializerExecutionAroundTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.around;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtConstructor;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that adds code before and after the initializer call simultaneously.
13 | */
14 | public class InitializerExecutionAroundTransformer extends AroundTransformer {
15 | @Override
16 | public String getName() {
17 | return "InitializerExecutionAroundTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXEC;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return INITIALIZER;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | CtConstructor initializer)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | String before = getTargetBefore();
38 | String after = getTargetAfter();
39 |
40 | ClassUtils.newInitializerDelegate(
41 | classPool,
42 | inputClass,
43 | initializer,
44 | (source, result) -> {
45 | String body = "{" + before + source + after + "}";
46 | return getReplaceStatement(inputClassName, initializer, true, body);
47 | }
48 | );
49 | Logger.warning(getPrettyName() + " by: " + before + " $proceed($$) " + after
50 | + " at " + inputClassName + ".java" + ":" + initializer.getName());
51 |
52 | return true;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/around/MethodCallAroundTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.around;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.MethodCall;
9 |
10 | /**
11 | * Transform that adds code before and after the method call simultaneously.
12 | */
13 | public class MethodCallAroundTransformer extends AroundTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "MethodCallAroundTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return METHOD_CALL;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | MethodCall methodCall)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | if (methodCall.isSuper()) {
38 | return false;
39 | }
40 |
41 | String insnClassName = methodCall.getClassName();
42 | String insnName = methodCall.getMethodName();
43 | String insnSignature = methodCall.getSignature();
44 |
45 | CtClass insnClass = tryGetClass(insnClassName, inputClassName);
46 | if (insnClass == null) {
47 | return false;
48 | }
49 |
50 | if (!isMatchSourceMethod(insnClass, insnName, insnSignature, false)) {
51 | return false;
52 | }
53 | String before = getTargetBefore();
54 | String after = getTargetAfter();
55 |
56 | Logger.warning(getPrettyName() + " by: " + before + " $proceed($$) " + after
57 | + " at " + inputClassName + ".java" + ":" + methodCall.getLineNumber());
58 |
59 | String proceed = isVoidSourceReturnType() ? "$proceed($$);" : "$_ =$proceed($$);";
60 | String statement = "{" + before + proceed + after + "}";
61 |
62 | replaceInstrument(inputClassName, methodCall, statement);
63 |
64 | return true;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/around/MethodExecutionAroundTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.around;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtMethod;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that adds code before and after the method execute simultaneously.
13 | */
14 | public class MethodExecutionAroundTransformer extends AroundTransformer {
15 |
16 | @Override
17 | public String getName() {
18 | return "MethodExecutionAroundTransformer";
19 | }
20 |
21 | @Override
22 | protected String getTransformType() {
23 | return TRANSFORM_EXEC;
24 | }
25 |
26 | @Override
27 | protected String getExecuteType() {
28 | return METHOD;
29 | }
30 |
31 | @Override
32 | protected boolean execute(
33 | CtClass inputClass,
34 | String inputClassName,
35 | CtMethod method)
36 | throws CannotCompileException, NotFoundException {
37 |
38 | String name = method.getName();
39 | String signature = method.getSignature();
40 |
41 | if (!isMatchSourceMethod(inputClass, false, name, signature, method, true)) {
42 | return false;
43 | }
44 | String before = getTargetBefore();
45 | String after = getTargetAfter();
46 |
47 | ClassUtils.newMethodDelegate(
48 | inputClass,
49 | method,
50 | (source, result) -> {
51 | String body = "{" + before + source + after + "}";
52 | return getReplaceStatement(inputClassName, (CtMethod) result.getSource(), body);
53 | });
54 |
55 | Logger.warning(getPrettyName() + " by: " + before + " $proceed($$) "
56 | + after + " at " + inputClassName + ".java" + ":" + name);
57 | return true;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/ConstructorCallTimingTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.NewExpr;
9 |
10 | /**
11 | * Transform that adds constructor-call time-consuming statistics code.
12 | */
13 | public class ConstructorCallTimingTransformer extends TimingTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "ConstructorCallTimingTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return NEW_EXPR;
28 | }
29 |
30 | @Override
31 | protected boolean filterClass(CtClass inputClass, String inputClassName) {
32 | return !isMatchSourceClassName(inputClassName);
33 | }
34 |
35 | @Override
36 | protected boolean execute(
37 | CtClass inputClass,
38 | String inputClassName,
39 | NewExpr expr)
40 | throws CannotCompileException, NotFoundException {
41 |
42 | String insnClassName = expr.getClassName();
43 | String insnSignature = expr.getSignature();
44 |
45 | if (!isMatchConstructorSource(insnClassName, insnSignature)) {
46 | return false;
47 | }
48 |
49 | String statement = getDefaultTimingStatement(false, getTarget());
50 | String replacement = replaceInstrument(inputClassName, expr, statement);
51 |
52 | Logger.warning(getPrettyName() + " by: " + replacement
53 | + " at " + inputClassName + ".java" + ":" + expr.getLineNumber());
54 | return true;
55 | }
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/ConstructorCallTryCatchTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.NewExpr;
9 |
10 | /**
11 | * Transform that wraps constructor-call with try-catch.
12 | */
13 | public class ConstructorCallTryCatchTransformer extends TryCatchTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "ConstructorCallTryCatchTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return NEW_EXPR;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | NewExpr expr)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | if (isMatchSourceClassName(inputClassName)) {
38 | return false;
39 | }
40 |
41 | String insnClassName = expr.getClassName();
42 | String insnSignature = expr.getSignature();
43 |
44 | if (!isMatchConstructorSource(insnClassName, insnSignature)) {
45 | return false;
46 | }
47 |
48 | String proceed = "$_=$proceed($$);";
49 |
50 | String statement = "try{" + proceed + "} catch (" + getException() + " e) {"
51 | + getTarget().replace("$e", "e") + "}";
52 |
53 | String replacement = replaceInstrument(inputClassName, expr, statement);
54 |
55 | Logger.warning(getPrettyName() + " by: " + replacement
56 | + " at " + inputClassName + ".java" + ":" + expr.getLineNumber());
57 | return true;
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/ConstructorExecutionTimingTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtConstructor;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that adds constructor-execute time-consuming statistics code.
13 | */
14 | public class ConstructorExecutionTimingTransformer extends TimingTransformer {
15 |
16 | @Override
17 | public String getName() {
18 | return "ConstructorExecutionTimingTransformer";
19 | }
20 |
21 | @Override
22 | protected String getTransformType() {
23 | return TRANSFORM_EXEC;
24 | }
25 |
26 | @Override
27 | protected String getExecuteType() {
28 | return CONSTRUCTOR;
29 | }
30 |
31 | @Override
32 | protected boolean execute(
33 | CtClass inputClass,
34 | String inputClassName,
35 | CtConstructor constructor)
36 | throws CannotCompileException, NotFoundException {
37 |
38 | String name = constructor.getName();
39 |
40 | if (!isMatchConstructorSource(inputClassName, constructor)) {
41 | return false;
42 | }
43 | String target = getTarget();
44 |
45 | ClassUtils.newConstructorDelegate(
46 | classPool,
47 | inputClass,
48 | constructor,
49 | (source, result) -> {
50 | String statement = "{" + getTimingStatement(source, target) + "}";
51 | statement = getReplaceStatement(inputClassName, (CtConstructor) result.getSource(), statement);
52 | return statement;
53 | });
54 |
55 | Logger.warning(getPrettyName() + " by: " + target
56 | + " at " + inputClassName + ".java" + ":" + name);
57 |
58 | return true;
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/ConstructorExecutionTryCatchTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtConstructor;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that wraps constructor-execute with try-catch.
13 | */
14 | public class ConstructorExecutionTryCatchTransformer extends TryCatchTransformer {
15 |
16 | @Override
17 | public String getName() {
18 | return "ConstructorExecutionTryCatchTransformer";
19 | }
20 |
21 | @Override
22 | protected String getTransformType() {
23 | return TRANSFORM_EXEC;
24 | }
25 |
26 | @Override
27 | protected String getExecuteType() {
28 | return CONSTRUCTOR;
29 | }
30 |
31 | @Override
32 | protected boolean execute(
33 | CtClass inputClass,
34 | String inputClassName,
35 | CtConstructor constructor)
36 | throws CannotCompileException, NotFoundException {
37 |
38 | if (!isMatchConstructorSource(inputClassName, constructor)) {
39 | return false;
40 | }
41 | String target = getTarget();
42 |
43 | ClassUtils.newConstructorDelegate(
44 | classPool,
45 | inputClass,
46 | constructor,
47 | (source, result) -> {
48 | String targetStatement = target;
49 | targetStatement = targetStatement.replace("\\s+", " ");
50 | String statement = "try{" + source + "} catch (" + getException() + " e) {"
51 | + targetStatement.replace("$e", "e") + "}";
52 |
53 | return getReplaceStatement(inputClassName, (CtConstructor) result.getSource(), statement);
54 | });
55 |
56 | Logger.warning(getPrettyName() + " by: " + target
57 | + " at " + inputClassName + ".java" + ":" + constructor.getName());
58 | return true;
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/InitializerExecutionTimingTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtConstructor;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that adds initializer-execute time-consuming statistics code.
13 | */
14 | public class InitializerExecutionTimingTransformer extends TimingTransformer {
15 |
16 | @Override
17 | public String getName() {
18 | return "InitializerExecutionTimingTransformer";
19 | }
20 |
21 | @Override
22 | protected String getTransformType() {
23 | return TRANSFORM_EXEC;
24 | }
25 |
26 | @Override
27 | protected String getExecuteType() {
28 | return INITIALIZER;
29 | }
30 |
31 | @Override
32 | protected boolean execute(
33 | CtClass inputClass,
34 | String inputClassName,
35 | CtConstructor initializer)
36 | throws CannotCompileException, NotFoundException {
37 |
38 | String target = getTarget();
39 |
40 | ClassUtils.newInitializerDelegate(
41 | classPool,
42 | inputClass,
43 | initializer,
44 | (source, result) -> {
45 | String statement = "{" + getTimingStatement(source, target) + "}";
46 | statement = getReplaceStatement(inputClassName, initializer, true, statement);
47 | return statement;
48 | });
49 |
50 | Logger.warning(getPrettyName() + " by: " + target
51 | + " at " + inputClassName + ".java" + ":" + initializer.getName());
52 |
53 | return true;
54 | }
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/InitializerExecutionTryCatchTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtConstructor;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that wraps initializer-execute with try-catch.
13 | */
14 | public class InitializerExecutionTryCatchTransformer extends TryCatchTransformer {
15 |
16 | @Override
17 | public String getName() {
18 | return "InitializerExecutionTryCatchTransformer";
19 | }
20 |
21 | @Override
22 | protected String getTransformType() {
23 | return TRANSFORM_EXEC;
24 | }
25 |
26 | @Override
27 | protected String getExecuteType() {
28 | return INITIALIZER;
29 | }
30 |
31 | @Override
32 | protected boolean execute(
33 | CtClass inputClass,
34 | String inputClassName,
35 | CtConstructor initializer)
36 | throws CannotCompileException, NotFoundException {
37 | String target = getTarget();
38 |
39 | ClassUtils.newInitializerDelegate(
40 | classPool,
41 | inputClass,
42 | initializer,
43 | (source, result) -> {
44 | String statement = "try{"
45 | + source +
46 | "} catch (" + getException() + " e) {"
47 | + target.replace("$e", "e")
48 | + "}";
49 | statement = getReplaceStatement(inputClassName, initializer, true, statement);
50 | return statement;
51 | }
52 | );
53 |
54 | Logger.warning(getPrettyName() + " add catch for constructor exec by: " + target
55 | + " at " + inputClassName + ".java" + ":" + initializer.getName());
56 | return true;
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/MethodCallTimingTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.MethodCall;
9 |
10 | /**
11 | * Transform that adds method-call time-consuming statistics code.
12 | */
13 | public class MethodCallTimingTransformer extends TimingTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "MethodCallTimingTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return METHOD_CALL;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | MethodCall methodCall)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | if (methodCall.isSuper()) {
38 | return false;
39 | }
40 |
41 | String insnClassName = methodCall.getClassName();
42 | String insnName = methodCall.getMethodName();
43 | String insnSignature = methodCall.getSignature();
44 |
45 | CtClass insnClass = tryGetClass(insnClassName, inputClassName);
46 | if (insnClass == null) {
47 | return false;
48 | }
49 |
50 | if (!isMatchSourceMethod(insnClass, insnName, insnSignature, false)) {
51 | return false;
52 | }
53 |
54 | String target = getTarget();
55 | String statement = getDefaultTimingStatement(isVoidSourceReturnType(), target);
56 | String replacement = replaceInstrument(inputClassName, methodCall, statement);
57 |
58 | Logger.warning(getPrettyName() + " by: " + replacement
59 | + " at " + inputClassName + ".java" + ":" + methodCall.getLineNumber());
60 | return true;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/MethodCallTryCatchTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.MethodCall;
9 |
10 | /**
11 | * Transform that wraps method-call with try-catch.
12 | */
13 | public class MethodCallTryCatchTransformer extends TryCatchTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "MethodCallTryCatchTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return METHOD_CALL;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | MethodCall methodCall)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | if (methodCall.isSuper()) {
38 | return false;
39 | }
40 |
41 | String insnClassName = methodCall.getClassName();
42 | String insnName = methodCall.getMethodName();
43 | String insnSignature = methodCall.getSignature();
44 |
45 | CtClass insnClass = tryGetClass(insnClassName, inputClassName);
46 | if (insnClass == null) {
47 | return false;
48 | }
49 |
50 | if (!isMatchSourceMethod(insnClass, insnName, insnSignature, false)) {
51 | return false;
52 | }
53 | String target = getTarget();
54 |
55 | String proceed = isVoidSourceReturnType() ? "$proceed($$);" : "$_ =$proceed($$);";
56 |
57 | String statement = "try{" +
58 | proceed +
59 | "} catch (" + getException() + " e) {" +
60 | target.replace("$e", "e") +
61 | "}";
62 |
63 | String replacement = replaceInstrument(inputClassName, methodCall, statement);
64 |
65 | Logger.warning(getPrettyName() + " by: " + replacement
66 | + " at " + inputClassName + ".java" + ":" + methodCall.getLineNumber());
67 |
68 | return true;
69 | }
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/MethodExecutionTimingTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtMethod;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that adds method-execute time-consuming statistics code.
13 | */
14 | public class MethodExecutionTimingTransformer extends TimingTransformer {
15 |
16 | @Override
17 | public String getName() {
18 | return "MethodExecutionTimingTransformer";
19 | }
20 |
21 | @Override
22 | protected String getTransformType() {
23 | return TRANSFORM_EXEC;
24 | }
25 |
26 | @Override
27 | protected String getExecuteType() {
28 | return METHOD;
29 | }
30 |
31 | @Override
32 | protected boolean execute(
33 | CtClass inputClass,
34 | String inputClassName,
35 | CtMethod method)
36 | throws CannotCompileException, NotFoundException {
37 |
38 | String name = method.getName();
39 | String signature = method.getSignature();
40 |
41 | if (!isMatchSourceMethod(inputClass, false, name, signature, method, true)) {
42 | return false;
43 | }
44 | String target = getTarget();
45 |
46 | ClassUtils.newMethodDelegate(
47 | inputClass,
48 | method,
49 | (source, result) -> {
50 | String body = "{" + getTimingStatement(source, target) + "}";
51 | return getReplaceStatement(inputClassName, (CtMethod) result.getSource(), body);
52 | });
53 |
54 | Logger.warning(getPrettyName() + " by: " + target
55 | + " at " + inputClassName + ".java" + ":" + name);
56 |
57 | return true;
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/MethodExecutionTryCatchTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.util.ClassUtils;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 |
6 | import javassist.CannotCompileException;
7 | import javassist.CtClass;
8 | import javassist.CtMethod;
9 | import javassist.NotFoundException;
10 |
11 | /**
12 | * Transform that wraps method-execute with try-catch.
13 | */
14 | public class MethodExecutionTryCatchTransformer extends TryCatchTransformer {
15 |
16 | @Override
17 | public String getName() {
18 | return "MethodExecutionTryCatchTransformer";
19 | }
20 |
21 | @Override
22 | protected String getTransformType() {
23 | return TRANSFORM_EXEC;
24 | }
25 |
26 | @Override
27 | protected String getExecuteType() {
28 | return METHOD;
29 | }
30 |
31 | @Override
32 | protected boolean execute(
33 | CtClass inputClass,
34 | String inputClassName,
35 | CtMethod method)
36 | throws CannotCompileException, NotFoundException {
37 |
38 | String name = method.getName();
39 | String signature = method.getSignature();
40 |
41 | if (!isMatchSourceMethod(inputClass, false, name, signature, method, true)) {
42 | return false;
43 | }
44 | String target = getTarget();
45 |
46 | addCatchForMethod(inputClass, method, getExceptionClass(), target);
47 |
48 | Logger.warning(getPrettyName() + "by: " + target
49 | + " at " + inputClassName + ".java" + ":" + name);
50 |
51 | return true;
52 | }
53 |
54 |
55 | private void addCatchForMethod(
56 | CtClass clazz,
57 | CtMethod method,
58 | CtClass exceptionType,
59 | String target)
60 | throws NotFoundException, CannotCompileException {
61 |
62 | ClassUtils.DelegateResult result =
63 | ClassUtils.newMethodDelegate(clazz, method, null);
64 |
65 | CtMethod srcMethod = result.getSource();
66 | String type = method.getReturnType().getName();
67 | boolean isVoid = "void".equals(type);
68 |
69 | StringBuilder builder = new StringBuilder(target);
70 | target = target.replace("\\s+", " ");
71 | boolean returnStatement =
72 | target.contains(" return ")
73 | || target.contains("return ")
74 | || target.contains(" return;")
75 | || target.contains(";return;")
76 | || target.contains(";return ")
77 | || target.contains(" throw ")
78 | || target.contains("throw ")
79 | || target.contains(";throw ");
80 | if (isVoid) {
81 | if (!returnStatement) {
82 | builder.append("return;");
83 | }
84 | } else {
85 | if (!returnStatement) {
86 | throw new CannotCompileException(
87 | "Catch block code fragment must end with a throw or return statement, " +
88 | "but found: " + target);
89 | }
90 | }
91 | target = getReplaceStatement(clazz.getName(), method, builder.toString());
92 | srcMethod.addCatch(target, exceptionType);
93 | }
94 | }
95 |
96 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/ReparentClassTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.transform.ExprExecTransformer;
4 | import com.didichuxing.tools.droidassist.util.Logger;
5 | import com.google.common.collect.Sets;
6 |
7 | import java.util.Set;
8 |
9 | import javassist.CannotCompileException;
10 | import javassist.CtClass;
11 | import javassist.NotFoundException;
12 | import javassist.bytecode.Descriptor;
13 | import javassist.expr.ConstructorCall;
14 | import javassist.expr.FieldAccess;
15 | import javassist.expr.MethodCall;
16 |
17 | /**
18 | * An transform that support for class parent reset
19 | *
20 | * See {@link ConstructorCallTryCatchTransformer}, {@link ConstructorExecutionTryCatchTransformer},
21 | * {@link InitializerExecutionTryCatchTransformer}, {@link MethodCallTryCatchTransformer},
22 | * {@link MethodCallTryCatchTransformer}
23 | */
24 | public class ReparentClassTransformer extends ExprExecTransformer {
25 |
26 | private CtClass targetClass;
27 |
28 | @Override
29 | public String getName() {
30 | return "ReparentClassTransformer";
31 | }
32 |
33 | public String getCategoryName() {
34 | return "Reparent";
35 | }
36 |
37 | @Override
38 | protected String getTransformType() {
39 | return TRANSFORM_EXPR;
40 | }
41 |
42 | @Override
43 | protected String getExecuteType() {
44 | return METHOD_CALL;
45 | }
46 |
47 | @Override
48 | protected Set See {@link ConstructorCallTimingTransformer}, {@link ConstructorExecutionTimingTransformer},
12 | * {@link InitializerExecutionTimingTransformer}, {@link MethodCallTimingTransformer},
13 | * {@link MethodExecutionTimingTransformer}
14 | */
15 | public abstract class TimingTransformer extends ExprExecTransformer {
16 | @Override
17 | public String getCategoryName() {
18 | return "Timing";
19 | }
20 |
21 | String getDefaultTimingStatement(boolean isVoidReturnType, String target) {
22 | String proceed = isVoidReturnType ? "$proceed($$);" : "$_ =$proceed($$);";
23 | return getTimingStatement(proceed, target);
24 | }
25 |
26 | String getTimingStatement(String proceed, String target) {
27 | return "long start = java.lang.System.nanoTime();" +
28 | proceed +
29 | "long nanoTime = java.lang.System.nanoTime()-start;" +
30 | target.replaceAll(Pattern.quote("$time"),
31 | Matcher.quoteReplacement("(nanoTime/1000000)").
32 | replaceAll(Pattern.quote("$nanotime"),
33 | Matcher.quoteReplacement("(nanoTime)")));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/enhance/TryCatchTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.enhance;
2 |
3 | import com.didichuxing.tools.droidassist.spec.SourceSpec;
4 | import com.didichuxing.tools.droidassist.transform.ExprExecTransformer;
5 |
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 |
9 | /**
10 | * An abstract transform that wraps target code with try-catch.
11 | *
12 | * See {@link ConstructorCallTryCatchTransformer}, {@link ConstructorExecutionTryCatchTransformer},
13 | * {@link InitializerExecutionTryCatchTransformer}, {@link MethodCallTryCatchTransformer},
14 | * {@link MethodCallTryCatchTransformer}
15 | */
16 | public abstract class TryCatchTransformer extends ExprExecTransformer {
17 | private String exception;
18 | private CtClass exceptionClass;
19 |
20 | @Override
21 | public String getCategoryName() {
22 | return "TryCatch";
23 | }
24 |
25 | protected String getException() {
26 | if (exception == null || exception.trim().equals("")) {
27 | exception = " java.lang.Exception";
28 | }
29 | return SourceSpec.Type.forName(exception).getName();
30 | }
31 |
32 | protected CtClass getExceptionClass() throws NotFoundException {
33 | if (exceptionClass == null) {
34 | exceptionClass = classPool.get(getException());
35 | }
36 | return exceptionClass;
37 | }
38 |
39 | public TryCatchTransformer setException(String exception) {
40 | this.exception = exception;
41 | return this;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/insert/ConstructorCallInsertTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.insert;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.NewExpr;
9 |
10 | /**
11 | * Transform that inserts custom code at the pointcut where constructor is called.
12 | */
13 | public class ConstructorCallInsertTransformer extends InsertTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "ConstructorCallInsertTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return NEW_EXPR;
28 | }
29 |
30 | @Override
31 | protected boolean filterClass(CtClass inputClass, String inputClassName) {
32 | return !isMatchSourceClassName(inputClassName);
33 | }
34 |
35 | @Override
36 | protected boolean execute(
37 | CtClass inputClass,
38 | String inputClassName,
39 | NewExpr newExpr)
40 | throws CannotCompileException, NotFoundException {
41 |
42 | String insnClassName = newExpr.getClassName();
43 | String insnSignature = newExpr.getSignature();
44 |
45 | if (!isMatchConstructorSource(insnClassName, insnSignature)) {
46 | return false;
47 | }
48 | String target = getTarget();
49 |
50 | if (!target.endsWith(";")) {
51 | target = target + ";";
52 | }
53 | String before = isAsBefore() ? target : "";
54 | String after = isAsAfter() ? target : "";
55 | String statement = "{" + before + "$_=$proceed($$);" + after + "}";
56 | String replacement = replaceInstrument(inputClassName, newExpr, statement);
57 |
58 | if (isAsBefore()) {
59 | Logger.warning(getPrettyName() + " by before: " + replacement
60 | + " at " + inputClassName + ".java" + ":" + newExpr.getLineNumber());
61 | }
62 |
63 | if (isAsAfter()) {
64 | Logger.warning(getPrettyName() + " by after: " + replacement
65 | + " at " + inputClassName + ".java" + ":" + newExpr.getLineNumber());
66 | }
67 | return true;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/insert/ConstructorExecutionInsertTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.insert;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.CtConstructor;
8 | import javassist.NotFoundException;
9 |
10 | /**
11 | * Transform that inserts custom code at the pointcut where constructor executes.
12 | */
13 | public class ConstructorExecutionInsertTransformer extends InsertTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "ConstructorExecutionInsertTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXEC;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return CONSTRUCTOR;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | CtConstructor constructor)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | if (!isMatchConstructorSource(inputClassName, constructor)) {
38 | return false;
39 | }
40 | String target = getTarget();
41 | String name = constructor.getName();
42 |
43 | target = getReplaceStatement(inputClassName, constructor, target);
44 |
45 | if (isAsBefore()) {
46 | constructor.insertBeforeBody(target);
47 | Logger.warning(getPrettyName() + " by before: " + target
48 | + " at " + inputClassName + ".java" + ":" + name);
49 | }
50 | if (isAsAfter()) {
51 | constructor.insertAfter(target);
52 | Logger.warning(getPrettyName() + " by after: " + target
53 | + " at " + inputClassName + ".java" + ":" + name);
54 | }
55 | return false;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/insert/FieldAccessInsertTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.insert;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.FieldAccess;
9 |
10 | /**
11 | * Transform that inserts custom code at the pointcut where field is read or written.
12 | */
13 | public class FieldAccessInsertTransformer extends InsertTransformer {
14 |
15 | private boolean fieldWrite = false;
16 |
17 | @Override
18 | public String getName() {
19 | return "FieldAccessInsertTransformer";
20 | }
21 |
22 | @Override
23 | protected String getTransformType() {
24 | return TRANSFORM_EXPR;
25 | }
26 |
27 | @Override
28 | protected String getExecuteType() {
29 | return FIELD_ACCESS;
30 | }
31 |
32 | @Override
33 | protected boolean filterClass(CtClass inputClass, String inputClassName) {
34 | return !isMatchSourceClassName(inputClassName);
35 | }
36 |
37 | @Override
38 | protected boolean execute(
39 | CtClass inputClass,
40 | String inputClassName,
41 | FieldAccess fieldAccess)
42 | throws CannotCompileException, NotFoundException {
43 |
44 | String insnClassName = fieldAccess.getClassName();
45 | String insnSignature = fieldAccess.getSignature();
46 | String insnFieldName = fieldAccess.getFieldName();
47 |
48 | if (!isMatchFieldSource(insnClassName, insnSignature, insnFieldName)
49 | || !meetConditions(fieldAccess)) {
50 | return false;
51 | }
52 |
53 | String target = getTarget();
54 | String proceed = fieldAccess.isWriter() ? "$proceed($$);" : "$_=$proceed($$);";
55 | String statement = ""
56 | + "{"
57 | + (isAsBefore() ? target : "")
58 | + proceed
59 | + (isAsAfter() ? target : "")
60 | + "}";
61 |
62 | String replacement = replaceInstrument(inputClassName, fieldAccess, statement);
63 |
64 | Logger.warning(getPrettyName() + " by: " + replacement
65 | + " at " + inputClassName + ".java" + ":" + fieldAccess.getLineNumber());
66 | return true;
67 | }
68 |
69 | private boolean meetConditions(FieldAccess fieldAccess) {
70 | return fieldAccess.isWriter() == fieldWrite;
71 | }
72 |
73 | public FieldAccessInsertTransformer setFieldWrite(boolean write) {
74 | this.fieldWrite = write;
75 | return this;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/insert/InitializerExecutionInsertTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.insert;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.CtConstructor;
8 | import javassist.NotFoundException;
9 |
10 | /**
11 | * Transform that inserts custom code at the pointcut where initializer executes.
12 | */
13 | public class InitializerExecutionInsertTransformer extends InsertTransformer {
14 | @Override
15 | public String getName() {
16 | return "InitializerExecutionInsertTransformer";
17 | }
18 |
19 | @Override
20 | protected String getTransformType() {
21 | return TRANSFORM_EXEC;
22 | }
23 |
24 | @Override
25 | protected String getExecuteType() {
26 | return INITIALIZER;
27 | }
28 |
29 | @Override
30 | protected boolean execute(
31 | CtClass inputClass,
32 | String inputClassName,
33 | CtConstructor initializer)
34 | throws CannotCompileException, NotFoundException {
35 |
36 | String target = getTarget();
37 |
38 | target = getReplaceStatement(inputClassName, initializer, true, target);
39 | if (isAsBefore()) {
40 | initializer.insertBefore(target);
41 | Logger.warning(getPrettyName() + " insert after execution by: " + target
42 | + " at " + inputClassName + ".java" + ":" + initializer.getName());
43 | }
44 | if (isAsAfter()) {
45 | initializer.insertAfter(target);
46 | Logger.warning(getPrettyName() + " insert after execution by: " + target
47 | + " at " + inputClassName + ".java" + ":" + initializer.getName());
48 | }
49 | return true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/insert/InsertTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.insert;
2 |
3 | import com.didichuxing.tools.droidassist.transform.ExprExecTransformer;
4 |
5 | /**
6 | * An abstract transform that inserts code at the pointcut.
7 | *
8 | * See {@link ConstructorCallInsertTransformer}, {@link ConstructorExecutionInsertTransformer},
9 | * {@link FieldAccessInsertTransformer}, {@link InitializerExecutionInsertTransformer},
10 | * {@link MethodCallInsertTransformer}, {@link MethodExecutionInsertTransformer}
11 | */
12 | @SuppressWarnings("WeakerAccess")
13 | public abstract class InsertTransformer extends ExprExecTransformer {
14 |
15 | private boolean asBefore = false;
16 | private boolean asAfter = false;
17 |
18 | @Override
19 | public String getCategoryName() {
20 | return "Insert";
21 | }
22 |
23 | @Override
24 | public String getName() {
25 | return "InsertTransformer";
26 | }
27 |
28 | public boolean isAsBefore() {
29 | return asBefore;
30 | }
31 |
32 | public InsertTransformer setAsBefore(boolean asBefore) {
33 | this.asBefore = asBefore;
34 | return this;
35 | }
36 |
37 | public boolean isAsAfter() {
38 | return asAfter;
39 | }
40 |
41 | public InsertTransformer setAsAfter(boolean asAfter) {
42 | this.asAfter = asAfter;
43 | return this;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/insert/MethodCallInsertTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.insert;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.MethodCall;
9 |
10 | /**
11 | * Transform that inserts custom code at the pointcut where method is called.
12 | */
13 | public class MethodCallInsertTransformer extends InsertTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "MethodCallInsertTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return METHOD_CALL;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | MethodCall methodCall)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | if (methodCall.isSuper()) {
38 | return false;
39 | }
40 | String insnClassName = methodCall.getClassName();
41 | String insnName = methodCall.getMethodName();
42 | String insnSignature = methodCall.getSignature();
43 |
44 | CtClass insnClass = tryGetClass(insnClassName, inputClassName);
45 | if (insnClass == null) {
46 | return false;
47 | }
48 | if (!isMatchSourceMethod(insnClass, insnName, insnSignature, false)) {
49 | return false;
50 | }
51 |
52 | String target = getTarget();
53 | int line = methodCall.getLineNumber();
54 | if (!target.endsWith(";")) target = target + ";";
55 |
56 | String before = isAsBefore() ? target : "";
57 | String after = isAsAfter() ? target : "";
58 |
59 | String proceed = isVoidSourceReturnType() ? "$proceed($$);" : "$_ =$proceed($$);";
60 |
61 | String statement = before + proceed + after;
62 |
63 | String replacement = replaceInstrument(inputClassName, methodCall, statement);
64 |
65 | if (isAsBefore()) {
66 | Logger.warning(getPrettyName() + " insert before call by: " + replacement
67 | + " at " + inputClassName + ".java" + ":" + line);
68 | }
69 |
70 | if (isAsAfter()) {
71 | Logger.warning(getPrettyName() + " insert after call by: " + replacement
72 | + " at " + inputClassName + ".java" + ":" + line);
73 | }
74 | return true;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/insert/MethodExecutionInsertTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.insert;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.CtMethod;
8 | import javassist.NotFoundException;
9 |
10 | /**
11 | * Transform that inserts custom code at the pointcut where method executes.
12 | */
13 | public class MethodExecutionInsertTransformer extends InsertTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "MethodExecutionInsertTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXEC;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return METHOD;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | CtMethod method)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | String name = method.getName();
38 | String signature = method.getSignature();
39 |
40 | if (!isMatchSourceMethod(inputClass, false, name, signature, method, true)) {
41 | return false;
42 | }
43 |
44 | String target = getTarget();
45 | target = getReplaceStatement(inputClassName, method, target);
46 | if (isAsBefore()) {
47 | method.insertBefore(target);
48 | Logger.warning(getPrettyName() + " by before: " + target
49 | + " at " + inputClassName + ".java" + ":" + name);
50 | }
51 | if (isAsAfter()) {
52 | method.insertAfter(target);
53 | Logger.warning(getPrettyName() + " by after: " + target
54 | + " at " + inputClassName + ".java" + ":" + name);
55 | }
56 | return true;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/replace/ConstructorCallReplaceTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.replace;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.NewExpr;
9 |
10 | /**
11 | * Transform that replaces constructor-call with new code.
12 | */
13 | public class ConstructorCallReplaceTransformer extends ReplaceTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "ConstructorCallReplaceTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXPR;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return NEW_EXPR;
28 | }
29 |
30 | @Override
31 | protected boolean filterClass(CtClass inputClass, String inputClassName) {
32 | return !isMatchSourceClassName(inputClassName);
33 | }
34 |
35 | @Override
36 | protected boolean execute(
37 | CtClass inputClass,
38 | String inputClassName,
39 | NewExpr newExpr)
40 | throws CannotCompileException, NotFoundException {
41 |
42 | String insnClassName = newExpr.getClassName();
43 | String insnSignature = newExpr.getSignature();
44 |
45 | if (!isMatchConstructorSource(insnClassName, insnSignature)) {
46 | return false;
47 | }
48 |
49 | String target = getTarget();
50 |
51 | if (!target.startsWith("$_=") || !target.startsWith("$_ =")) {
52 | if (target.startsWith("{")) {
53 | target = "{" + "$_=" + target.substring(1);
54 | } else {
55 | target = "$_=" + target;
56 | }
57 | }
58 |
59 | String replacement = replaceInstrument(inputClassName, newExpr, target);
60 |
61 | Logger.warning(getPrettyName() + "by: " + replacement
62 | + " at " + inputClassName + ".java" + ":" + newExpr.getLineNumber());
63 | return true;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/replace/ConstructorExecutionReplaceTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.replace;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.CtConstructor;
8 | import javassist.NotFoundException;
9 |
10 | /**
11 | * Transform that replaces constructor-execute with new code.
12 | */
13 | public class ConstructorExecutionReplaceTransformer extends ReplaceTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "ConstructorExecutionReplaceTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXEC;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return CONSTRUCTOR;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | CtConstructor constructor)
35 | throws CannotCompileException, NotFoundException {
36 |
37 | if (!isMatchConstructorSource(inputClassName, constructor)) {
38 | return false;
39 | }
40 | String target = getTarget();
41 | replaceInstrument(inputClassName, constructor, target);
42 | Logger.warning(getPrettyName() + " replaced execution by: " + target
43 | + " at " + inputClassName + ".java" + ":" + constructor.getName());
44 | return true;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/replace/FieldAccessReplaceTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.replace;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.NotFoundException;
8 | import javassist.expr.FieldAccess;
9 |
10 | /**
11 | * Transform that replaces field-access with new code.
12 | */
13 | public class FieldAccessReplaceTransformer extends ReplaceTransformer {
14 |
15 | private boolean fieldWrite = false;
16 |
17 | @Override
18 | public String getName() {
19 | return "FieldAccessReplaceTransformer";
20 | }
21 |
22 | @Override
23 | protected String getTransformType() {
24 | return TRANSFORM_EXPR;
25 | }
26 |
27 | @Override
28 | protected String getExecuteType() {
29 | return FIELD_ACCESS;
30 | }
31 |
32 | @Override
33 | protected boolean filterClass(CtClass inputClass, String inputClassName) {
34 | return !isMatchSourceClassName(inputClassName);
35 | }
36 |
37 | @Override
38 | protected boolean execute(
39 | CtClass inputClass,
40 | String inputClassName,
41 | FieldAccess fieldAccess)
42 | throws CannotCompileException, NotFoundException {
43 |
44 | String insnClassName = fieldAccess.getClassName();
45 | String insnSignature = fieldAccess.getSignature();
46 | String insnFieldName = fieldAccess.getFieldName();
47 |
48 | if (!isMatchFieldSource(insnClassName, insnSignature, insnFieldName)
49 | || !meetConditions(fieldAccess)) {
50 | return false;
51 | }
52 |
53 | String target = getTarget();
54 | String replacement = replaceInstrument(inputClassName, fieldAccess, target);
55 |
56 | Logger.warning(getPrettyName() + " by: " +
57 | (fieldAccess.isWriter() ? " write" : " read") + replacement + " at " +
58 | inputClassName + ".java" + ":" + fieldAccess.getLineNumber());
59 | return true;
60 | }
61 |
62 | private boolean meetConditions(FieldAccess fieldAccess) {
63 | return fieldAccess.isWriter() == fieldWrite;
64 | }
65 |
66 | public FieldAccessReplaceTransformer setFieldWrite(boolean write) {
67 | this.fieldWrite = write;
68 | return this;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/replace/InitializerExecutionReplaceTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.replace;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.CtConstructor;
8 | import javassist.NotFoundException;
9 |
10 | /**
11 | * Transform that replaces initializer-execute with new code.
12 | */
13 | public class InitializerExecutionReplaceTransformer extends ReplaceTransformer {
14 | @Override
15 | public String getName() {
16 | return "InitializerExecutionReplaceTransformer";
17 | }
18 |
19 | @Override
20 | protected String getTransformType() {
21 | return TRANSFORM_EXEC;
22 | }
23 |
24 | @Override
25 | protected String getExecuteType() {
26 | return INITIALIZER;
27 | }
28 |
29 | @Override
30 | protected boolean execute(
31 | CtClass inputClass,
32 | String inputClassName,
33 | CtConstructor constructor)
34 | throws CannotCompileException, NotFoundException {
35 |
36 | String target = getTarget();
37 | target = getReplaceStatement(inputClassName, constructor, true, target);
38 | constructor.setBody(target);
39 | Logger.warning(getPrettyName() + " replaced execution by: " + target
40 | + " at " + inputClassName + ".java" + ":" + constructor.getName());
41 | return true;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/replace/MethodCallReplaceTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.replace;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import java.util.regex.Matcher;
6 | import java.util.regex.Pattern;
7 |
8 | import javassist.CannotCompileException;
9 | import javassist.CtClass;
10 | import javassist.NotFoundException;
11 | import javassist.expr.MethodCall;
12 |
13 | /**
14 | * Transform that replaces method-call with new code.
15 | */
16 | public class MethodCallReplaceTransformer extends ReplaceTransformer {
17 |
18 | @Override
19 | public String getName() {
20 | return "MethodCallReplaceTransformer";
21 | }
22 |
23 | @Override
24 | protected String getTransformType() {
25 | return TRANSFORM_EXPR;
26 | }
27 |
28 | @Override
29 | protected String getExecuteType() {
30 | return METHOD_CALL;
31 | }
32 |
33 | @Override
34 | protected boolean execute(
35 | CtClass inputClass,
36 | String inputClassName,
37 | MethodCall methodCall)
38 | throws CannotCompileException, NotFoundException {
39 | if (methodCall.isSuper()) {
40 | return false;
41 | }
42 |
43 | String insnClassName = methodCall.getClassName();
44 | String insnName = methodCall.getMethodName();
45 | String insnSignature = methodCall.getSignature();
46 |
47 | CtClass insnClass = tryGetClass(insnClassName, inputClassName);
48 | if (insnClass == null) {
49 | return false;
50 | }
51 |
52 | if (!isMatchSourceMethod(insnClass, insnName, insnSignature, false)) {
53 | return false;
54 | }
55 |
56 | String target = getTarget();
57 | String replacement = replaceInstrument(inputClassName, methodCall, target);
58 | Logger.warning(getPrettyName() + " by: " + replacement
59 | + " at " + inputClassName + ".java" + ":" + methodCall.getLineNumber());
60 | return true;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/replace/MethodExecutionReplaceTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.replace;
2 |
3 | import com.didichuxing.tools.droidassist.util.Logger;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.CtClass;
7 | import javassist.CtMethod;
8 | import javassist.NotFoundException;
9 |
10 | /**
11 | * Transform that replaces method-execute with new code.
12 | */
13 | public class MethodExecutionReplaceTransformer extends ReplaceTransformer {
14 |
15 | @Override
16 | public String getName() {
17 | return "MethodExecutionReplaceTransformer";
18 | }
19 |
20 | @Override
21 | protected String getTransformType() {
22 | return TRANSFORM_EXEC;
23 | }
24 |
25 | @Override
26 | protected String getExecuteType() {
27 | return METHOD;
28 | }
29 |
30 | @Override
31 | protected boolean execute(
32 | CtClass inputClass,
33 | String inputClassName,
34 | CtMethod method)
35 | throws CannotCompileException, NotFoundException {
36 | String name = method.getName();
37 | String signature = method.getSignature();
38 |
39 | if (!isMatchSourceMethod(inputClass, false, name, signature, method, true)) {
40 | return false;
41 | }
42 | String target = getTarget();
43 | target = getReplaceStatement(inputClassName, method, target);
44 | method.setBody(target);
45 | Logger.warning(getPrettyName() + " by: " + target
46 | + " at " + inputClassName + ".java" + ":" + name);
47 | return true;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/transform/replace/ReplaceTransformer.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.transform.replace;
2 |
3 | import com.didichuxing.tools.droidassist.transform.ExprExecTransformer;
4 |
5 | /**
6 | * An abstract transform that replaces the specified code with new code.
7 | *
8 | * See{@link ConstructorCallReplaceTransformer}, {@link ConstructorExecutionReplaceTransformer},
9 | * {@link FieldAccessReplaceTransformer}, {@link InitializerExecutionReplaceTransformer},
10 | * {@link MethodCallReplaceTransformer}, {@link MethodExecutionReplaceTransformer}
11 | */
12 | public abstract class ReplaceTransformer extends ExprExecTransformer {
13 | @Override
14 | public String getName() {
15 | return "ReplaceTransformer";
16 | }
17 |
18 | @Override
19 | public String getCategoryName() {
20 | return "Replace";
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/plugin/src/main/groovy/com/didichuxing/tools/droidassist/util/ClassUtils.java:
--------------------------------------------------------------------------------
1 | package com.didichuxing.tools.droidassist.util;
2 |
3 | import java.util.List;
4 |
5 | import javassist.CannotCompileException;
6 | import javassist.ClassPool;
7 | import javassist.CtClass;
8 | import javassist.CtConstructor;
9 | import javassist.CtMember;
10 | import javassist.CtMethod;
11 | import javassist.CtNewMethod;
12 | import javassist.Modifier;
13 | import javassist.NotFoundException;
14 | import javassist.bytecode.AccessFlag;
15 | import javassist.bytecode.AnnotationsAttribute;
16 | import javassist.bytecode.AttributeInfo;
17 | import javassist.bytecode.BadBytecode;
18 | import javassist.bytecode.CodeAttribute;
19 | import javassist.bytecode.CodeIterator;
20 | import javassist.bytecode.ConstPool;
21 | import javassist.bytecode.ExceptionTable;
22 | import javassist.bytecode.MethodInfo;
23 | import javassist.bytecode.Opcode;
24 |
25 | @SuppressWarnings("RedundantThrows")
26 | public class ClassUtils {
27 | public interface BodyProducer {
28 | String createBody(String source, DelegateResult result);
29 | }
30 |
31 | public static class DelegateResult {
32 | private final CtMember source;
33 | private final CtMember delegate;
34 | private final String statement;
35 |
36 | private DelegateResult(CtMember source, CtMember delegate, String statement) {
37 | this.source = source;
38 | this.delegate = delegate;
39 | this.statement = statement;
40 | }
41 |
42 | @SuppressWarnings("unchecked")
43 | public