-
Notifications
You must be signed in to change notification settings - Fork 5
/
DexinfoTask.groovy
165 lines (131 loc) · 5.3 KB
/
DexinfoTask.groovy
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package com.mutualmobile.gradle.plugins.dexinfo
import com.android.dexdeps.DexData
import com.android.dexdeps.DexDataException
import info.persistent.dex.DexMethodCounts
import org.gradle.api.DefaultTask
import org.gradle.api.GradleScriptException
import org.gradle.api.tasks.TaskAction
import java.util.zip.ZipEntry
import java.util.zip.ZipException
import java.util.zip.ZipFile
class DexinfoTask extends DefaultTask {
/** Global instance of Dexinfo Extension */
//DexinfoPluginExtension dexinfo
def variant
DexinfoPluginExtension dexinfo
DexinfoTask() {
super()
this.description = 'Display information about the generated DEX file'
this.dexinfo = project.dexinfo
}
@TaskAction
void printDexInfo() {
boolean first = true;
String mOutputFormat = "brief" // "xml"
boolean mJustClasses = false
DexMethodCounts.Filter filter = DexMethodCounts.Filter.valueOf(this.dexinfo.filter)
variant.outputs.each { output ->
String fileName = output.outputFile.path;
println("Processing " + fileName)
DexMethodCounts.overallCount = 0;
try {
List<RandomAccessFile> dexFiles = openInputFiles(fileName);
DexMethodCounts.Node packageTree = new DexMethodCounts.Node();
for (RandomAccessFile dexFile : dexFiles) {
DexData dexData = new DexData(dexFile);
dexData.load();
DexMethodCounts.generate(
packageTree, dexData, dexinfo.includeClasses, dexinfo.packageFilter, dexinfo.maxDepth, filter);
/*
if (first) {
first = false;
Output.generateFirstHeader(fileName, mOutputFormat);
} else {
Output.generateHeader(fileName, mOutputFormat);
}
Output.generate(dexData, mOutputFormat, mJustClasses);
Output.generateFooter(mOutputFormat);
*/
dexFile.close();
}
packageTree.output("");
} catch (IOException ioe) {
throw new GradleScriptException(dde);
} catch (DexDataException dde) {
/* a message was already reported, just bail quietly */
throw new GradleScriptException(dde);
}
println("")
if (DexMethodCounts.overallCount >= (1024 * 64)) {
println("*" * 80);
println("Overall method count: " + DexMethodCounts.overallCount);
println("*" * 80);
} else {
println("Overall method count: " + DexMethodCounts.overallCount);
}
}
}
/**
* Opens an input file, which could be a .dex or a .jar/.apk with a
* classes.dex inside. If the latter, we extract the contents to a
* temporary file.
*/
List<RandomAccessFile> openInputFiles(String fileName) throws IOException {
List<RandomAccessFile> dexFiles = new ArrayList<RandomAccessFile>();
openInputFileAsZip(fileName, dexFiles);
if (dexFiles.size() == 0) {
File inputFile = new File(fileName);
RandomAccessFile dexFile = new RandomAccessFile(inputFile, "r");
dexFiles.add(dexFile);
}
return dexFiles;
}
/**
* Tries to open an input file as a Zip archive (jar/apk) with a
* "classes.dex" inside.
*/
void openInputFileAsZip(String fileName, List<RandomAccessFile> dexFiles) throws IOException {
ZipFile zipFile;
// Try it as a zip file.
try {
zipFile = new ZipFile(fileName);
} catch (FileNotFoundException fnfe) {
// not found, no point in retrying as non-zip.
System.err.println("Unable to open '" + fileName + "': " +
fnfe.getMessage());
throw fnfe;
} catch (ZipException ze) {
// not a zip
return;
}
// Open and add all files matching "classes.*\.dex" in the zip file.
for (ZipEntry entry : Collections.list(zipFile.entries())) {
if (entry.getName().matches("classes.*\\.dex")) {
dexFiles.add(openDexFile(zipFile, entry));
}
}
zipFile.close();
}
RandomAccessFile openDexFile(ZipFile zipFile, ZipEntry entry) throws IOException {
// We know it's a zip; see if there's anything useful inside. A
// failure here results in some type of IOException (of which
// ZipException is a subclass).
InputStream zis = zipFile.getInputStream(entry);
// Create a temp file to hold the DEX data, open it, and delete it
// to ensure it doesn't hang around if we fail.
File tempFile = File.createTempFile("dexdeps", ".dex");
RandomAccessFile dexFile = new RandomAccessFile(tempFile, "rw");
tempFile.delete();
// Copy all data from input stream to output file.
byte[] copyBuf = new byte[32768];
int actual;
while (true) {
actual = zis.read(copyBuf);
if (actual == -1)
break;
dexFile.write(copyBuf, 0, actual);
}
dexFile.seek(0);
return dexFile;
}
}