From a54523e080a7752f298e7681a602542300ad7573 Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Sat, 24 Sep 2016 18:16:55 -0700 Subject: [PATCH] More default method vtable fixes --- .../org/jf/dexlib2/analysis/ClassProto.java | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java index 28618d4d..6705d067 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java @@ -934,9 +934,14 @@ public class ClassProto implements TypeProto { for (ClassDef interfaceDef: interfaces) { for (Method interfaceMethod : interfaceDef.getVirtualMethods()) { - int methodIndex = findMethodIndexInVtable(vtable, interfaceMethod); - if (methodIndex < 0) { + int vtableIndex = findMethodIndexInVtable(vtable, interfaceMethod); + + if (vtableIndex >= 0) { + if (interfaceMethodOverrides(interfaceMethod, vtable.get(vtableIndex))) { + vtable.set(vtableIndex, interfaceMethod); + } + } else { int defaultMethodIndex = findMethodIndexInVtable(defaultMethods, interfaceMethod); if (defaultMethodIndex >= 0) { @@ -963,9 +968,17 @@ public class ClassProto implements TypeProto { if (mirandaMethodIndex >= 0) { if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { - Method removedMethod = mirandaMethods.remove(mirandaMethodIndex); - defaultMethods.add(removedMethod); + + ClassProto existingInterface = (ClassProto)classPath.getClass( + mirandaMethods.get(mirandaMethodIndex).getDefiningClass()); + if (!existingInterface.implementsInterface(interfaceMethod.getDefiningClass())) { + Method oldMethod = mirandaMethods.remove(mirandaMethodIndex); + int methodOrderValue = methodOrder.get(oldMethod); + methodOrder.put(interfaceMethod, methodOrderValue); + defaultMethods.add(interfaceMethod); + } } + continue; } if (!AccessFlags.ABSTRACT.isSet(interfaceMethod.getAccessFlags())) { @@ -1034,6 +1047,26 @@ public class ClassProto implements TypeProto { } } + /** + * Checks if the interface method overrides the virtual or interface method2 + * @param method A Method from an interface + * @param method2 A Method from an interface or a class + * @return true if the interface method overrides the virtual or interface method2 + */ + private boolean interfaceMethodOverrides(@Nonnull Method method, @Nonnull Method method2) { + ClassProto classProto = (ClassProto)classPath.getClass(method2.getDefiningClass()); + + if (classProto.isInterface()) { + ClassProto targetClassProto = (ClassProto)classPath.getClass(method.getDefiningClass()); + if (targetClassProto.implementsInterface(method2.getDefiningClass())) { + return true; + } + return false; + } else { + return false; + } + } + static class ReparentedMethod extends BaseMethodReference implements Method { private final Method method; private final String definingClass;