Skip to content
This repository was archived by the owner on Dec 1, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ build/

#Gradle
.gradle/

# Android
local.properties

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Supported options are:
* `--package-filter=...`: Only consider methods whose fully qualified name starts with this prefix.
* `--max-depth=...`: Limit how far into package paths (or inner classes, with `--include-classes`) counts should be reported for.
* `--filter=[all|defined_only|referenced_only]`: Whether to count all methods (the default), just those defined in the input file, or just those that are referenced in it. Note that referenced methods count against the 64K method limit too.
* `--compare`: Prints a comparison counts between the second and first APK. Note that the comparison will not be accurate if either of the APKs has been obfuscated using ProGuard.
* `--output-style=[flat|tree]`: Print the output as a list or as an indented tree.

The DEX file parsing is based on the `dexdeps` tool from
Expand Down
74 changes: 69 additions & 5 deletions src/info/persistent/dex/DexCount.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
import com.android.dexdeps.DexData;

import java.io.PrintStream;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;

public abstract class DexCount {

Expand Down Expand Up @@ -56,33 +56,77 @@ enum OutputStyle {
void output(DexCount counts) {
counts.packageTree.output("");
}

@Override
void output(DexCount counts, DexCount comparedTo) {
counts.packageTree.output("", comparedTo.packageTree);
}
},
FLAT {
@Override
void output(DexCount counts) {
for (Map.Entry<String, IntHolder> e : counts.packageCount.entrySet()) {
String packageName = e.getKey();
if (packageName == "") {
if (packageName.equals("")) {
packageName = "<no package>";
}
System.out.printf("%6s %s\n", e.getValue().value, packageName);
}
}

@Override
void output(DexCount counts, DexCount comparedTo) {
for (Map.Entry<String, IntHolder> e : counts.packageCount.entrySet()) {
String packageName = e.getKey();
final IntHolder comparedToValue;

if (packageName.equals("")) {
packageName = "<no package>";
comparedToValue = null;
} else {
comparedToValue = comparedTo.packageCount.get(packageName);
}

final int diff = (comparedToValue == null)
? e.getValue().value
: e.getValue().value - comparedToValue.value;
System.out.printf(
"%6d (%+6d) %s\n",
e.getValue().value,
diff,
packageName);
}

final Set<String> removed = new LinkedHashSet<>(comparedTo.packageCount.keySet());
removed.removeAll(counts.packageCount.keySet());
removed.forEach(packageName -> System.out.printf(
"%6d (%+6d) %s\n",
0,
-comparedTo.packageCount.get(packageName).value,
packageName));
}
};

abstract void output(DexCount counts);
abstract void output(DexCount counts, DexCount comparedTo);
}

void output() {
outputStyle.output(this);
}

void output(DexCount comparedTo) {
outputStyle.output(this, comparedTo);
}

int getOverallCount() {
return overallCount;
}

static class Node {

private static final NumberFormat FORMAT = new DecimalFormat("+#;-#");

int count = 0;
NavigableMap<String, Node> children = new TreeMap<String, Node>();

Expand All @@ -97,6 +141,26 @@ void output(String indent) {
child.output(indent);
}
}
}

void output(String indent, Node comparedTo) {
if (indent.length() == 0) {
out.println("<root>: " + count);
}
indent += " ";

for (String name : children.navigableKeySet()) {
Node child = children.get(name);

final Node comparedToChild = (comparedTo == null)
? null
:comparedTo.children.get(name);
final int diff = (comparedToChild == null)
? child.count
: child.count - comparedToChild.count;

out.println(indent + name + ": " + child.count + " (" + FORMAT.format(diff) + ")");
child.output(indent, comparedToChild);
}
}
}
}
20 changes: 16 additions & 4 deletions src/info/persistent/dex/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class Main {
private String packageFilter;
private int maxDepth = Integer.MAX_VALUE;
private DexMethodCounts.Filter filter = DexMethodCounts.Filter.ALL;
private boolean compare;
private DexMethodCounts.OutputStyle outputStyle = DexMethodCounts.OutputStyle.TREE;

public static void main(String[] args) {
Expand All @@ -44,9 +45,10 @@ public static void main(String[] args) {

void run(String[] args) {
try {
String[] inputFileNames = parseArgs(args);
int overallCount = 0;
for (String fileName : collectFileNames(inputFileNames)) {
DexCount previousCount = null;

for (String fileName : collectFileNames(parseArgs(args))) {
System.out.println("Processing " + fileName);
DexCount counts;
if (countFields) {
Expand All @@ -62,8 +64,15 @@ void run(String[] args) {
counts.generate(dexData, includeClasses, packageFilter, maxDepth, filter);
dexFile.close();
}
counts.output();
overallCount = counts.getOverallCount();

if (compare && previousCount != null) {
counts.output(previousCount);
} else if (!compare) {
counts.output();
}

overallCount =+ counts.getOverallCount();
previousCount = counts;
}
System.out.println(String.format("Overall %s count: %d", countFields ? "field" : "method", overallCount));
} catch (UsageException ue) {
Expand Down Expand Up @@ -178,6 +187,8 @@ private String[] parseArgs(String[] args) {
filter = Enum.valueOf(
DexMethodCounts.Filter.class,
arg.substring(arg.indexOf('=') + 1).toUpperCase());
} else if (arg.equals("--compare")) {
compare = true;
} else if (arg.startsWith("--output-style")) {
outputStyle = Enum.valueOf(
DexMethodCounts.OutputStyle.class,
Expand Down Expand Up @@ -208,6 +219,7 @@ private void usage() {
" --package-filter=com.foo.bar\n" +
" --max-depth=N\n" +
" --filter=ALL|DEFINED_ONLY|REFERENCED_ONLY\n" +
" --compare\n" +
" --output-style=FLAT|TREE\n"
);
}
Expand Down