0%

构建编译MPaaSAARHookerTask

分析

1.build.gradle

1
classpath 'com.android.boost.easyconfig:easyconfig:2.2.10'

2.easyconfig-2.2.10.pom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.android.boost.easyconfig</groupId>
<artifactId>easyconfig</artifactId>
<version>2.2.10</version>
<dependencies>
<dependency>
<groupId>com.android.boost.dependency</groupId>
<artifactId>gradle_plugin</artifactId>
<version>3.4.11</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

3.gradle_plugin-3.4.11.jar
image.png
image.png

4.amap_android/scm/miniapp/ariver.gradle

1
apply plugin: 'com.alipay.apollo.baseline.config'

5.portal task依赖中正好也看到了有MPaaSAARHookerTask
image.png

寻找这个task的思路?

反推法,从第五步开始,我们看到了MPaaSAARHookerTask,如果想知道这个task做了什么,我们应该从项目所有的classpath依赖中去查找,通过简单的分析’paas’,’easy’,’config’ ,再通过所有打印出的所有classpath,估计应该在com.android.boost.easyconfig:easyconfig:2.2.10这个库中,但是打开这个库之后,并没有发现有MPaaSAARHookerTask这个类,于是又在pom文件发现easyconfig依赖gradle_plugin,最终在gradle_plugin中找到了这个Task

task:https://yuque.antfin.com/xiaobao.spf/ad2gcp/rvlk3e
classpath: https://yuque.antfin.com/xiaobao.spf/ad2gcp/yizp1w

解析

DSL语法转化为class,反编译后的代码,阅读上比较费劲

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Object handleAARConfig(Project project, BaseVariant variant) {
CallSite[] $getCallSiteArray = $getCallSiteArray();
if (!BytecodeInterface8.isOrigZ() || __$stMC || BytecodeInterface8.disabledStandardMetaClass()) {
if (ScriptBytecodeAdapter.compareEqual(project, null) || ScriptBytecodeAdapter.compareEqual(variant, null)) {
return null;
}
} else {
if (ScriptBytecodeAdapter.compareEqual(project, null) || ScriptBytecodeAdapter.compareEqual(variant, null)) {
return null;
}
}
Object applicationId = $getCallSiteArray[72].callGetProperty(variant);
Object packageName = $getCallSiteArray[73].callStatic(MPaaSAARPlugin.class, variant);
File outputDir = (File) ScriptBytecodeAdapter.castToType($getCallSiteArray[74].call(project, new GStringImpl(new Object[]{$getCallSiteArray[75].callGetProperty(project), $getCallSiteArray[76].callGetProperty(variant)}, new String[]{"", "/generated/source/aar_hook/", ""})), File.class);
MPaaSAARHookerTask task = (MPaaSAARHookerTask) ScriptBytecodeAdapter.castToType($getCallSiteArray[77].call($getCallSiteArray[78].callGetProperty(project), new GStringImpl(new Object[]{$getCallSiteArray[79].call($getCallSiteArray[80].callGetProperty(variant))}, new String[]{"mpaas", "AARHookerTask"}), MPaaSAARHookerTask.class), MPaaSAARHookerTask.class);
$getCallSiteArray[81].call(task, applicationId);
$getCallSiteArray[82].call(task, packageName);
$getCallSiteArray[83].call(task, $getCallSiteArray[84].callGetProperty(outputDir));
return $getCallSiteArray[85].call(variant, task, outputDir);
}

先找到了MPaaSAARHookerTask,然后查看handleAARConfig的调用,在strArr[70]数组中发现了这个方法

1
2
3
4
5
6
7
strArr[70] = "handleAARConfig";

public Object handleVariant(Project project, Object variant) {
CallSite[] $getCallSiteArray = $getCallSiteArray();
$getCallSiteArray[70].callCurrent(this, project, variant);
return $getCallSiteArray[71].callCurrent(this, variant, project);
}

继续查找发现handleVariant中又调用了handleAARConfig,再往上查看就是Plugin的apply中了,这里忽略,进行分析MPaaSAARHookerTask,handleAARConfig方法中有很多的getCallSiteArray数组,数组索引为72-85

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
strArr[71] = "handleMpaasConfig";
strArr[72] = "applicationId";
strArr[73] = "getPackageName";
strArr[74] = "file";
strArr[75] = "buildDir";
strArr[76] = "dirName";
strArr[77] = "create";
strArr[78] = "tasks";
strArr[79] = "capitalize";
strArr[80] = "name";
strArr[81] = "setApplicationId";
strArr[82] = "setPackageName";
strArr[83] = "setOutputFilePath";
strArr[84] = "absolutePath";
strArr[85] = "registerJavaGeneratingTask";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
open fun registerJavaGeneratingTask(
task: Task,
generatedSourceFolders: Collection<File>
) {
@Suppress("DEPRECATION")
taskContainer.sourceGenTask.dependsOn(task) // 重点

val fileTrees = extraGeneratedSourceFileTrees ?: mutableListOf<ConfigurableFileTree>().also {
extraGeneratedSourceFileTrees = it
}

for (f in generatedSourceFolders) {
val fileTree = services.fileTree(f).builtBy(task)
fileTrees.add(fileTree)
}
addJavaSourceFoldersToModel(generatedSourceFolders)
}

分析registerJavaGeneratingTask,得出在generatorVariantNameSourcesTask会依赖MPaaSAARHookerTask

MPaaSAARHookerTask

1
2
3
4
5
6
7
8
@TaskAction
public void executeTask() {
try {
new HookerJavaGenerator().generate(this.outputFilePath, this.packageName);
} catch (IOException e) {
e.printStackTrace();
}
}

HookerJavaGenerator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class HookerJavaGenerator {
private static final String TAG = HookerJavaGenerator.class.getName();
private final String className = "FinalRInit";
private final String packageName = "com.mpaas.project.aar.convert.converter";

public static void main(String[] args) throws IOException {
new HookerJavaGenerator().generate("/Users/gezihua/mpaas_code/dependcychecker/java-demo/src/main/java", "com.alipay.iap.android.webapp");
}

public void generate(String outFilePath, String RJavaPackage) throws IOException {
if (StringUtils.isEmpty(outFilePath)) {
System.err.println(TAG + "generate outFilePath is null");
} else if (StringUtils.isEmpty(RJavaPackage)) {
System.err.println(TAG + "generate RJavaPackage is null");
} else {
File outFile = Paths.get(outFilePath, "com.mpaas.project.aar.convert.converter".replaceAll("\\.", "/") + "/FinalRInit.java").toFile();
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
if (!outFile.exists()) {
outFile.createNewFile();
}
System.out.println(outFile.getAbsolutePath());
new JavaWriter(new OutputStreamWriter(new FileOutputStream(outFile))).emitPackage("com.mpaas.project.aar.convert.converter").beginType("com.mpaas.project.aar.convert.converter.FinalRInit", "class", EnumSet.of(Modifier.PUBLIC, Modifier.FINAL)).emitJavadoc("com.mpaas.project.aar.convert init with your R class", new Object[0]).beginMethod("Class", "getRClass", EnumSet.of(Modifier.PUBLIC, Modifier.STATIC), new String[0]).emitStatement(String.format("return %s.R.class", RJavaPackage), new Object[0]).endMethod().endType().close();
}
}
}

通过分析,得知MPaaSAARHookerTask 主要是用于生成一个FinalRInit.java

1
2
3
4
5
6
7
8
public final class FinalRInit {
/**
* com.mpaas.project.aar.convert init with your R class
*/
public static Class getRClass() {
return com.autonavi.minimap.R.class;
}
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class FinalR {
...

public static Class invokeFinalRInit() {
try {
return (Class) Class.forName("com.mpaas.project.aar.convert.converter.FinalRInit").getMethod("getRClass", new Class[0]).invoke(null, new Object[0]);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

...
public static int invokeRInnerClassIntWithOutException(String className, String valueName) {
try {
return invokeRInnerClassInt(className, valueName);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}

...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.alibaba.ailabs.tg.sdk.test;

import com.alipay.mobile.common.share.widget.ResUtils;
import com.alipay.mobile.nebulax.resource.storage.dbbean.AromeRecentAppBean;
import com.mpaas.project.aar.convert.converter.FinalR;

public final class R {

public static final class drawable {
public static final int aomp_bg_indicator_default = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_bg_indicator_default");
public static final int aomp_bg_indicator_selected = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_bg_indicator_selected");
public static final int aomp_bg_indicator_selector = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_bg_indicator_selector");
public static final int aomp_btn_bg_cancel = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_btn_bg_cancel");
public static final int aomp_dialog_bg_auth = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_dialog_bg_auth");
public static final int aomp_ic_auth_fail = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_ic_auth_fail");
public static final int aomp_ic_auth_success = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_ic_auth_success");
}

...
}

最终发现是在子项目的 R文件 中通过反射的方式调用 portal(com.autonavi.minimap.R.class) 中 R文件

子项目中引用R文件的类,类中指定了R.class,而非使用高德中的R,所以指定的R文件中需要建立映射到高德中的R文件。