| // Copyright (c) 2019, 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; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.DataResourceProvider.Visitor; |
| import com.android.tools.r8.ProgramResource.Kind; |
| import com.android.tools.r8.dex.Marker; |
| import com.android.tools.r8.dex.Marker.Tool; |
| import com.android.tools.r8.dump.DumpOptions; |
| import com.android.tools.r8.origin.Origin; |
| import com.android.tools.r8.utils.AndroidApiLevel; |
| import com.android.tools.r8.utils.AndroidApp; |
| import com.android.tools.r8.utils.Box; |
| import com.android.tools.r8.utils.DescriptorUtils; |
| import com.android.tools.r8.utils.InternalOptions; |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.nio.file.Path; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Set; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| |
| @RunWith(Parameterized.class) |
| public class AndroidAppDumpsTest extends TestBase { |
| |
| @Parameterized.Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return getTestParameters().withNoneRuntime().build(); |
| } |
| |
| public AndroidAppDumpsTest(TestParameters parameters) { |
| parameters.assertNoneRuntime(); |
| } |
| |
| @Test |
| public void test() throws Exception { |
| InternalOptions options = new InternalOptions(); |
| options.dumpOptions = DumpOptions.builder(Tool.D8).setBackend(Marker.Backend.DEX).build(); |
| |
| String dataResourceName = "my-resource.bin"; |
| byte[] dataResourceData = new byte[] {1, 2, 3}; |
| |
| Path dexForB = |
| testForD8().addProgramClasses(B.class).setMinApi(AndroidApiLevel.B).compile().writeToZip(); |
| |
| AndroidApp appIn = |
| AndroidApp.builder(options.reporter) |
| .addClassProgramData(ToolHelper.getClassAsBytes(A.class), origin("A")) |
| .addClassProgramData(ToolHelper.getClassAsBytes(A.class), origin("A")) |
| .addClassProgramData(ToolHelper.getClassAsBytes(A.class), origin("A")) |
| .addProgramFile(dexForB) |
| .addClasspathResourceProvider(provider(B.class)) |
| .addClasspathResourceProvider(provider(B.class)) |
| .addClasspathResourceProvider(provider(B.class)) |
| .addLibraryResourceProvider(provider(C.class)) |
| .addLibraryResourceProvider(provider(C.class)) |
| .addLibraryResourceProvider(provider(C.class)) |
| .addProgramResourceProvider( |
| createDataResourceProvider( |
| dataResourceName, dataResourceData, origin(dataResourceName))) |
| .build(); |
| |
| Path dumpFile = temp.newFolder().toPath().resolve("dump.zip"); |
| appIn.dump(dumpFile, options.dumpOptions, options); |
| |
| AndroidApp appOut = AndroidApp.builder(options.reporter).addDump(dumpFile).build(); |
| assertEquals(1, appOut.getClassProgramResourcesForTesting().size()); |
| assertEquals( |
| DescriptorUtils.javaTypeToDescriptor(A.class.getTypeName()), |
| appOut.getClassProgramResourcesForTesting().get(0).getClassDescriptors().iterator().next()); |
| |
| assertEquals(1, appOut.getDexProgramResourcesForTesting().size()); |
| |
| assertEquals(1, appOut.getClasspathResourceProviders().size()); |
| assertEquals( |
| DescriptorUtils.javaTypeToDescriptor(B.class.getTypeName()), |
| appOut.getClasspathResourceProviders().get(0).getClassDescriptors().iterator().next()); |
| |
| assertEquals(1, appOut.getLibraryResourceProviders().size()); |
| assertEquals( |
| DescriptorUtils.javaTypeToDescriptor(C.class.getTypeName()), |
| appOut.getLibraryResourceProviders().get(0).getClassDescriptors().iterator().next()); |
| |
| Box<Boolean> foundData = new Box<>(false); |
| for (ProgramResourceProvider provider : appOut.getProgramResourceProviders()) { |
| DataResourceProvider dataProvider = provider.getDataResourceProvider(); |
| if (dataProvider != null) { |
| dataProvider.accept( |
| new Visitor() { |
| @Override |
| public void visit(DataDirectoryResource directory) {} |
| |
| @Override |
| public void visit(DataEntryResource file) { |
| if (file.getName().equals(dataResourceName)) { |
| foundData.set(true); |
| } |
| } |
| }); |
| } |
| } |
| assertTrue(foundData.get()); |
| } |
| |
| private ProgramResourceProvider createDataResourceProvider( |
| String name, byte[] content, Origin origin) { |
| return new ProgramResourceProvider() { |
| @Override |
| public Collection<ProgramResource> getProgramResources() { |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public DataResourceProvider getDataResourceProvider() { |
| return new DataResourceProvider() { |
| @Override |
| public void accept(Visitor visitor) { |
| visitor.visit( |
| new DataEntryResource() { |
| @Override |
| public InputStream getByteStream() { |
| return new ByteArrayInputStream(content); |
| } |
| |
| @Override |
| public String getName() { |
| return name; |
| } |
| |
| @Override |
| public Origin getOrigin() { |
| return origin; |
| } |
| }); |
| } |
| }; |
| } |
| }; |
| } |
| |
| private Origin origin(String name) { |
| return new Origin(Origin.root()) { |
| @Override |
| public String part() { |
| return name; |
| } |
| }; |
| } |
| |
| private ClassFileResourceProvider provider(Class<?> clazz) { |
| return new ClassFileResourceProvider() { |
| @Override |
| public Set<String> getClassDescriptors() { |
| return Collections.singleton(DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName())); |
| } |
| |
| @Override |
| public ProgramResource getProgramResource(String descriptor) { |
| try { |
| return ProgramResource.fromBytes( |
| origin(clazz.getTypeName()), |
| Kind.CF, |
| ToolHelper.getClassAsBytes(clazz), |
| getClassDescriptors()); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| }; |
| } |
| |
| public static class A {} |
| |
| public static class B {} |
| |
| public static class C {} |
| } |