private static ClassProvider getBasicClasses() { // fallbacks for some special classes that we assume are present return new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), ImmutableSet.of( new ReflectionClassDef(Class.class), new ReflectionClassDef(Cloneable.class), new ReflectionClassDef(Object.class), new ReflectionClassDef(Serializable.class), new ReflectionClassDef(String.class), new ReflectionClassDef(Throwable.class)))); }
@Nonnull @Override public DexFile rewriteDexFile(@Nonnull DexFile dexFile) { try { return org.jf.dexlib2.immutable.ImmutableDexFile.of(super.rewriteDexFile(dexFile)); } catch (Exception e) { LLog.i("Failed to re-construct dex " + e); if (e instanceof NullPointerException || e instanceof ArrayIndexOutOfBoundsException) { LLog.ex(e); } } return new FailedDexFile(); }
@Nonnull public static DexFile[] unquicken(@Nonnull Vdex vdex, @Nullable Opcodes opcodes) { if (opcodes == null) { opcodes = DexUtil.getOpcodes(Oat.Version.O_80.api); } VdexRewriterModule previousModule = null; final DexFile[] mDeodexedFiles = new DexFile[vdex.dexFiles.length]; for (int i = 0; i < mDeodexedFiles.length; i++) { final VdexRewriterModule rewriterModule; if (vdex.isSingleQuickeningInfo && previousModule != null) { // All dex files share the same iterator. rewriterModule = new VdexRewriterModule(vdex.dexFiles[i], previousModule); } else { rewriterModule = new VdexRewriterModule(vdex.dexFiles[i], opcodes); } final DexRewriter vdexRewriter = new DexRewriter(rewriterModule); mDeodexedFiles[i] = ImmutableDexFile.of( vdexRewriter.rewriteDexFile(rewriterModule.mDex)); previousModule = rewriterModule; if (VdexRewriterModule.DEBUG) { rewriterModule.fillLastInfo(); rewriterModule.printUnquickenInfo(); } } return mDeodexedFiles; }
public static ImmutableDexFile of(DexFile dexFile) { if (dexFile instanceof ImmutableDexFile) { return (ImmutableDexFile)dexFile; } return new ImmutableDexFile(dexFile.getClasses()); }
public static ImmutableDexFile of(DexFile dexFile) { if (dexFile instanceof ImmutableDexFile) { return (ImmutableDexFile)dexFile; } return new ImmutableDexFile(dexFile.getOpcodes(), dexFile.getClasses()); }
public static ImmutableDexFile of(DexFile dexFile) { if (dexFile instanceof ImmutableDexFile) { return (ImmutableDexFile)dexFile; } return new ImmutableDexFile(dexFile.getOpcodes(), dexFile.getClasses()); }
DexFileFactory.writeDexFile(patchDexFile.getAbsolutePath(), new ImmutableDexFile(newClassDef.keySet())); } else if (patchClassDefs.size() > 0) { DexFileFactory.writeDexFile(patchDexFile.getAbsolutePath(), new ImmutableDexFile(patchClassDefs.keySet())); DexFileFactory.writeDexFile(tempDexFile.getAbsolutePath(), new ImmutableDexFile(classes));
@Test public void testGetSuperclassChain_Unresolved() throws IOException { // Ltest/one; isn't defined ClassDef twoClassDef = TestUtils.makeClassDef("Ltest/two;", "Ltest/one;"); ClassDef threeClassDef = TestUtils.makeClassDef("Ltest/three;", "Ltest/two;"); ImmutableSet<ClassDef> classes = ImmutableSet.<ClassDef>of(twoClassDef, threeClassDef); ClassPath classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), classes))); TypeProto unknownClassProto = classPath.getUnknownClass(); TypeProto oneClassProto = classPath.getClass("Ltest/one;"); TypeProto twoClassProto = classPath.getClass("Ltest/two;"); TypeProto threeClassProto = classPath.getClass("Ltest/three;"); Assert.assertEquals( ImmutableList.<TypeProto>of(oneClassProto, unknownClassProto), ImmutableList.copyOf(TypeProtoUtils.getSuperclassChain(twoClassProto))); Assert.assertEquals( ImmutableList.<TypeProto>of(twoClassProto, oneClassProto, unknownClassProto), ImmutableList.copyOf(TypeProtoUtils.getSuperclassChain(threeClassProto))); } }
private static ClassProvider getBasicClasses() { // fallbacks for some special classes that we assume are present return new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), ImmutableSet.of( new ReflectionClassDef(Class.class), new ReflectionClassDef(Cloneable.class), new ReflectionClassDef(Object.class), new ReflectionClassDef(Serializable.class), new ReflectionClassDef(String.class), new ReflectionClassDef(Throwable.class)))); }
public ClassPathEx(@Nonnull Iterable<? extends DexFile> classPath, int oatVersion) { super(false, oatVersion); for (DexFile dexFile : classPath) { addDex(dexFile, false); } if (availableClasses.get("Ljava/lang/Class;") == null) { final DexFile basicClasses = new ImmutableDexFile( DexUtil.getOpcodes(VersionMap.mapArtVersionToApi(oatVersion)), ImmutableSet.of( new ReflectionClassDef(Class.class), new ReflectionClassDef(Cloneable.class), new ReflectionClassDef(Object.class), new ReflectionClassDef(Serializable.class), new ReflectionClassDef(String.class), new ReflectionClassDef(Throwable.class))); addDex(basicClasses, false); } }
@Test public void testGetSuperclassChain() throws IOException { ClassDef objectClassDef = TestUtils.makeClassDef("Ljava/lang/Object;", null); ClassDef oneClassDef = TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"); ClassDef twoClassDef = TestUtils.makeClassDef("Ltest/two;", "Ltest/one;"); ClassDef threeClassDef = TestUtils.makeClassDef("Ltest/three;", "Ltest/two;"); ImmutableSet<ClassDef> classes = ImmutableSet.<ClassDef>of( objectClassDef, oneClassDef, twoClassDef, threeClassDef); ClassPath classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), classes))); TypeProto objectClassProto = classPath.getClass("Ljava/lang/Object;"); TypeProto oneClassProto = classPath.getClass("Ltest/one;"); TypeProto twoClassProto = classPath.getClass("Ltest/two;"); TypeProto threeClassProto = classPath.getClass("Ltest/three;"); Assert.assertEquals( ImmutableList.<TypeProto>of(), ImmutableList.copyOf(TypeProtoUtils.getSuperclassChain(objectClassProto))); Assert.assertEquals( ImmutableList.<TypeProto>of(objectClassProto), ImmutableList.copyOf(TypeProtoUtils.getSuperclassChain(oneClassProto))); Assert.assertEquals( ImmutableList.<TypeProto>of(oneClassProto, objectClassProto), ImmutableList.copyOf(TypeProtoUtils.getSuperclassChain(twoClassProto))); Assert.assertEquals( ImmutableList.<TypeProto>of(twoClassProto, oneClassProto, objectClassProto), ImmutableList.copyOf(TypeProtoUtils.getSuperclassChain(threeClassProto))); }
private static DexFile getBasicClasses() { // fallbacks for some special classes that we assume are present return new ImmutableDexFile(ImmutableSet.of( new ReflectionClassDef(Class.class), new ReflectionClassDef(Cloneable.class), new ReflectionClassDef(Object.class), new ReflectionClassDef(Serializable.class), new ReflectionClassDef(String.class), new ReflectionClassDef(Throwable.class))); }
@Test public void testAnnotationElementOrder() { // Elements are out of order wrt to the element name ImmutableSet<ImmutableAnnotationElement> elements = ImmutableSet.of(new ImmutableAnnotationElement("zabaglione", ImmutableNullEncodedValue.INSTANCE), new ImmutableAnnotationElement("blah", ImmutableNullEncodedValue.INSTANCE)); ImmutableAnnotation annotation = new ImmutableAnnotation(AnnotationVisibility.RUNTIME, "Lorg/test/anno;", elements); ImmutableClassDef classDef = new ImmutableClassDef("Lorg/test/blah;", 0, "Ljava/lang/Object;", null, null, ImmutableSet.of(annotation), null, null); MemoryDataStore dataStore = new MemoryDataStore(); try { DexPool.writeTo(dataStore, new ImmutableDexFile(Opcodes.getDefault(), ImmutableSet.of(classDef))); } catch (IOException ex) { throw new RuntimeException(ex); } DexBackedDexFile dexFile = new DexBackedDexFile(Opcodes.getDefault(), dataStore.getBuffer()); ClassDef dbClassDef = Iterables.getFirst(dexFile.getClasses(), null); Assert.assertNotNull(dbClassDef); Annotation dbAnnotation = Iterables.getFirst(dbClassDef.getAnnotations(), null); Assert.assertNotNull(dbAnnotation); List<AnnotationElement> dbElements = Lists.newArrayList(dbAnnotation.getElements()); // Ensure that the elements were written out in sorted order Assert.assertEquals(2, dbElements.size()); Assert.assertEquals("blah", dbElements.get(0).getName()); Assert.assertEquals("zabaglione", dbElements.get(1).getName()); }
null, null, null, null, null, null)); ImmutableDexFile dexFile = new ImmutableDexFile(Opcodes.getDefault(), classes); File zip = folder.newFile(); try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zip))) {
DexPool.writeTo(dataStore, new ImmutableDexFile(Opcodes.getDefault(), ImmutableSet.of(classDef))); } catch (IOException ex) { throw new RuntimeException(ex);
@Test public void testCustomMethodInlineTable_Direct() throws IOException { List<ImmutableInstruction> instructions = Lists.newArrayList( new ImmutableInstruction35mi(Opcode.EXECUTE_INLINE, 1, 0, 0, 0, 0, 0, 0), new ImmutableInstruction10x(Opcode.RETURN_VOID)); ImmutableMethodImplementation methodImpl = new ImmutableMethodImplementation(1, instructions, null, null); ImmutableMethod method = new ImmutableMethod("Lblah;", "blah", null, "V", AccessFlags.PRIVATE.getValue(), null, methodImpl); ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, null, ImmutableList.of(method), null); DexFile dexFile = new ImmutableDexFile(Opcodes.getDefault(), ImmutableList.of(classDef)); ClassPathResolver resolver = new ClassPathResolver(ImmutableList.<String>of(), ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile); ClassPath classPath = new ClassPath(resolver.getResolvedClassProviders(), false, ClassPath.NOT_ART); InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V"); MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false); Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0); Assert.assertEquals(Opcode.INVOKE_DIRECT, deodexedInstruction.getOpcode()); MethodReference methodReference = (MethodReference)((Instruction35c)deodexedInstruction).getReference(); Assert.assertEquals(method, methodReference); } }
@Test public void testCustomMethodInlineTable_Virtual() throws IOException { List<ImmutableInstruction> instructions = Lists.newArrayList( new ImmutableInstruction35mi(Opcode.EXECUTE_INLINE, 1, 0, 0, 0, 0, 0, 0), new ImmutableInstruction10x(Opcode.RETURN_VOID)); ImmutableMethodImplementation methodImpl = new ImmutableMethodImplementation(1, instructions, null, null); ImmutableMethod method = new ImmutableMethod("Lblah;", "blah", null, "V", AccessFlags.PUBLIC.getValue(), null, methodImpl); ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, null, null, ImmutableList.of(method)); DexFile dexFile = new ImmutableDexFile(Opcodes.getDefault(), ImmutableList.of(classDef)); ClassPathResolver resolver = new ClassPathResolver(ImmutableList.<String>of(), ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile); ClassPath classPath = new ClassPath(resolver.getResolvedClassProviders(), false, ClassPath.NOT_ART); InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V"); MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false); Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0); Assert.assertEquals(Opcode.INVOKE_VIRTUAL, deodexedInstruction.getOpcode()); MethodReference methodReference = (MethodReference)((Instruction35c)deodexedInstruction).getReference(); Assert.assertEquals(method, methodReference); }
@Test public void testCustomMethodInlineTable_Static() throws IOException { List<ImmutableInstruction> instructions = Lists.newArrayList( new ImmutableInstruction35mi(Opcode.EXECUTE_INLINE, 1, 0, 0, 0, 0, 0, 0), new ImmutableInstruction10x(Opcode.RETURN_VOID)); ImmutableMethodImplementation methodImpl = new ImmutableMethodImplementation(1, instructions, null, null); ImmutableMethod method = new ImmutableMethod("Lblah;", "blah", null, "V", AccessFlags.STATIC.getValue(), null, methodImpl); ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, null, ImmutableList.of(method), null); DexFile dexFile = new ImmutableDexFile(Opcodes.getDefault(), ImmutableList.of(classDef)); ClassPathResolver resolver = new ClassPathResolver(ImmutableList.<String>of(), ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile); ClassPath classPath = new ClassPath(resolver.getResolvedClassProviders(), false, ClassPath.NOT_ART); InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V"); MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false); Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0); Assert.assertEquals(Opcode.INVOKE_STATIC, deodexedInstruction.getOpcode()); MethodReference methodReference = (MethodReference)((Instruction35c)deodexedInstruction).getReference(); Assert.assertEquals(method, methodReference); }
@Test public void should_generate_non_final_classes() throws IOException { ImmutableClassDef def = new ImmutableClassDef("Lfoo/Bar;", AccessFlags.FINAL.getValue(), "Ljava/lang/Object;", null, null, null, null, null); byte[] bytes = DexPoolUtils.toBytecode(new ImmutableDexFile(Opcodes.getDefault(), Collections.singleton(def))); given(dexFileLoader.loadDex(srcPathCaptor.capture(), anyString())) .will(answer((String src, String out) -> { assertTrue(src.endsWith("tmp.dex")); assertTrue(out.endsWith(".dex")); DexFile file; try (InputStream in = new FileInputStream(src)) { file = new DexBackedDexFile(null, ByteStreams.toByteArray(in)); } Set<? extends ClassDef> classes = file.getClasses(); assertSame(1, classes.size()); assertFalse(AccessFlags.FINAL.isSet(classes.iterator().next().getAccessFlags())); return dexFile; })); DexFile file = new DexBackedDexFile(null, bytes); ClassTransformer transformer = new ClassTransformer(file.getOpcodes(), file.getClasses(), folder.newFolder(), dexFileLoader); assertSame(dexFile, transformer.call()); assertTrue(transformer.getClasses().isEmpty()); assertFalse(new File(srcPathCaptor.getValue()).exists()); }
"Liface/sub2;", "Liface/sub3;", "Liface/sub4;")); oldClassPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), classes))); newClassPath = new ClassPath(Lists.newArrayList(new DexClassProvider( new ImmutableDexFile(Opcodes.forArtVersion(72), classes))), true, 72);