Split disassembly writing out of DexApplication.
Change-Id: Ib89c6ed48f5e7c54e21e859c609fb70634bc30c8
Bug:
diff --git a/src/main/java/com/android/tools/r8/Disassemble.java b/src/main/java/com/android/tools/r8/Disassemble.java
index a0770bc..27bcac2 100644
--- a/src/main/java/com/android/tools/r8/Disassemble.java
+++ b/src/main/java/com/android/tools/r8/Disassemble.java
@@ -3,13 +3,21 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.graph.AssemblyWriter;
+import com.android.tools.r8.graph.DexByteCodeWriter;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.SmaliWriter;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
public class Disassemble {
public static class DisassembleCommand extends BaseCommand {
@@ -64,6 +72,7 @@
" and options are:",
" --smali # Disassemble using smali syntax.",
" --pg-map <file> # Proguard map <file> for mapping names.",
+ " --output # Specify a file or directory to write to.",
" --version # Print the version of r8.",
" --help # Print this message."));
@@ -144,9 +153,30 @@
return;
}
if (command.isPrintVersion()) {
- System.out.println("R8 " + Version.LABEL);
+ System.out.println("Disassemble (R8) " + Version.LABEL);
return;
}
- R8.disassemble(command);
+ disassemble(command);
+ }
+
+ public static void disassemble(DisassembleCommand command)
+ throws IOException, ExecutionException {
+ AndroidApp app = command.getInputApp();
+ InternalOptions options = command.getInternalOptions();
+ ExecutorService executor = ThreadUtils.getExecutorService(options);
+ Timing timing = new Timing("disassemble");
+ try {
+ DexApplication application = new ApplicationReader(app, options, timing).read(executor);
+ DexByteCodeWriter writer = command.useSmali()
+ ? new SmaliWriter(application, options)
+ : new AssemblyWriter(application, options);
+ if (command.getOutputPath() != null) {
+ writer.write(command.getOutputPath());
+ } else {
+ writer.write(System.out);
+ }
+ } finally {
+ executor.shutdown();
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index d0badf2..0c367bd 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -164,33 +164,6 @@
return result;
}
- public static void disassemble(Disassemble.DisassembleCommand command)
- throws IOException, ExecutionException {
- Path output = command.getOutputPath();
- AndroidApp app = command.getInputApp();
- InternalOptions options = command.getInternalOptions();
- ExecutorService executor = ThreadUtils.getExecutorService(options);
- Timing timing = new Timing("disassemble");
- try {
- DexApplication application = new ApplicationReader(app, options, timing).read(executor);
- if (options.useSmaliSyntax) {
- if (output != null) {
- Files.createDirectories(output);
- try (PrintStream ps = new PrintStream(
- Files.newOutputStream(output.resolve("classes.smali")))) {
- application.smali(options, ps);
- }
- } else {
- application.smali(options, System.out);
- }
- } else {
- application.disassemble(output, options);
- }
- } finally {
- executor.shutdown();
- }
- }
-
static CompilationResult runForTesting(AndroidApp app, InternalOptions options)
throws IOException, CompilationException {
ExecutorService executor = ThreadUtils.getExecutorService(options);
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
new file mode 100644
index 0000000..50ff578
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.InternalOptions;
+import java.io.PrintStream;
+
+public class AssemblyWriter extends DexByteCodeWriter {
+
+ public AssemblyWriter(DexApplication application, InternalOptions options) {
+ super(application, options);
+ }
+
+ @Override
+ String getFileEnding() {
+ return ".dump";
+ }
+
+ @Override
+ void writeClassHeader(DexProgramClass clazz, PrintStream ps) {
+ String clazzName;
+ if (application.getProguardMap() != null) {
+ clazzName = application.getProguardMap().originalNameOf(clazz.type);
+ } else {
+ clazzName = clazz.type.toSourceString();
+ }
+ ps.println("# Bytecode for");
+ ps.println("# Class: '" + clazzName + "'");
+ ps.println();
+ }
+
+ @Override
+ void writeField(DexEncodedField field, PrintStream ps) {
+ // Not implemented, yet.
+ }
+
+ @Override
+ void writeMethod(DexEncodedMethod method, PrintStream ps) {
+ ClassNameMapper naming = application.getProguardMap();
+ String methodName = naming != null
+ ? naming.originalSignatureOf(method.method).toString()
+ : method.method.name.toString();
+ ps.println("#");
+ ps.println("# Method: '" + methodName + "':");
+ ps.println("#");
+ ps.println();
+ Code code = method.getCode();
+ if (code != null) {
+ ps.println(code.toString(method, naming));
+ }
+ }
+
+ @Override
+ void writeClassFooter(DexProgramClass clazz, PrintStream ps) {
+
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index b79f30e..a84c90b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -8,23 +8,14 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ProgramClassCollection;
-import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.primitives.Bytes;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
import java.util.Set;
@@ -99,148 +90,6 @@
return proguardMap;
}
- private void disassemble(DexEncodedMethod method, ClassNameMapper naming, Path outputDir) {
- if (method.getCode() != null) {
- PrintStream ps = System.out;
- try {
- String clazzName;
- String methodName;
- if (naming != null) {
- clazzName = naming.originalNameOf(method.method.holder);
- methodName = naming.originalSignatureOf(method.method).toString();
- } else {
- clazzName = method.method.holder.toSourceString();
- methodName = method.method.name.toString();
- }
- if (outputDir != null) {
- Path directory = outputDir.resolve(clazzName.replace('.', '/'));
- String name = methodName + ".dump";
- if (name.length() > 200) {
- name = StringUtils.computeMD5Hash(name);
- }
- Files.createDirectories(directory);
- ps = new PrintStream(Files.newOutputStream(directory.resolve(name)));
- }
- ps.println("Bytecode for");
- ps.println("Class: '" + clazzName + "'");
- ps.println("Method: '" + methodName + "':");
- ps.println(method.getCode().toString(method, naming));
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if (outputDir != null) {
- ps.flush();
- ps.close();
- }
- }
- }
- }
-
- /**
- * Write disassembly for the application code in the provided directory.
- *
- * <p>If no directory is provided everything is written to System.out.
- */
- public void disassemble(Path outputDir, InternalOptions options) {
- for (DexProgramClass clazz : programClasses.getAllClasses()) {
- clazz.forEachMethod(method -> {
- if (options.methodMatchesFilter(method)) {
- disassemble(method, getProguardMap(), outputDir);
- }
- });
- }
- }
-
- /**
- * Return smali source for the application code.
- */
- public String smali(InternalOptions options) {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- PrintStream ps = new PrintStream(os);
- smali(options, ps);
- return new String(os.toByteArray(), StandardCharsets.UTF_8);
- }
-
- private void writeClassHeader(DexClass clazz, PrintStream ps) {
- StringBuilder builder = new StringBuilder();
- builder.append(".class ");
- builder.append(clazz.accessFlags.toSmaliString());
- builder.append(" ");
- builder.append(clazz.type.toSmaliString());
- builder.append("\n\n");
- if (clazz.type != dexItemFactory.objectType) {
- builder.append(".super ");
- builder.append(clazz.superType.toSmaliString());
- builder.append("\n");
- for (DexType iface : clazz.interfaces.values) {
- builder.append(".implements ");
- builder.append(iface.toSmaliString());
- builder.append("\n");
- }
- }
- ps.append(builder.toString());
- }
-
- private void writeClassFooter(DexClass clazz, PrintStream ps) {
- StringBuilder builder = new StringBuilder();
- builder.append("# End of class ");
- builder.append(clazz.type.toSmaliString());
- builder.append("\n");
- ps.append(builder.toString());
- }
-
- /**
- * Write smali source for the application code on the provided PrintStream.
- */
- public void smali(InternalOptions options, PrintStream ps) {
- List<DexProgramClass> classes = programClasses.getAllClasses();
- classes.sort(Comparator.comparing(DexProgramClass::toSourceString));
- boolean firstClass = true;
- for (DexClass clazz : classes) {
- boolean classHeaderWritten = false;
- if (!options.hasMethodsFilter()) {
- if (!firstClass) {
- ps.append("\n");
- firstClass = false;
- }
- writeClassHeader(clazz, ps);
- classHeaderWritten = true;
- }
- for (DexEncodedMethod method : clazz.virtualMethods()) {
- if (options.methodMatchesFilter(method)) {
- if (!classHeaderWritten) {
- if (!firstClass) {
- ps.append("\n");
- firstClass = false;
- }
- writeClassHeader(clazz, ps);
- classHeaderWritten = true;
- }
- ps.append("\n");
- ps.append(method.toSmaliString(getProguardMap()));
- }
- }
- for (DexEncodedMethod method : clazz.directMethods()) {
- if (options.methodMatchesFilter(method)) {
- if (!classHeaderWritten) {
- if (!firstClass) {
- ps.append("\n");
- firstClass = false;
- }
- writeClassHeader(clazz, ps);
- classHeaderWritten = true;
- }
- ps.append("\n");
- ps.append(method.toSmaliString(getProguardMap()));
- }
- }
- if (classHeaderWritten) {
- ps.append("\n");
- writeClassFooter(clazz, ps);
- }
- }
- }
-
public abstract static class Builder<T extends Builder> {
// We handle program class collection separately from classpath
// and library class collections. Since while we assume program
diff --git a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
new file mode 100644
index 0000000..025a502
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
@@ -0,0 +1,99 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThrowingFunction;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+public abstract class DexByteCodeWriter {
+
+ final DexApplication application;
+ final InternalOptions options;
+
+ DexByteCodeWriter(DexApplication application,
+ InternalOptions options) {
+ this.application = application;
+ this.options = options;
+ }
+
+ private void ensureParentExists(Path path) throws IOException {
+ Path parent = path.getParent();
+ if (parent != null) {
+ Files.createDirectories(parent);
+ }
+ }
+
+ private ThrowingFunction<DexClass, PrintStream, IOException> oneFilePerClass(Path path) {
+ return (clazz) -> {
+ String className = DescriptorUtils.descriptorToJavaType(clazz.type.toDescriptorString(),
+ application.getProguardMap());
+ Path classOutput = path.resolve(className.replace('.', File.separatorChar)
+ + getFileEnding());
+ ensureParentExists(classOutput);
+ return new PrintStream(Files.newOutputStream(classOutput));
+ };
+ }
+
+ public void write(Path path) throws IOException {
+ if (Files.isDirectory(path)) {
+ write(oneFilePerClass(path), PrintStream::close);
+ } else {
+ ensureParentExists(path);
+ try (PrintStream ps = new PrintStream(Files.newOutputStream(path))) {
+ write(ps);
+ }
+ }
+ }
+
+ public void write(PrintStream output) throws IOException {
+ write(x -> output, x -> {
+ });
+ }
+
+ private void write(ThrowingFunction<DexClass, PrintStream, IOException> outputStreamProvider,
+ Consumer<PrintStream> closer)
+ throws IOException {
+ for (DexProgramClass clazz : application.classes()) {
+ if (anyMethodMatches(clazz)) {
+ PrintStream ps = outputStreamProvider.apply(clazz);
+ try {
+ writeClass(clazz, outputStreamProvider.apply(clazz));
+ } finally {
+ closer.accept(ps);
+ }
+ }
+ }
+ }
+
+ private boolean anyMethodMatches(DexClass clazz) {
+ return !options.hasMethodsFilter()
+ || Arrays.stream(clazz.virtualMethods()).anyMatch(options::methodMatchesFilter)
+ || Arrays.stream(clazz.directMethods()).anyMatch(options::methodMatchesFilter);
+ }
+
+ private void writeClass(DexProgramClass clazz, PrintStream ps) {
+ writeClassHeader(clazz, ps);
+ clazz.forEachField(field -> writeField(field, ps));
+ clazz.forEachMethod(method -> writeMethod(method, ps));
+ writeClassFooter(clazz, ps);
+ }
+
+ abstract String getFileEnding();
+
+ abstract void writeClassHeader(DexProgramClass clazz, PrintStream ps);
+
+ abstract void writeField(DexEncodedField field, PrintStream ps);
+
+ abstract void writeMethod(DexEncodedMethod method, PrintStream ps);
+
+ abstract void writeClassFooter(DexProgramClass clazz, PrintStream ps);
+}
diff --git a/src/main/java/com/android/tools/r8/graph/SmaliWriter.java b/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
new file mode 100644
index 0000000..480e549
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/SmaliWriter.java
@@ -0,0 +1,70 @@
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.utils.InternalOptions;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+
+public class SmaliWriter extends DexByteCodeWriter {
+
+ public SmaliWriter(DexApplication application,
+ InternalOptions options) {
+ super(application, options);
+ }
+
+ /** Return smali source for the application code. */
+ public static String smali(DexApplication application, InternalOptions options) {
+ SmaliWriter writer = new SmaliWriter(application, options);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ try (PrintStream ps = new PrintStream(os)) {
+ writer.write(ps);
+ } catch (IOException e) {
+ throw new CompilationError("Failed to generate smali sting", e);
+ }
+ return new String(os.toByteArray(), StandardCharsets.UTF_8);
+ }
+
+ @Override
+ String getFileEnding() {
+ return ".smali";
+ }
+
+ @Override
+ void writeClassHeader(DexProgramClass clazz, PrintStream ps) {
+ ps.append(".class ");
+ ps.append(clazz.accessFlags.toSmaliString());
+ ps.append(" ");
+ ps.append(clazz.type.toSmaliString());
+ ps.append("\n\n");
+ if (clazz.type != application.dexItemFactory.objectType) {
+ ps.append(".super ");
+ ps.append(clazz.superType.toSmaliString());
+ ps.append("\n");
+ for (DexType iface : clazz.interfaces.values) {
+ ps.append(".implements ");
+ ps.append(iface.toSmaliString());
+ ps.append("\n");
+ }
+ }
+ }
+
+ @Override
+ void writeClassFooter(DexProgramClass clazz, PrintStream ps) {
+ ps.append("# End of class ");
+ ps.append(clazz.type.toSmaliString());
+ ps.append("\n");
+ }
+
+ @Override
+ void writeMethod(DexEncodedMethod method, PrintStream ps) {
+ ps.println();
+ ps.println(method.toSmaliString(application.getProguardMap()));
+ }
+
+ @Override
+ void writeField(DexEncodedField field, PrintStream ps) {
+ // Not yet implemented.
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingFunction.java b/src/main/java/com/android/tools/r8/utils/ThrowingFunction.java
new file mode 100644
index 0000000..ab33e81
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/ThrowingFunction.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.utils;
+
+import java.util.function.Function;
+
+/**
+ * Similar to a {@link Function} but throws a single {@link Throwable}.
+ *
+ * @param <T> the type of the first argument
+ * @param <R> the return type
+ * @param <E> the type of the {@link Throwable}
+ */
+@FunctionalInterface
+public interface ThrowingFunction<T, R, E extends Throwable> {
+
+ R apply(T t) throws E;
+}
diff --git a/src/test/java/com/android/tools/r8/internal/R8DisassemblerTest.java b/src/test/java/com/android/tools/r8/internal/R8DisassemblerTest.java
index d455841..0d2c5af 100644
--- a/src/test/java/com/android/tools/r8/internal/R8DisassemblerTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8DisassemblerTest.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.CompilationException;
import com.android.tools.r8.Disassemble;
-import com.android.tools.r8.R8;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.FileUtils;
import java.io.IOException;
@@ -15,19 +14,35 @@
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.junit.Test;
-import org.junit.experimental.theories.Theories;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
// Invoke R8 on the dex files extracted from GMSCore.apk to disassemble the dex code.
-@RunWith(Theories.class)
+@RunWith(Parameterized.class)
public class R8DisassemblerTest {
static final String APP_DIR = "third_party/gmscore/v5/";
- public void testDisassemble(boolean deobfuscate, boolean smali)
+ @Parameters(name = "deobfuscate: {0} smali: {1}")
+ public static Iterable<Object[]> data() {
+ return Arrays
+ .asList(new Object[][]{{false, false}, {false, true}, {true, false}, {true, true}});
+ }
+
+ @Parameter(0)
+ public boolean deobfuscate;
+
+ @Parameter(1)
+ public boolean smali;
+
+ @Test
+ public void testDisassemble()
throws IOException, ExecutionException, ProguardRuleParserException, CompilationException {
// This test only ensures that we do not break disassembling of dex code. It does not
// check the generated code. To make it fast, we get rid of the output.
@@ -46,30 +61,11 @@
Files.list(Paths.get(APP_DIR))
.filter(FileUtils::isDexFile)
.collect(Collectors.toList()));
- R8.disassemble(builder.build());
+ Disassemble.DisassembleCommand command = builder.build();
+ Disassemble.disassemble(command);
} finally {
// Restore System.out for good measure.
System.setOut(originalOut);
}
}
-
- @Test
- public void test1() throws Exception {
- testDisassemble(false, false);
- }
-
- @Test
- public void test2() throws Exception {
- testDisassemble(false, true);
- }
-
- @Test
- public void test3() throws Exception {
- testDisassemble(true, false);
- }
-
- @Test
- public void test4() throws Exception {
- testDisassemble(true, true);
- }
}
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliDisassembleTest.java b/src/test/java/com/android/tools/r8/smali/SmaliDisassembleTest.java
index ea0d767..b35e768 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliDisassembleTest.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliDisassembleTest.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.errors.DexOverflowException;
import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.SmaliWriter;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Smali;
@@ -32,7 +33,7 @@
new InternalOptions(),
new Timing("SmaliTest"))
.read();
- assertEquals(smali, application.smali(new InternalOptions()));
+ assertEquals(smali, SmaliWriter.smali(application, new InternalOptions()));
} catch (IOException | RecognitionException | ExecutionException | DexOverflowException e) {
throw new RuntimeException(e);
}
@@ -73,7 +74,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}
@@ -129,7 +130,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}
@@ -185,7 +186,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}
@@ -228,7 +229,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}
@@ -271,7 +272,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}
@@ -314,7 +315,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}
@@ -357,7 +358,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}
@@ -380,7 +381,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}
@@ -404,7 +405,7 @@
"\n" +
"# End of class LTest;\n";
- assertEquals(expected, application.smali(new InternalOptions()));
+ assertEquals(expected, SmaliWriter.smali(application, new InternalOptions()));
roundTripRawSmali(expected);
}