Skip to content

Commit

Permalink
don't use methods and classes removed in upstream dx
Browse files Browse the repository at this point in the history
RELNOTES: update dexing tools to Android SDK 26.0.1

PiperOrigin-RevId: 164278101
  • Loading branch information
kevin1e100 authored and buchgr committed Aug 7, 2017
1 parent 2266a6f commit ce61d63
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void testBuildDexArchive() throws Exception {
options.outputZip =
FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR"), "dex_builder_test.zip");
options.maxThreads = 1;
DexBuilder.buildDexArchive(options, new Dexing.DexingOptions());
DexBuilder.buildDexArchive(options, new Dexing(new Dexing.DexingOptions()));
assertThat(options.outputZip.toFile().exists()).isTrue();

HashSet<String> files = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.mockito.Mockito.when;

import com.android.dex.Dex;
import com.android.dx.command.dexer.DxContext;
import com.android.dx.dex.DexOptions;
import com.android.dx.dex.cf.CfOptions;
import com.google.common.cache.Cache;
Expand Down Expand Up @@ -64,7 +65,7 @@ private void makeStuffer() {
new DexConversionEnqueuer(
zip,
newDirectExecutorService(),
new DexConverter(new Dexing(new DexOptions(), new CfOptions())),
new DexConverter(new Dexing(new DxContext(), new DexOptions(), new CfOptions())),
cache);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.mockito.Mockito.verify;

import com.android.dex.Dex;
import com.android.dx.command.dexer.DxContext;
import com.android.dx.dex.DexOptions;
import com.android.dx.dex.cf.CfOptions;
import com.android.dx.dex.file.DexFile;
Expand Down Expand Up @@ -59,23 +60,24 @@ public void setUp() throws IOException {
@Test
public void testClose_emptyWritesNothing() throws Exception {
DexFileAggregator dexer =
new DexFileAggregator(dest, MultidexStrategy.MINIMAL, DEX_LIMIT, WASTE);
new DexFileAggregator(new DxContext(), dest, MultidexStrategy.MINIMAL, DEX_LIMIT, WASTE);
dexer.close();
verify(dest, times(0)).addFile(any(ZipEntry.class), any(Dex.class));
}

@Test
public void testAddAndClose_singleInputWritesThatInput() throws Exception {
DexFileAggregator dexer = new DexFileAggregator(dest, MultidexStrategy.MINIMAL, 0, WASTE);
DexFileAggregator dexer =
new DexFileAggregator(new DxContext(), dest, MultidexStrategy.MINIMAL, 0, WASTE);
dexer.add(dex);
dexer.close();
verify(dest).addFile(any(ZipEntry.class), eq(dex));
}

@Test
public void testMultidex_underLimitWritesOneShard() throws Exception {
DexFileAggregator dexer =
new DexFileAggregator(dest, MultidexStrategy.BEST_EFFORT, DEX_LIMIT, WASTE);
DexFileAggregator dexer = new DexFileAggregator(
new DxContext(), dest, MultidexStrategy.BEST_EFFORT, DEX_LIMIT, WASTE);
Dex dex2 = DexFiles.toDex(convertClass(ByteStreams.class));
dexer.add(dex);
dexer.add(dex2);
Expand All @@ -87,8 +89,8 @@ public void testMultidex_underLimitWritesOneShard() throws Exception {

@Test
public void testMultidex_overLimitWritesSecondShard() throws Exception {
DexFileAggregator dexer = new DexFileAggregator(dest, MultidexStrategy.BEST_EFFORT,
2 /* dex has more than 2 methods and fields */, WASTE);
DexFileAggregator dexer = new DexFileAggregator(new DxContext(), dest,
MultidexStrategy.BEST_EFFORT, 2 /* dex has more than 2 methods and fields */, WASTE);
Dex dex2 = DexFiles.toDex(convertClass(ByteStreams.class));
dexer.add(dex); // classFile is already over limit but we take anything in empty shard
dexer.add(dex2); // this should start a new shard
Expand All @@ -101,7 +103,7 @@ public void testMultidex_overLimitWritesSecondShard() throws Exception {

@Test
public void testMonodex_alwaysWritesSingleShard() throws Exception {
DexFileAggregator dexer = new DexFileAggregator(dest, MultidexStrategy.OFF,
DexFileAggregator dexer = new DexFileAggregator(new DxContext(), dest, MultidexStrategy.OFF,
2 /* dex has more than 2 methods and fields */, WASTE);
Dex dex2 = DexFiles.toDex(convertClass(ByteStreams.class));
dexer.add(dex);
Expand All @@ -116,7 +118,7 @@ private static DexFile convertClass(Class<?> clazz) throws IOException {
String path = clazz.getName().replace('.', '/') + ".class";
try (InputStream in =
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)) {
return new DexConverter(new Dexing(new DexOptions(), new CfOptions()))
return new DexConverter(new Dexing(new DxContext(), new DexOptions(), new CfOptions()))
.toDexFile(ByteStreams.toByteArray(in), path);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import com.android.dex.ClassDef;
import com.android.dex.Dex;
import com.android.dx.command.dexer.DxContext;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.HashMultimap;
Expand Down Expand Up @@ -259,7 +260,7 @@ private Path buildDexArchive() throws Exception {
options.outputZip =
FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR"), "libtests.dex.zip");
options.maxThreads = 1;
DexBuilder.buildDexArchive(options, new Dexing.DexingOptions());
DexBuilder.buildDexArchive(options, new Dexing(new DxContext(), new Dexing.DexingOptions()));
return options.outputZip;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.util.concurrent.Executors.newFixedThreadPool;

import com.android.dx.command.DxConsole;
import com.android.dx.command.dexer.DxContext;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
Expand Down Expand Up @@ -120,21 +120,20 @@ public static void main(String[] args) throws Exception {
if (options.persistentWorker) {
runPersistentWorker();
} else {
buildDexArchive(options, optionsParser.getOptions(DexingOptions.class));
buildDexArchive(options, new Dexing(optionsParser.getOptions(DexingOptions.class)));
}
}

@VisibleForTesting
static void buildDexArchive(Options options, DexingOptions dexingOptions)
throws Exception {
static void buildDexArchive(Options options, Dexing dexing) throws Exception {
checkArgument(options.maxThreads > 0,
"--max_threads must be strictly positive, was: %s", options.maxThreads);
try (ZipFile in = new ZipFile(options.inputJar.toFile())) {
// Heuristic: use at most 1 thread per 1000 files in the input Jar
int threads = Math.min(options.maxThreads, in.size() / 1000 + 1);
ExecutorService executor = newFixedThreadPool(threads);
try (ZipOutputStream out = createZipOutputStream(options.outputZip)) {
produceDexArchive(in, out, executor, threads <= 1, dexingOptions, null);
produceDexArchive(in, out, executor, threads <= 1, dexing, null);
} finally {
executor.shutdown();
}
Expand Down Expand Up @@ -169,11 +168,11 @@ public int weigh(DexingKey key, byte[] value) {
// Redirect dx's output so we can return it in response
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos, /*autoFlush*/ true);
DxConsole.out = DxConsole.err = ps;
DxContext context = new DxContext(ps, ps);
// Make sure that we exit nonzero in case uncaught errors occur during processRequest.
int exitCode = 1;
try {
processRequest(executor, dexCache, request.getArgumentsList());
processRequest(executor, dexCache, context, request.getArgumentsList());
exitCode = 0; // success!
} catch (Exception e) {
// Deliberate catch-all so we can capture a stack trace.
Expand Down Expand Up @@ -206,7 +205,10 @@ public int weigh(DexingKey key, byte[] value) {
}

private static void processRequest(
ExecutorService executor, Cache<DexingKey, byte[]> dexCache, List<String> args)
ExecutorService executor,
Cache<DexingKey, byte[]> dexCache,
DxContext context,
List<String> args)
throws OptionsParsingException, IOException, InterruptedException, ExecutionException {
OptionsParser optionsParser =
OptionsParser.newOptionsParser(Options.class, DexingOptions.class);
Expand All @@ -220,7 +222,7 @@ private static void processRequest(
out,
executor,
/*convertOnReaderThread*/ false,
optionsParser.getOptions(DexingOptions.class),
new Dexing(context, optionsParser.getOptions(DexingOptions.class)),
dexCache);
}
// Use input's timestamp for output file so the output file is stable.
Expand All @@ -236,7 +238,7 @@ private static void produceDexArchive(
ZipOutputStream out,
ExecutorService executor,
boolean convertOnReaderThread,
DexingOptions dexingOptions,
Dexing dexing,
@Nullable Cache<DexingKey, byte[]> dexCache)
throws InterruptedException, ExecutionException, IOException {
// If we only have one thread in executor, we give a "direct" executor to the stuffer, which
Expand All @@ -245,7 +247,7 @@ private static void produceDexArchive(
// the stuffer is still working its way through the input.
DexConversionEnqueuer enqueuer = new DexConversionEnqueuer(in,
convertOnReaderThread ? MoreExecutors.newDirectExecutorService() : executor,
new DexConverter(new Dexing(dexingOptions)),
new DexConverter(dexing),
dexCache);
Future<?> enqueuerTask = executor.submit(enqueuer);
while (true) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
import com.android.dex.DexFormat;
import com.android.dex.FieldId;
import com.android.dex.MethodId;
import com.android.dex.ProtoId;
import com.android.dex.TypeList;
import com.android.dx.command.dexer.DxContext;
import com.android.dx.merge.CollisionPolicy;
import com.android.dx.merge.DexMerger;
import com.google.auto.value.AutoValue;
Expand Down Expand Up @@ -55,14 +58,17 @@ class DexFileAggregator implements Closeable {
private final int maxNumberOfIdxPerDex;
private final int wasteThresholdPerDex;
private final MultidexStrategy multidex;
private final DxContext context;
private DexFileArchive dest;
private int nextDexFileIndex = 0;

public DexFileAggregator(
DxContext context,
DexFileArchive dest,
MultidexStrategy multidex,
int maxNumberOfIdxPerDex,
int wasteThresholdPerDex) {
this.context = context;
this.dest = dest;
this.multidex = multidex;
this.maxNumberOfIdxPerDex = maxNumberOfIdxPerDex;
Expand Down Expand Up @@ -145,7 +151,7 @@ private Dex merge(Dex... dexes) throws IOException {
return dexes[0];
default:
try {
DexMerger dexMerger = new DexMerger(dexes, CollisionPolicy.FAIL);
DexMerger dexMerger = new DexMerger(dexes, CollisionPolicy.FAIL, context);
dexMerger.setCompactWasteThreshold(wasteThresholdPerDex);
return dexMerger.merge();
} catch (BufferOverflowException e) {
Expand Down Expand Up @@ -195,12 +201,13 @@ static FieldDescriptor fromDex(Dex dex, int fieldIndex) {
abstract static class MethodDescriptor {
static MethodDescriptor fromDex(Dex dex, int methodIndex) {
MethodId method = dex.methodIds().get(methodIndex);
ProtoId proto = dex.protoIds().get(method.getProtoIndex());
String name = dex.strings().get(method.getNameIndex());
String declaringClass = typeName(dex, method.getDeclaringClassIndex());
String returnType = typeName(dex, dex.returnTypeIndexFromMethodIndex(methodIndex));
short[] parameterTypeIndices = dex.parameterTypeIndicesFromMethodIndex(methodIndex);
String returnType = typeName(dex, proto.getReturnTypeIndex());
TypeList parameterTypeIndices = dex.readTypeList(proto.getParametersOffset());
ImmutableList.Builder<String> parameterTypes = ImmutableList.builder();
for (short parameterTypeIndex : parameterTypeIndices) {
for (short parameterTypeIndex : parameterTypeIndices.getTypes()) {
parameterTypes.add(typeName(dex, parameterTypeIndex & 0xFFFF));
}
return new AutoValue_DexFileAggregator_MethodDescriptor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import com.android.dex.Dex;
import com.android.dex.DexFormat;
import com.android.dx.command.DxConsole;
import com.android.dx.command.dexer.DxContext;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
Expand Down Expand Up @@ -188,9 +188,10 @@ static void buildMergedDexFiles(Options options) throws IOException {
DexFileAggregator out = createDexFileAggregator(options)) {
checkForUnprocessedClasses(zip);
if (!options.verbose) {
// com.android.dx.merge.DexMerger prints tons of debug information to System.out that we
// silence here unless it was explicitly requested.
System.setOut(DxConsole.noop);
// com.android.dx.merge.DexMerger prints status information to System.out that we silence
// here unless it was explicitly requested. (It also prints debug info to DxContext.out,
// which we populate accordingly below.)
System.setOut(Dexing.nullout);
}

if (classesInMainDex == null) {
Expand Down Expand Up @@ -262,6 +263,7 @@ private static void checkForUnprocessedClasses(ZipFile zip) {

private static DexFileAggregator createDexFileAggregator(Options options) throws IOException {
return new DexFileAggregator(
new DxContext(options.verbose ? System.out : ByteStreams.nullOutputStream(), System.err),
new DexFileArchive(
new ZipOutputStream(
new BufferedOutputStream(Files.newOutputStream(options.outputArchive)))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import com.android.dx.cf.direct.DirectClassFile;
import com.android.dx.cf.direct.StdAttributeFactory;
import com.android.dx.command.DxConsole;
import com.android.dx.command.dexer.DxContext;
import com.android.dx.dex.DexOptions;
import com.android.dx.dex.cf.CfOptions;
import com.android.dx.dex.cf.CfTranslator;
Expand All @@ -25,16 +25,20 @@
import com.android.dx.util.ByteArray;
import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.ByteStreams;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionDocumentationCategory;
import com.google.devtools.common.options.OptionEffectTag;
import com.google.devtools.common.options.OptionsBase;
import java.io.PrintStream;

/**
* Common helper class that encodes Java classes into {@link DexFile}s.
*/
class Dexing {

static final PrintStream nullout = new PrintStream(ByteStreams.nullOutputStream());

/**
* Common command line options for use with {@link Dexing}.
*/
Expand Down Expand Up @@ -73,11 +77,11 @@ public static class DexingOptions extends OptionsBase {
)
public boolean printWarnings;

public CfOptions toCfOptions() {
public CfOptions toCfOptions(DxContext context) {
CfOptions result = new CfOptions();
result.localInfo = this.localInfo;
result.optimize = this.optimize;
result.warn = printWarnings ? DxConsole.err : DxConsole.noop;
result.warn = printWarnings ? context.err : Dexing.nullout;
// Use dx's defaults
result.optimizeListFile = null;
result.dontOptimizeListFile = null;
Expand Down Expand Up @@ -114,15 +118,21 @@ static DexingKey create(boolean localInfo, boolean optimize, byte[] classfileCon
@SuppressWarnings("mutable") abstract byte[] classfileContent();
}

private final DxContext context;
private final DexOptions dexOptions;
private final CfOptions cfOptions;

public Dexing(DexingOptions options) {
this(options.toDexOptions(), options.toCfOptions());
this(new DxContext(), options);
}

public Dexing(DxContext context, DexingOptions options) {
this(context, options.toDexOptions(), options.toCfOptions(context));
}

@VisibleForTesting
Dexing(DexOptions dexOptions, CfOptions cfOptions) {
Dexing(DxContext context, DexOptions dexOptions, CfOptions cfOptions) {
this.context = context;
this.dexOptions = dexOptions;
this.cfOptions = cfOptions;
}
Expand All @@ -140,7 +150,9 @@ public DexFile newDexFile() {
}

public ClassDefItem addToDexFile(DexFile dest, DirectClassFile classFile) {
ClassDefItem result = CfTranslator.translate(classFile,
ClassDefItem result = CfTranslator.translate(
context,
classFile,
(byte[]) null /*ignored*/,
cfOptions,
dest.getDexOptions(),
Expand Down

0 comments on commit ce61d63

Please sign in to comment.