memberMapping) {
39 | this.memberMapping = memberMapping;
40 | }
41 |
42 | @Override
43 | public boolean equals(Object o) {
44 | if (this == o) return true;
45 | if (!(o instanceof ClassMapping)) return false;
46 |
47 | ClassMapping classMapping = (ClassMapping) o;
48 |
49 | return getClassName() != null ? getClassName().equals(classMapping.getClassName()) : classMapping.getClassName() == null;
50 |
51 | }
52 |
53 | @Override
54 | public int hashCode() {
55 | return getClassName() != null ? getClassName().hashCode() : 0;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/java/com/meituan/robust/autopatch/Config.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.autopatch;
2 |
3 | import com.meituan.robust.Constants;
4 |
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.HashSet;
8 | import java.util.LinkedHashMap;
9 | import java.util.List;
10 | import java.util.Map;
11 | import java.util.Set;
12 |
13 | import javassist.ClassPool;
14 | import javassist.CtMethod;
15 |
16 | import static com.meituan.robust.Constants.DEFAULT_MAPPING_FILE;
17 |
18 | /**
19 | * Created by mivanzhang on 16/12/2.
20 | *
21 | * members read from robust.xml
22 | */
23 |
24 | public final class Config {
25 | public static boolean catchReflectException = false;
26 | public static boolean supportProGuard = true;
27 | public static boolean isLogging = true;
28 | public static boolean isManual = false;
29 | public static String patchPackageName = Constants.PATCH_PACKAGENAME;
30 | public static String mappingFilePath;
31 | public static Set patchMethodSignatureSet = new HashSet<>();
32 | public static List newlyAddedClassNameList = new ArrayList();
33 | public static Set newlyAddedMethodSet = new HashSet();
34 | public static List modifiedClassNameList = new ArrayList();
35 | public static List hotfixPackageList = new ArrayList<>();
36 | public static LinkedHashMap methodMap = new LinkedHashMap<>();
37 | public static String robustGenerateDirectory;
38 | public static Map> invokeSuperMethodMap = new HashMap<>();
39 | public static ClassPool classPool = new ClassPool();
40 | public static Set methodNeedPatchSet = new HashSet();
41 | public static List addedSuperMethodList = new ArrayList<>();
42 | public static Set noNeedReflectClassSet = new HashSet<>();
43 |
44 |
45 | public static void init() {
46 | catchReflectException = false;
47 | isLogging = true;
48 | isManual = false;
49 | patchPackageName = Constants.PATCH_PACKAGENAME;
50 | mappingFilePath = DEFAULT_MAPPING_FILE;
51 | patchMethodSignatureSet = new HashSet<>();
52 | newlyAddedClassNameList = new ArrayList();
53 | modifiedClassNameList = new ArrayList();
54 | hotfixPackageList = new ArrayList<>();
55 | newlyAddedMethodSet = new HashSet<>();
56 | invokeSuperMethodMap = new HashMap<>();
57 | classPool = new ClassPool();
58 | methodNeedPatchSet = new HashSet();
59 | addedSuperMethodList = new ArrayList<>();
60 | noNeedReflectClassSet = new HashSet<>();
61 | noNeedReflectClassSet.addAll(Constants.NO_NEED_REFLECT_CLASS);
62 | supportProGuard=true;
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/java/com/meituan/robust/autopatch/NameManger.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.autopatch;
2 |
3 | import com.meituan.robust.Constants;
4 |
5 | import java.util.HashMap;
6 |
7 | /**
8 | * Created by mivanzhang on 17/2/10.
9 | *
10 | * manager patches' name ,inline patch name
11 | */
12 |
13 | public class NameManger {
14 | private static NameManger nameManger;
15 | private HashMap patchNameMap = new HashMap();
16 |
17 | private NameManger() {
18 |
19 | }
20 |
21 | public static void init() {
22 | nameManger = new NameManger();
23 | }
24 |
25 | public static NameManger getInstance() {
26 | if (nameManger == null) {
27 | nameManger = new NameManger();
28 | }
29 | return nameManger;
30 | }
31 |
32 | public HashMap getPatchNameMap() {
33 | return patchNameMap;
34 | }
35 |
36 | /***
37 | * @param className java class name java.lang.object
38 | * @return patchname.object
39 | */
40 | public String getPatchName(String className) {
41 | String patchName = getPatchNamWithoutRecord(className);
42 | patchNameMap.put(patchName, className);
43 | return patchName;
44 | }
45 |
46 | public String getInlinePatchName(String className) {
47 | String patchName = getInlinePatchNameWithoutRecord(className);
48 | patchNameMap.put(patchName, className);
49 | return patchName;
50 | }
51 |
52 | public String getInlinePatchNameWithoutRecord(String className) {
53 | String patchName = Config.patchPackageName + "." + className.substring(className.lastIndexOf(".") + 1) + Constants.INLINE_PATCH_SUFFIX;
54 | return patchName;
55 | }
56 |
57 | public String getPatchNamWithoutRecord(String className) {
58 | String patchName = Config.patchPackageName + "." + className.substring(className.lastIndexOf(".") + 1) + Constants.PATCH_SUFFIX;
59 | return patchName;
60 | }
61 |
62 | public String getPatchControlName(String simpleClassName) {
63 | return Config.patchPackageName + "." + simpleClassName + Constants.PATCH_SUFFIX + Constants.PATCH_CONTROL_SUFFIX;
64 | }
65 |
66 | public String getAssistClassName(String s) {
67 | patchNameMap.put(s + Constants.ROBUST_ASSIST_SUFFIX, s + Constants.ROBUST_ASSIST_SUFFIX);
68 | return s + Constants.ROBUST_ASSIST_SUFFIX;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/java/com/meituan/robust/autopatch/PatchesControlFactory.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.autopatch;
2 |
3 | import com.meituan.robust.Constants;
4 | import com.meituan.robust.utils.JavaUtils;
5 |
6 | import javassist.CtClass;
7 | import javassist.CtMethod;
8 | import javassist.NotFoundException;
9 | import javassist.bytecode.AccessFlag;
10 |
11 | import static com.meituan.robust.autopatch.Config.classPool;
12 |
13 | /**
14 | * Created by mivanzhang on 17/2/9.
15 | *
16 | * create patch control classes,which dispatch patch methods
17 | */
18 |
19 | public class PatchesControlFactory {
20 | private static PatchesControlFactory patchesControlFactory = new PatchesControlFactory();
21 |
22 | private PatchesControlFactory() {
23 |
24 | }
25 |
26 | private CtClass createControlClass(CtClass modifiedClass) throws Exception {
27 | CtClass patchClass = classPool.get(NameManger.getInstance().getPatchName(modifiedClass.getName()));
28 | patchClass.defrost();
29 | CtClass controlClass = classPool.getAndRename(Constants.PATCH_TEMPLATE_FULL_NAME, NameManger.getInstance().getPatchControlName(modifiedClass.getSimpleName()));
30 | StringBuilder getRealParameterMethodBody = new StringBuilder();
31 | getRealParameterMethodBody.append("public Object getRealParameter(Object parameter) {");
32 | getRealParameterMethodBody.append("if(parameter instanceof " + modifiedClass.getName() + "){");
33 | getRealParameterMethodBody.
34 | append("return new " + patchClass.getName() + "(parameter);");
35 | getRealParameterMethodBody.append("}");
36 | getRealParameterMethodBody.append("return parameter;}");
37 | controlClass.addMethod(CtMethod.make(getRealParameterMethodBody.toString(), controlClass));
38 | controlClass.getDeclaredMethod("accessDispatch").insertBefore(getAccessDispatchMethodBody(patchClass, modifiedClass.getName()));
39 | controlClass.getDeclaredMethod("isSupport").insertBefore(getIsSupportMethodBody(patchClass, modifiedClass.getName()));
40 | controlClass.defrost();
41 | return controlClass;
42 | }
43 |
44 | private
45 | static String getAccessDispatchMethodBody(CtClass patchClass, String modifiedClassName) throws NotFoundException {
46 | StringBuilder accessDispatchMethodBody = new StringBuilder();
47 | if(Config.catchReflectException){
48 | accessDispatchMethodBody.append("try{");
49 | }
50 | if (Constants.isLogging) {
51 | accessDispatchMethodBody.append(" android.util.Log.d(\"robust\",\"arrivied in AccessDispatch \"+methodName+\" paramArrayOfObject \" +paramArrayOfObject);");
52 | }
53 | //create patch instance
54 | accessDispatchMethodBody.append(patchClass.getName() + " patch= null;\n");
55 | accessDispatchMethodBody.append(" String isStatic=$1.split(\":\")[2];");
56 | accessDispatchMethodBody.append(" if (isStatic.equals(\"false\")) {\n");
57 | accessDispatchMethodBody.append(" if (keyToValueRelation.get(paramArrayOfObject[paramArrayOfObject.length - 1]) == null) {\n");
58 | if (Constants.isLogging) {
59 | accessDispatchMethodBody.append(" android.util.Log.d(\"robust\",\"keyToValueRelation not contain\" );");
60 | }
61 | accessDispatchMethodBody.append("patch=new " + patchClass.getName() + "(paramArrayOfObject[paramArrayOfObject.length - 1]);\n");
62 | accessDispatchMethodBody.append(" keyToValueRelation.put(paramArrayOfObject[paramArrayOfObject.length - 1], null);\n");
63 | accessDispatchMethodBody.append("}else{");
64 | accessDispatchMethodBody.append("patch=(" + patchClass.getName() + ") keyToValueRelation.get(paramArrayOfObject[paramArrayOfObject.length - 1]);\n");
65 | accessDispatchMethodBody.append("}");
66 | accessDispatchMethodBody.append("}\n");
67 | accessDispatchMethodBody.append("else{");
68 | if (Constants.isLogging) {
69 | accessDispatchMethodBody.append(" android.util.Log.d(\"robust\",\"static method forward \" );");
70 | }
71 | accessDispatchMethodBody.append("patch=new " + patchClass.getName() + "(null);\n");
72 | accessDispatchMethodBody.append("}");
73 | accessDispatchMethodBody.append("String methodNo=$1.split(\":\")[3];\n");
74 | if (Constants.isLogging) {
75 | accessDispatchMethodBody.append(" android.util.Log.d(\"robust\",\"assemble method number is \" + methodNo);");
76 | }
77 |
78 | // patchClass.declaredMethods.each {
79 | for (CtMethod method : patchClass.getDeclaredMethods()) {
80 | CtClass[] parametertypes = method.getParameterTypes();
81 | String methodSignure = JavaUtils.getJavaMethodSignure(method).replaceAll(patchClass.getName(), modifiedClassName);
82 | String methodLongName = modifiedClassName + "." + methodSignure;
83 | Integer methodNumber = Config.methodMap.get(methodLongName);
84 | //just Forward methods with methodNumber
85 | if (methodNumber != null) {
86 | accessDispatchMethodBody.append(" if((\"" + methodNumber + "\").equals(methodNo)){\n");
87 | if (Constants.isLogging) {
88 | accessDispatchMethodBody.append(" android.util.Log.d(\"robust\",\"invoke method is " + method.getLongName() + " \" );");
89 | }
90 | String methodName = method.getName();
91 | if (AccessFlag.isPrivate(method.getModifiers())) {
92 | methodName = Constants.ROBUST_PUBLIC_SUFFIX + method.getName();
93 | }
94 | if (method.getReturnType().getName().equals("void")) {
95 | accessDispatchMethodBody.append("(patch." + methodName + "(");
96 | } else {
97 | switch (method.getReturnType().getName()) {
98 | case "boolean":
99 | accessDispatchMethodBody.append("return Boolean.valueOf(patch." + methodName + "(");
100 | break;
101 | case "byte":
102 | accessDispatchMethodBody.append("return Byte.valueOf(patch." + methodName + "(");
103 | break;
104 | case "char":
105 | accessDispatchMethodBody.append("return Character.valueOf(patch." + methodName + "(");
106 | break;
107 | case "double":
108 | accessDispatchMethodBody.append("return Double.valueOf(patch." + methodName + "(");
109 | break;
110 | case "float":
111 | accessDispatchMethodBody.append("return Float.valueOf(patch." + methodName + "(");
112 | break;
113 | case "int":
114 | accessDispatchMethodBody.append("return Integer.valueOf(patch." + methodName + "(");
115 | break;
116 | case "long":
117 | accessDispatchMethodBody.append("return Long.valueOf(patch." + methodName + "(");
118 | break;
119 | case "short":
120 | accessDispatchMethodBody.append("return Short.valueOf(patch." + methodName + "(");
121 | break;
122 | default:
123 | accessDispatchMethodBody.append("return (patch." + methodName + "(");
124 | break;
125 | }
126 | }
127 | for (int index = 0; index < parametertypes.length; index++) {
128 | if (booleanPrimeType(parametertypes[index].getName())){
129 | accessDispatchMethodBody.append("((" + JavaUtils.getWrapperClass(parametertypes[index].getName()) + ") (fixObj(paramArrayOfObject[" + index + "]))");
130 | accessDispatchMethodBody.append(")" + JavaUtils.wrapperToPrime(parametertypes[index].getName()));
131 | if (index != parametertypes.length - 1) {
132 | accessDispatchMethodBody.append(",");
133 | }
134 | } else {
135 | accessDispatchMethodBody.append("((" + JavaUtils.getWrapperClass(parametertypes[index].getName()) + ") (paramArrayOfObject[" + index + "])");
136 | accessDispatchMethodBody.append(")" + JavaUtils.wrapperToPrime(parametertypes[index].getName()));
137 | if (index != parametertypes.length - 1) {
138 | accessDispatchMethodBody.append(",");
139 | }
140 | }
141 | }
142 | accessDispatchMethodBody.append("));}\n");
143 | }
144 | }
145 | if(Config.catchReflectException){
146 | accessDispatchMethodBody.append(" } catch (Throwable e) {");
147 | accessDispatchMethodBody.append(" e.printStackTrace();}");
148 | }
149 | return accessDispatchMethodBody.toString();
150 | }
151 |
152 | private static String getIsSupportMethodBody(CtClass patchClass, String modifiedClassName) throws NotFoundException {
153 | StringBuilder isSupportBuilder = new StringBuilder();
154 | StringBuilder methodsIdBuilder = new StringBuilder();
155 | if (Constants.isLogging) {
156 | isSupportBuilder.append(" android.util.Log.d(\"robust\",\"arrivied in isSupport \"+methodName+\" paramArrayOfObject \" +paramArrayOfObject);");
157 | }
158 | isSupportBuilder.append("String methodNo=$1.split(\":\")[3];\n");
159 | if (Constants.isLogging) {
160 | isSupportBuilder.append(" android.util.Log.d(\"robust\",\"in isSupport assemble method number is \" + methodNo);");
161 | }
162 | for (CtMethod method : patchClass.getDeclaredMethods()) {
163 | String methodSignure = JavaUtils.getJavaMethodSignure(method).replaceAll(patchClass.getName(), modifiedClassName);
164 | String methodLongName = modifiedClassName + "." + methodSignure;
165 | Integer methodNumber = Config.methodMap.get(methodLongName);
166 | //just Forward methods with methodNumber
167 | if (methodNumber != null) {
168 | // 一前一后的冒号作为匹配锚点,只有一边有的话可能会有多重匹配的bug
169 | methodsIdBuilder.append(":" + methodNumber + ":");
170 | }
171 | }
172 |
173 | if (Constants.isLogging) {
174 | isSupportBuilder.append(" android.util.Log.d(\"robust\",\"arrivied in isSupport \"+methodName+\" paramArrayOfObject \" +paramArrayOfObject+\" isSupport result is \"+\"" + methodsIdBuilder.toString() + "\".contains(\":\" + methodNo + \":\"));");
175 | }
176 | isSupportBuilder.append("return \"" + methodsIdBuilder.toString() + "\".contains(\":\" + methodNo + \":\");");
177 | return isSupportBuilder.toString();
178 | }
179 |
180 |
181 | public static CtClass createPatchesControl(CtClass modifiedClass) throws Exception {
182 | return patchesControlFactory.createControlClass(modifiedClass);
183 | }
184 |
185 | public static boolean booleanPrimeType(String typeName) {
186 | return "boolean".equals(typeName);
187 | }
188 |
189 | }
190 |
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/java/com/meituan/robust/autopatch/PatchesInfoFactory.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.autopatch;
2 |
3 | import com.meituan.robust.Constants;
4 |
5 | import javassist.CtClass;
6 | import javassist.CtMethod;
7 | import javassist.bytecode.ClassFile;
8 |
9 | import static com.meituan.robust.autopatch.Config.classPool;
10 | import static javassist.CtNewMethod.make;
11 |
12 | /**
13 | * Created by mivanzhang on 17/2/9.
14 | *
15 | * create patch info classes which describes patch dex
16 | */
17 |
18 | public class PatchesInfoFactory {
19 | private static PatchesInfoFactory patchesInfoFactory = new PatchesInfoFactory();
20 |
21 | private PatchesInfoFactory() {
22 |
23 | }
24 |
25 | private CtClass createPatchesInfoClass() {
26 | try {
27 | CtClass ctPatchesInfoImpl = classPool.makeClass(Config.patchPackageName + ".PatchesInfoImpl");
28 | ctPatchesInfoImpl.getClassFile().setMajorVersion(ClassFile.JAVA_7);
29 | ctPatchesInfoImpl.setInterfaces(new CtClass[]{classPool.get("com.meituan.robust.PatchesInfo")});
30 | StringBuilder methodBody = new StringBuilder();
31 | methodBody.append("public java.util.List getPatchedClassesInfo() {");
32 | methodBody.append(" java.util.List patchedClassesInfos = new java.util.ArrayList();");
33 | for (int i = 0; i < Config.modifiedClassNameList.size(); i++) {
34 | if (Constants.OBSCURE) {
35 | methodBody.append("com.meituan.robust.PatchedClassInfo patchedClass" + i + " = new com.meituan.robust.PatchedClassInfo(\"" + ReadMapping.getInstance().getClassMappingOrDefault(Config.modifiedClassNameList.get(i)).getValueName() + "\",\"" + NameManger.getInstance().getPatchControlName(Config.modifiedClassNameList.get(i).substring(Config.modifiedClassNameList.get(i).lastIndexOf('.') + 1)) + "\");");
36 | } else {
37 | methodBody.append("com.meituan.robust.PatchedClassInfo patchedClass" + i + " = new com.meituan.robust.PatchedClassInfo(\"" + Config.modifiedClassNameList.get(i) + "\",\"" + NameManger.getInstance().getPatchControlName(Config.modifiedClassNameList.get(i).substring(Config.modifiedClassNameList.get(i).lastIndexOf('.') + 1)) + "\");");
38 | }
39 | methodBody.append("patchedClassesInfos.add(patchedClass" + i + ");");
40 | }
41 | methodBody.append(Constants.ROBUST_UTILS_FULL_NAME + ".isThrowable=!" + Config.catchReflectException + ";");
42 | methodBody.append("return patchedClassesInfos;\n" +
43 | " }");
44 | CtMethod m = make(methodBody.toString(), ctPatchesInfoImpl);
45 | ctPatchesInfoImpl.addMethod(m);
46 | return ctPatchesInfoImpl;
47 | } catch (Exception e) {
48 | e.printStackTrace();
49 | throw new RuntimeException(e);
50 | }
51 | }
52 |
53 | public static CtClass createPatchesInfo() {
54 | return patchesInfoFactory.createPatchesInfoClass();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/java/com/meituan/robust/autopatch/ReadMapping.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.autopatch;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.FileInputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.io.InputStreamReader;
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | /**
12 | * Created by mivanzhang on 17/1/19.
13 | *
14 | * Reading mapping from mapping.txt,which is generated by ProGuard
15 | */
16 |
17 | public class ReadMapping {
18 | private static ReadMapping instance;
19 |
20 | private Map usedInModifiedClassMappingInfo = new HashMap();
21 |
22 | public static ReadMapping getInstance() {
23 | if (instance == null) {
24 | instance = new ReadMapping();
25 | }
26 | return instance;
27 | }
28 |
29 | public static void init() {
30 | instance = new ReadMapping();
31 | }
32 |
33 | private ReadMapping() {
34 |
35 | }
36 |
37 | /***
38 | * read all class mapping info
39 | *
40 | * @return
41 | */
42 | public void initMappingInfo() {
43 | //查找mapping文件
44 | InputStream is = null;
45 | boolean needBacktrace = true;
46 | String line;
47 | try {
48 | is = new FileInputStream(Config.mappingFilePath);
49 | BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"), 1024);
50 | // 读取一行,存储于字符串列表中
51 | line = reader.readLine().trim();
52 | while (line != null) {
53 | line = line.trim();
54 | if (!needBacktrace) {
55 | line = reader.readLine();
56 | if (line == null) {
57 | break;
58 | }
59 | line = line.trim();
60 | }
61 | needBacktrace = false;
62 | if (line.indexOf("->") > 0 && line.indexOf(":") == line.length() - 1) {
63 | ClassMapping classMapping = new ClassMapping();
64 | classMapping.setClassName(line.substring(0, line.indexOf("->") - 1).trim());
65 | classMapping.setValueName(line.split("->")[1].substring(0, line.split("->")[1].length() - 1).trim());
66 | line = reader.readLine();
67 | while (line != null) {
68 | line = line.trim();
69 | if (line.endsWith(":")) {
70 | needBacktrace = true;
71 | break;
72 | }
73 | String[] lineinfo = line.split(" ");
74 | if (lineinfo.length != 4) {
75 | throw new RuntimeException("mapping line info is error " + line);
76 | }
77 | if (lineinfo[1].contains("(") && lineinfo[1].contains(")")) {
78 | //methods need return type
79 | classMapping.getMemberMapping().put(getMethodSigureWithReturnTypeInMapping(lineinfo[0].trim(), lineinfo[1].trim()), lineinfo[3].trim());
80 | } else {
81 | //fields
82 | classMapping.getMemberMapping().put(lineinfo[1].trim(), lineinfo[3].trim());
83 | }
84 | line = reader.readLine();
85 | if (line == null) {
86 | break;
87 | }
88 | line = line.trim();
89 | }
90 | usedInModifiedClassMappingInfo.put(classMapping.getClassName(), classMapping);
91 | }
92 | }
93 | } catch (IOException ioe) {
94 | ioe.printStackTrace();
95 | } finally {
96 | try {
97 | if (is != null) {
98 | is.close();
99 | }
100 | } catch (IOException e) {
101 | e.printStackTrace();
102 | }
103 | }
104 | }
105 |
106 | public ClassMapping getClassMapping(String classname) {
107 | return usedInModifiedClassMappingInfo.get(classname);
108 | }
109 |
110 | public void setClassMapping(String classname, ClassMapping classMapping) {
111 | usedInModifiedClassMappingInfo.put(classname, classMapping);
112 | }
113 |
114 | public ClassMapping getClassMappingOrDefault(String classname) {
115 | ClassMapping defaultClassMapping = new ClassMapping();
116 | if (!Config.supportProGuard) {
117 | defaultClassMapping.setValueName(classname);
118 | }
119 | return usedInModifiedClassMappingInfo.getOrDefault(classname, defaultClassMapping);
120 | }
121 |
122 | /***
123 | * @param returnTypeWithNumber
124 | * @param methodSignure
125 | * @return returnType+" "+methodSignure,just one blank
126 | */
127 |
128 | public String getMethodSigureWithReturnTypeInMapping(String returnTypeWithNumber, String methodSignure) {
129 | //初步观察mapping文件,使用":"来截取返回值,还可以通过寻找第一个字符,
130 | if (methodSignure.contains(":")) {
131 | //兼容R8
132 | return getMethodSignureWithReturnType(returnTypeWithNumber.substring(returnTypeWithNumber.lastIndexOf(":") + 1), methodSignure.substring(0, methodSignure.indexOf(":")));
133 | }
134 | return getMethodSignureWithReturnType(returnTypeWithNumber.substring(returnTypeWithNumber.lastIndexOf(":") + 1), methodSignure);
135 | }
136 |
137 | public String getMethodSignureWithReturnType(String returnType, String methodSignure) {
138 | //只有一个空格
139 | return returnType + " " + methodSignure;
140 | }
141 | }
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/resources/META-INF/gradle-plugins/auto-patch-plugin.properties:
--------------------------------------------------------------------------------
1 | implementation-class=robust.gradle.plugin.AutoPatchTransform
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/resources/libs/baksmali-2.1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Meituan-Dianping/Robust/955adcc21e4fbcb52054a8f7f4bbb11f462aeb2f/auto-patch-plugin/src/main/resources/libs/baksmali-2.1.2.jar
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/resources/libs/dx.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Meituan-Dianping/Robust/955adcc21e4fbcb52054a8f7f4bbb11f462aeb2f/auto-patch-plugin/src/main/resources/libs/dx.jar
--------------------------------------------------------------------------------
/auto-patch-plugin/src/main/resources/libs/smali-2.1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Meituan-Dianping/Robust/955adcc21e4fbcb52054a8f7f4bbb11f462aeb2f/auto-patch-plugin/src/main/resources/libs/smali-2.1.2.jar
--------------------------------------------------------------------------------
/autopatchbase/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply from: '../gradle_mvn_push.gradle'
3 | sourceCompatibility= 1.7
4 | targetCompatibility= 1.7
5 |
--------------------------------------------------------------------------------
/autopatchbase/src/main/java/com/meituan/robust/ChangeQuickRedirect.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust;
2 |
3 | /**
4 | * Created by c_kunwu on 16/5/10.
5 | */
6 | public interface ChangeQuickRedirect {
7 | Object accessDispatch(String methodName, Object[] paramArrayOfObject);
8 |
9 | boolean isSupport(String methodName, Object[] paramArrayOfObject);
10 | }
11 |
--------------------------------------------------------------------------------
/autopatchbase/src/main/java/com/meituan/robust/Constants.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust;
2 |
3 | import java.util.Arrays;
4 | import java.util.HashSet;
5 | import java.util.List;
6 | import java.util.Set;
7 |
8 | /**
9 | * Created by mivanzhang on 16/11/3.
10 | */
11 |
12 | public class Constants {
13 |
14 | public static final String ORIGINCLASS = "originClass";
15 | public static final String MODIFY_ANNOTATION = "com.meituan.robust.patch.annotaion.Modify";
16 | // public static final String MODIFY_ANNOTATION = Modify.class.getCanonicalName();
17 | public static final String ADD_ANNOTATION = "com.meituan.robust.patch.annotaion.Add";
18 | // public static final String ADD_ANNOTATION = Add.class.getCanonicalName();
19 | public static final String LAMBDA_MODIFY = "com.meituan.robust.patch.RobustModify";
20 | // public static final String LAMBDA_MODIFY = RobustModify.class.getCanonicalName();
21 |
22 | public static final String PATCH_TEMPLATE_FULL_NAME = "com.meituan.robust.utils.PatchTemplate";
23 |
24 |
25 | public static final String ZIP_FILE_NAME = "meituan.jar";
26 | public static final String PATACH_DEX_NAME = "patch.dex";
27 | public static final String CLASSES_DEX_NAME = "classes.dex";
28 | public static final String PATACH_JAR_NAME = "patch.jar";
29 | public static final String PATCH_SUFFIX = "Patch";
30 | public static final String PATCH_CONTROL_SUFFIX = "Control";
31 | public static final String INLINE_PATCH_SUFFIX = "InLinePatch";
32 | public static final String STATICFLAG = "staticRobust";
33 | public static final String ROBUST_ASSIST_SUFFIX = "RobustAssist";
34 | public static final String ROBUST_PUBLIC_SUFFIX = "RobustPublic";
35 | public static final String GET_REAL_PARAMETER = "getRealParameter";
36 | public static final String ROBUST_UTILS_FULL_NAME = "com.meituan.robust.utils.EnhancedRobustUtils";
37 |
38 | public static final String ROBUST_GENERATE_DIRECTORY = "outputs/robust";
39 |
40 | //FILE_MD5_PATH is a copy from RobustTransform.FILE_MD5_PATH ,please make sure the two is the same
41 | public static final String METHOD_MAP_PATH = "/robust/methodsMap.robust";
42 | public static final String DEFAULT_MAPPING_FILE = "/robust/mapping.txt";
43 |
44 | public static final String SMALI_INVOKE_SUPER_COMMAND = "invoke-super";
45 | public static final String SMALI_INVOKE_VIRTUAL_COMMAND = "invoke-virtual";
46 |
47 | public static Class ModifyAnnotationClass = null;
48 | public static Class AddAnnotationClass = null;
49 |
50 | public final static String[] LIB_NAME_ARRAY = {"baksmali-2.1.2.jar", "smali-2.1.2.jar", "dx.jar"};
51 | public static final String PACKNAME_END = ";";
52 | public final static String PRIMITIVE_TYPE = "ZCBSIJFDV";
53 | public final static String ARRAY_TYPE = "[";
54 | public final static char OBJECT_TYPE = 'L';
55 | public static final String PACKNAME_START = String.valueOf(OBJECT_TYPE);
56 | public static final Boolean OBSCURE = true;
57 | // public static final Boolean OBSCURE = false;
58 | // public static final Boolean isLogging = false;
59 | public static boolean isLogging = true;
60 |
61 | public static final String PATCH_PACKAGENAME = "com.meituan.robust.patch";
62 | public static final Set RFileClassSet = new HashSet();
63 | public final static String ROBUST_XML = "robust.xml";
64 |
65 | static {
66 | RFileClassSet.add("R$array");
67 | RFileClassSet.add("R$xml");
68 | RFileClassSet.add("R$styleable");
69 | RFileClassSet.add("R$style");
70 | RFileClassSet.add("R$string");
71 | RFileClassSet.add("R$raw");
72 | RFileClassSet.add("R$menu");
73 | RFileClassSet.add("R$layout");
74 | RFileClassSet.add("R$integer");
75 | RFileClassSet.add("R$id");
76 | RFileClassSet.add("R$drawable");
77 | RFileClassSet.add("R$dimen");
78 | RFileClassSet.add("R$color");
79 | RFileClassSet.add("R$bool");
80 | RFileClassSet.add("R$attr");
81 | RFileClassSet.add("R$anim");
82 | }
83 |
84 | //=========================RobustTransForm========================
85 | //=========================RobustTransForm========================
86 | public static final String CONSTRUCTOR = "Constructor";
87 | public static final String LANG_VOID = "java.lang.Void";
88 | public static final String VOID = "void";
89 | public static final String LANG_BOOLEAN = "java.lang.Boolean";
90 | public static final String BOOLEAN = "boolean";
91 | public static final String LANG_INT = "java.lang.Integer";
92 | public static final String INT = "int";
93 | public static final String LANG_LONG = "java.lang.Long";
94 | public static final String LONG = "long";
95 | public static final String LANG_DOUBLE = "java.lang.Double";
96 | public static final String DOUBLE = "double";
97 | public static final String LANG_FLOAT = "java.lang.Float";
98 | public static final String FLOAT = "float";
99 | public static final String LANG_SHORT = "java.lang.Short";
100 | public static final String SHORT = "short";
101 | public static final String LANG_BYTE = "java.lang.Byte";
102 | public static final String BYTE = "byte";
103 | public static final String LANG_CHARACTER = "Character";
104 | public static final String CHAR = "char";
105 |
106 | public static final String METHOD_MAP_OUT_PATH = "/outputs/robust/methodsMap.robust";
107 | public static final String INTERFACE_NAME = "com.meituan.robust.ChangeQuickRedirect";
108 | public static final String INSERT_FIELD_NAME = "changeQuickRedirect";
109 | public static final List NO_NEED_REFLECT_CLASS = Arrays.asList("android.os.Bundle","android.os.BaseBundle");
110 |
111 | //robust apk hash : apk's unique id
112 | public static final String ROBUST_APK_HASH_FILE_NAME = "robust.apkhash";
113 | public static final String ASPECTJ_AROUND_CLASS = "org.aspectj.runtime.internal.AroundClosure";
114 | public static final String PATCH_EXECUTE = "patch execute ,other extension will be ignore ";
115 |
116 |
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/autopatchbase/src/main/java/com/meituan/robust/RobustArguments.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust;
2 |
3 | /**
4 | * Created by zhangmeng on 2017/5/9.
5 | */
6 |
7 | public class RobustArguments {
8 | public Object[] paramsArray;
9 | public Object current;
10 | public boolean isStatic;
11 | public int methodNumber;
12 | public Class[] paramsClassTypes;
13 | public Class returnType;
14 |
15 | public RobustArguments(Object[] paramsArray, Object current, boolean isStatic, int methodNumber, Class[] paramsClassTypes, Class returnType) {
16 | this.paramsArray = paramsArray;
17 | this.current = current;
18 | this.isStatic = isStatic;
19 | this.methodNumber = methodNumber;
20 | this.paramsClassTypes = paramsClassTypes;
21 | this.returnType = returnType;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/autopatchbase/src/main/java/com/meituan/robust/RobustExtension.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust;
2 |
3 | /**
4 | * Created by zhangmeng on 2017/4/21.
5 | */
6 |
7 | public interface RobustExtension {
8 | /**
9 | *
10 | * @return 关于接入方信息的描述,请保证各个业务方独立不同,且唯一不变。
11 | * 建议使用各个业务方包名+一些功能性描述,比如:com.meituan.robust android热更新系统
12 | */
13 | String describeSelfFunction();
14 |
15 | /**
16 | * 通知监听者信息,通知哪个监听者被执行了
17 | * @param msg,msg是describeSelfFunction中的返回内容
18 | */
19 | void notifyListner(String msg);
20 | /**
21 | * @param paramsArray 原方法的参数列表
22 | * @param current 当前对象的引用,即this对象,如果是static方法,值为null
23 | * @param methodNumber 方法的唯一编号
24 | * @param paramsTypeArray 方法参数类型列表
25 | * @param returnType 方法的返回值类型
26 | * 在方法的方法体最先执行的代码逻辑,请注意这个方法执行之后,原方法体中的其他逻辑不在执行
27 | * @return
28 | *
29 | */
30 | Object accessDispatch(RobustArguments robustArguments);
31 |
32 | /**
33 | *@param paramsArray 原方法的参数列表
34 | * @param current 当前对象的引用,即this对象,如果是static方法,值为null
35 | * @param methodNumber 方法的唯一编号
36 | * @param paramsTypeArray 方法参数类型列表
37 | * @param returnType 方法的返回值类型
38 | *
39 | * @return return true 代表不继续执行原有方法体,只执行accessDispatch方法的逻辑,并把accessDispatch的方法返回值作为原函数的返回值
40 | * return false 代表执行原有方法体,但是可以在isSupport方法里面添加额外的逻辑,比如说记录当前的方法调用栈或者日志等
41 | */
42 | boolean isSupport(RobustArguments robustArguments);
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/autopatchbase/src/main/java/com/meituan/robust/patch/RobustModify.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.patch;
2 |
3 | /**
4 | * Created by mivanzhang on 16/12/9.
5 | *
6 | * A backup for annotation Modify, in some situation Modify will not work, such as Generic
7 | */
8 |
9 | public final class RobustModify {
10 | public static final void modify() {
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/autopatchbase/src/main/java/com/meituan/robust/patch/annotaion/Add.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.patch.annotaion;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Created by mivanzhang on 16/12/19.
11 | * 用来标记新增的类和方法
12 | * annotaion used for add classes or methods,classes and methods will be packed into patch.jar/patch.apk
13 | */
14 |
15 | @Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
16 | @Retention(RetentionPolicy.CLASS)
17 | @Documented
18 | public @interface Add {
19 | String value() default "";
20 | }
--------------------------------------------------------------------------------
/autopatchbase/src/main/java/com/meituan/robust/patch/annotaion/Modify.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.patch.annotaion;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Created by mivanzhang on 16/12/9.
11 | * annotaion used for modify classes or methods,classes and methods will be packed into patch.jar/patch.apk
12 | */
13 | @Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
14 | @Retention(RetentionPolicy.CLASS)
15 | @Documented
16 | public @interface Modify {
17 | String value() default "";
18 | }
19 |
--------------------------------------------------------------------------------
/autopatchbase/src/main/java/com/meituan/robust/utils/PatchTemplate.java:
--------------------------------------------------------------------------------
1 | package com.meituan.robust.utils;
2 |
3 |
4 | import com.meituan.robust.ChangeQuickRedirect;
5 |
6 | import java.util.Map;
7 | import java.util.WeakHashMap;
8 |
9 | /**
10 | * Created by mivanzhang on 16/7/26.
11 | */
12 | public class PatchTemplate implements ChangeQuickRedirect {
13 | public static final String MATCH_ALL_PARAMETER = "(\\w*\\.)*\\w*";
14 |
15 | public PatchTemplate() {
16 | }
17 |
18 | private static final Map