aboutsummaryrefslogtreecommitdiff
path: root/dexlib2
diff options
context:
space:
mode:
Diffstat (limited to 'dexlib2')
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java70
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java7
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java2
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java58
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java112
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java7
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java4
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java7
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java12
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java13
-rw-r--r--dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java21
-rw-r--r--dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java6
12 files changed, 253 insertions, 66 deletions
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java
new file mode 100644
index 00000000..775a819d
--- /dev/null
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/AnalyzedMethodUtil.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.jf.dexlib2.analysis;
+
+import org.jf.dexlib2.AccessFlags;
+import org.jf.dexlib2.analysis.util.TypeProtoUtils;
+import org.jf.dexlib2.iface.ClassDef;
+import org.jf.dexlib2.iface.Method;
+import org.jf.dexlib2.util.MethodUtil;
+import org.jf.dexlib2.util.TypeUtils;
+
+import javax.annotation.Nonnull;
+
+public class AnalyzedMethodUtil {
+ public static boolean canAccess(@Nonnull TypeProto type, @Nonnull Method virtualMethod, boolean checkPackagePrivate,
+ boolean checkProtected, boolean checkClass) {
+ if (checkPackagePrivate && MethodUtil.isPackagePrivate(virtualMethod)) {
+ String otherPackage = TypeUtils.getPackage(virtualMethod.getDefiningClass());
+ String thisPackage = TypeUtils.getPackage(type.getType());
+ if (!otherPackage.equals(thisPackage)) {
+ return false;
+ }
+ }
+
+ if (checkProtected && (virtualMethod.getAccessFlags() & AccessFlags.PROTECTED.getValue()) != 0) {
+ if (!TypeProtoUtils.extendsFrom(type, virtualMethod.getDefiningClass())) {
+ return false;
+ }
+ }
+
+ if (checkClass) {
+ ClassPath classPath = type.getClassPath();
+ ClassDef methodClassDef = classPath.getClassDef(virtualMethod.getDefiningClass());
+ if (!TypeUtils.canAccessClass(type.getType(), methodClassDef)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java
index 8fcfc8c5..4aa9a5e4 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ArrayProto.java
@@ -32,6 +32,7 @@
package org.jf.dexlib2.analysis;
import com.google.common.base.Strings;
+import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.immutable.reference.ImmutableFieldReference;
@@ -160,7 +161,11 @@ public class ArrayProto implements TypeProto {
@Override
@Nullable
- public MethodReference getMethodByVtableIndex(int vtableIndex) {
+ public Method getMethodByVtableIndex(int vtableIndex) {
return classPath.getClass("Ljava/lang/Object;").getMethodByVtableIndex(vtableIndex);
}
+
+ @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) {
+ return classPath.getClass("Ljava/lang/Object;").findMethodIndexInVtable(method);
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
index 83104b2f..4b8920f4 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
@@ -146,7 +146,7 @@ public class ClassPath {
}
@Nonnull
- public TypeProto getClass(CharSequence type) {
+ public TypeProto getClass(@Nonnull CharSequence type) {
return loadedClasses.getUnchecked(type.toString());
}
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 d011c1e7..d66e8ebd 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java
@@ -34,7 +34,10 @@ package org.jf.dexlib2.analysis;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
-import com.google.common.collect.*;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import com.google.common.primitives.Ints;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.analysis.util.TypeProtoUtils;
@@ -44,6 +47,7 @@ import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.immutable.ImmutableMethod;
+import org.jf.dexlib2.util.MethodUtil;
import org.jf.util.AlignmentUtils;
import org.jf.util.ExceptionWithContext;
import org.jf.util.SparseArray;
@@ -346,7 +350,7 @@ public class ClassProto implements TypeProto {
@Override
@Nullable
- public MethodReference getMethodByVtableIndex(int vtableIndex) {
+ public Method getMethodByVtableIndex(int vtableIndex) {
List<Method> vtable = getVtable();
if (vtableIndex < 0 || vtableIndex >= vtable.size()) {
return null;
@@ -355,6 +359,20 @@ public class ClassProto implements TypeProto {
return vtable.get(vtableIndex);
}
+ public int findMethodIndexInVtable(@Nonnull MethodReference method) {
+ List<Method> vtable = getVtable();
+ for (int i=0; i<vtable.size(); i++) {
+ Method candidate = vtable.get(i);
+ if (MethodUtil.methodSignaturesMatch(candidate, method)) {
+ if (!classPath.shouldCheckPackagePrivateAccess() ||
+ AnalyzedMethodUtil.canAccess(this, candidate, true, false, false)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
@Nonnull SparseArray<FieldReference> getInstanceFields() {
if (classPath.isArt) {
return artInstanceFieldsSupplier.get();
@@ -790,8 +808,9 @@ public class ClassProto implements TypeProto {
outer: for (Method virtualMethod: methods) {
for (int i=0; i<vtable.size(); i++) {
Method superMethod = vtable.get(i);
- if (methodSignaturesMatch(superMethod, virtualMethod)) {
- if (!classPath.shouldCheckPackagePrivateAccess() || canAccess(superMethod)) {
+ if (MethodUtil.methodSignaturesMatch(superMethod, virtualMethod)) {
+ if (!classPath.shouldCheckPackagePrivateAccess() ||
+ AnalyzedMethodUtil.canAccess(ClassProto.this, superMethod, true, false, false)) {
if (replaceExisting) {
vtable.set(i, virtualMethod);
}
@@ -803,37 +822,6 @@ public class ClassProto implements TypeProto {
vtable.add(virtualMethod);
}
}
-
- private boolean methodSignaturesMatch(@Nonnull Method a, @Nonnull Method b) {
- return (a.getName().equals(b.getName()) &&
- a.getReturnType().equals(b.getReturnType()) &&
- a.getParameters().equals(b.getParameters()));
- }
-
- private boolean canAccess(@Nonnull Method virtualMethod) {
- if (!methodIsPackagePrivate(virtualMethod.getAccessFlags())) {
- return true;
- }
-
- String otherPackage = getPackage(virtualMethod.getDefiningClass());
- String ourPackage = getPackage(getClassDef().getType());
- return otherPackage.equals(ourPackage);
- }
-
- @Nonnull
- private String getPackage(@Nonnull String classType) {
- int lastSlash = classType.lastIndexOf('/');
- if (lastSlash < 0) {
- return "";
- }
- return classType.substring(1, lastSlash);
- }
-
- private boolean methodIsPackagePrivate(int accessFlags) {
- return (accessFlags & (AccessFlags.PRIVATE.getValue() |
- AccessFlags.PROTECTED.getValue() |
- AccessFlags.PUBLIC.getValue())) == 0;
- }
});
private static byte getFieldType(@Nonnull FieldReference field) {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java
index 401c0ec0..3d0318c4 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java
@@ -72,6 +72,8 @@ public class MethodAnalyzer {
@Nonnull private final Method method;
@Nonnull private final MethodImplementation methodImpl;
+ private final boolean normalizeVirtualMethods;
+
private final int paramRegisterCount;
@Nonnull private final ClassPath classPath;
@@ -93,9 +95,10 @@ public class MethodAnalyzer {
private final AnalyzedInstruction startOfMethod;
public MethodAnalyzer(@Nonnull ClassPath classPath, @Nonnull Method method,
- @Nullable InlineMethodResolver inlineResolver) {
+ @Nullable InlineMethodResolver inlineResolver, boolean normalizeVirtualMethods) {
this.classPath = classPath;
this.inlineResolver = inlineResolver;
+ this.normalizeVirtualMethods = normalizeVirtualMethods;
this.method = method;
@@ -735,21 +738,32 @@ public class MethodAnalyzer {
case SPUT_OBJECT:
return true;
case INVOKE_VIRTUAL:
+ analyzeInvokeVirtual(analyzedInstruction, false);
+ return true;
case INVOKE_SUPER:
+ analyzeInvokeVirtual(analyzedInstruction, false);
return true;
case INVOKE_DIRECT:
analyzeInvokeDirect(analyzedInstruction);
return true;
case INVOKE_STATIC:
+ return true;
case INVOKE_INTERFACE:
+ // TODO: normalize interfaces
+ return true;
case INVOKE_VIRTUAL_RANGE:
+ analyzeInvokeVirtual(analyzedInstruction, true);
+ return true;
case INVOKE_SUPER_RANGE:
+ analyzeInvokeVirtual(analyzedInstruction, true);
return true;
case INVOKE_DIRECT_RANGE:
analyzeInvokeDirectRange(analyzedInstruction);
return true;
case INVOKE_STATIC_RANGE:
+ return true;
case INVOKE_INTERFACE_RANGE:
+ // TODO: normalize interfaces
return true;
case NEG_INT:
case NOT_INT:
@@ -1545,12 +1559,12 @@ public class MethodAnalyzer {
ClassDef thisClass = classPath.getClassDef(method.getDefiningClass());
- if (!canAccessClass(thisClass, classPath.getClassDef(resolvedField.getDefiningClass()))) {
+ if (!TypeUtils.canAccessClass(thisClass.getType(), classPath.getClassDef(resolvedField.getDefiningClass()))) {
// the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different
// than resolvedField.getDefiningClass()), and walk up the class hierarchy.
ClassDef fieldClass = classPath.getClassDef(objectRegisterTypeProto.getType());
- while (!canAccessClass(thisClass, fieldClass)) {
+ while (!TypeUtils.canAccessClass(thisClass.getType(), fieldClass)) {
String superclass = fieldClass.getSuperclass();
if (superclass == null) {
throw new ExceptionWithContext("Couldn't find accessible class while resolving field %s",
@@ -1585,6 +1599,75 @@ public class MethodAnalyzer {
return true;
}
+ private boolean analyzeInvokeVirtual(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isRange) {
+ MethodReference targetMethod;
+
+ if (!normalizeVirtualMethods) {
+ return true;
+ }
+
+ if (isRange) {
+ Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction;
+ targetMethod = (MethodReference)instruction.getReference();
+ } else {
+ Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction;
+ targetMethod = (MethodReference)instruction.getReference();
+ }
+
+ TypeProto typeProto = classPath.getClass(targetMethod.getDefiningClass());
+ int methodIndex;
+ try {
+ methodIndex = typeProto.findMethodIndexInVtable(targetMethod);
+ } catch (UnresolvedClassException ex) {
+ return true;
+ }
+
+ if (methodIndex < 0) {
+ return true;
+ }
+
+ Method replacementMethod = typeProto.getMethodByVtableIndex(methodIndex);
+ assert replacementMethod != null;
+ while (true) {
+ String superType = typeProto.getSuperclass();
+ if (superType == null) {
+ break;
+ }
+ typeProto = classPath.getClass(superType);
+ Method resolvedMethod = typeProto.getMethodByVtableIndex(methodIndex);
+ if (resolvedMethod == null) {
+ break;
+ }
+
+ if (!resolvedMethod.equals(replacementMethod)) {
+ if (!AnalyzedMethodUtil.canAccess(typeProto, replacementMethod, true, true, true)) {
+ continue;
+ }
+
+ replacementMethod = resolvedMethod;
+ }
+ }
+
+ if (replacementMethod.equals(method)) {
+ return true;
+ }
+
+ Instruction deodexedInstruction;
+ if (isRange) {
+ Instruction3rc instruction = (Instruction3rc)analyzedInstruction.instruction;
+ deodexedInstruction = new ImmutableInstruction3rc(instruction.getOpcode(), instruction.getStartRegister(),
+ instruction.getRegisterCount(), replacementMethod);
+ } else {
+ Instruction35c instruction = (Instruction35c)analyzedInstruction.instruction;
+ deodexedInstruction = new ImmutableInstruction35c(instruction.getOpcode(), instruction.getRegisterCount(),
+ instruction.getRegisterC(), instruction.getRegisterD(), instruction.getRegisterE(),
+ instruction.getRegisterF(), instruction.getRegisterG(), replacementMethod);
+ }
+
+ analyzedInstruction.setDeodexedInstruction(deodexedInstruction);
+ return true;
+ }
+
private boolean analyzeInvokeVirtualQuick(@Nonnull AnalyzedInstruction analyzedInstruction, boolean isSuper,
boolean isRange) {
int methodIndex;
@@ -1637,12 +1720,13 @@ public class MethodAnalyzer {
// no need to check class access for invoke-super. A class can obviously access its superclass.
ClassDef thisClass = classPath.getClassDef(method.getDefiningClass());
- if (!isSuper && !canAccessClass(thisClass, classPath.getClassDef(resolvedMethod.getDefiningClass()))) {
+ if (!isSuper && !TypeUtils.canAccessClass(
+ thisClass.getType(), classPath.getClassDef(resolvedMethod.getDefiningClass()))) {
// the class is not accessible. So we start looking at objectRegisterTypeProto (which may be different
// than resolvedMethod.getDefiningClass()), and walk up the class hierarchy.
ClassDef methodClass = classPath.getClassDef(objectRegisterTypeProto.getType());
- while (!canAccessClass(thisClass, methodClass)) {
+ while (!TypeUtils.canAccessClass(thisClass.getType(), methodClass)) {
String superclass = methodClass.getSuperclass();
if (superclass == null) {
throw new ExceptionWithContext("Couldn't find accessible class while resolving method %s",
@@ -1698,24 +1782,6 @@ public class MethodAnalyzer {
return true;
}
- private boolean canAccessClass(@Nonnull ClassDef accessorClassDef, @Nonnull ClassDef accesseeClassDef) {
- if (AccessFlags.PUBLIC.isSet(accesseeClassDef.getAccessFlags())) {
- return true;
- }
-
- // Classes can only be public or package private. Any private or protected inner classes are actually
- // package private.
- return getPackage(accesseeClassDef.getType()).equals(getPackage(accessorClassDef.getType()));
- }
-
- private static String getPackage(String className) {
- int lastSlash = className.lastIndexOf('/');
- if (lastSlash < 0) {
- return "";
- }
- return className.substring(1, lastSlash);
- }
-
private boolean analyzePutGetVolatile(@Nonnull AnalyzedInstruction analyzedInstruction) {
return analyzePutGetVolatile(analyzedInstruction, true);
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java
index 06ab8e17..2c283932 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/PrimitiveProto.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.analysis;
+import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.util.ExceptionWithContext;
@@ -65,7 +66,11 @@ public class PrimitiveProto implements TypeProto {
@Override
@Nullable
- public MethodReference getMethodByVtableIndex(int vtableIndex) {
+ public Method getMethodByVtableIndex(int vtableIndex) {
return null;
}
+
+ @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) {
+ return -1;
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java
index f6db2399..776363b8 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/TypeProto.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.analysis;
+import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
@@ -45,5 +46,6 @@ public interface TypeProto {
@Nullable String getSuperclass();
@Nonnull TypeProto getCommonSuperclass(@Nonnull TypeProto other);
@Nullable FieldReference getFieldByOffset(int fieldOffset);
- @Nullable MethodReference getMethodByVtableIndex(int vtableIndex);
+ @Nullable Method getMethodByVtableIndex(int vtableIndex);
+ int findMethodIndexInVtable(@Nonnull MethodReference method);
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java
index 38256fbe..32873456 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/UnknownClassProto.java
@@ -31,6 +31,7 @@
package org.jf.dexlib2.analysis;
+import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
@@ -75,7 +76,11 @@ public class UnknownClassProto implements TypeProto {
@Override
@Nullable
- public MethodReference getMethodByVtableIndex(int vtableIndex) {
+ public Method getMethodByVtableIndex(int vtableIndex) {
return classPath.getClass("Ljava/lang/Object;").getMethodByVtableIndex(vtableIndex);
}
+
+ @Override public int findMethodIndexInVtable(@Nonnull MethodReference method) {
+ return classPath.getClass("Ljava/lang/Object;").findMethodIndexInVtable(method);
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java
index 0313c7c3..e2adf1c4 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/util/TypeProtoUtils.java
@@ -94,4 +94,16 @@ public class TypeProtoUtils {
return type.getClassPath().getUnknownClass();
}
}
+
+ public static boolean extendsFrom(@Nonnull TypeProto candidate, @Nonnull String possibleSuper) {
+ if (candidate.getType().equals(possibleSuper)) {
+ return true;
+ }
+ for (TypeProto superProto: getSuperclassChain(candidate)) {
+ if (superProto.getType().equals(possibleSuper)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java b/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java
index 631b8928..dc978daf 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/util/MethodUtil.java
@@ -35,6 +35,7 @@ import com.google.common.base.Predicate;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.MethodReference;
+import org.jf.util.CharSequenceUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -68,6 +69,12 @@ public final class MethodUtil {
return methodReference.getName().equals("<init>");
}
+ public static boolean isPackagePrivate(@Nonnull Method method) {
+ return (method.getAccessFlags() & (AccessFlags.PRIVATE.getValue() |
+ AccessFlags.PROTECTED.getValue() |
+ AccessFlags.PUBLIC.getValue())) == 0;
+ }
+
public static int getParameterRegisterCount(@Nonnull Method method) {
return getParameterRegisterCount(method, MethodUtil.isStatic(method));
}
@@ -109,5 +116,11 @@ public final class MethodUtil {
return sb.toString();
}
+ public static boolean methodSignaturesMatch(@Nonnull MethodReference a, @Nonnull MethodReference b) {
+ return (a.getName().equals(b.getName()) &&
+ a.getReturnType().equals(b.getReturnType()) &&
+ CharSequenceUtils.listEquals(a.getParameterTypes(), b.getParameterTypes()));
+ }
+
private MethodUtil() {}
}
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java b/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java
index 02890b87..6be21af0 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/util/TypeUtils.java
@@ -31,6 +31,8 @@
package org.jf.dexlib2.util;
+import org.jf.dexlib2.AccessFlags;
+import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.reference.TypeReference;
import javax.annotation.Nonnull;
@@ -49,5 +51,24 @@ public final class TypeUtils {
return type.length() == 1;
}
+ @Nonnull
+ public static String getPackage(@Nonnull String type) {
+ int lastSlash = type.lastIndexOf('/');
+ if (lastSlash < 0) {
+ return "";
+ }
+ return type.substring(1, lastSlash);
+ }
+
+ public static boolean canAccessClass(@Nonnull String accessorType, @Nonnull ClassDef accesseeClassDef) {
+ if (AccessFlags.PUBLIC.isSet(accesseeClassDef.getAccessFlags())) {
+ return true;
+ }
+
+ // Classes can only be public or package private. Any private or protected inner classes are actually
+ // package private.
+ return getPackage(accesseeClassDef.getType()).equals(getPackage(accessorType));
+ }
+
private TypeUtils() {}
}
diff --git a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java
index 65a82f05..25f7778d 100644
--- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java
+++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java
@@ -71,7 +71,7 @@ public class CustomMethodInlineTableTest {
ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile,
15, false);
InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V");
- MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver);
+ MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false);
Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0);
Assert.assertEquals(Opcode.INVOKE_VIRTUAL, deodexedInstruction.getOpcode());
@@ -98,7 +98,7 @@ public class CustomMethodInlineTableTest {
ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile,
15, false);
InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V");
- MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver);
+ MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false);
Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0);
Assert.assertEquals(Opcode.INVOKE_STATIC, deodexedInstruction.getOpcode());
@@ -125,7 +125,7 @@ public class CustomMethodInlineTableTest {
ClassPath classPath = ClassPath.fromClassPath(ImmutableList.<String>of(), ImmutableList.<String>of(), dexFile,
15, false);
InlineMethodResolver inlineMethodResolver = new CustomInlineMethodResolver(classPath, "Lblah;->blah()V");
- MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver);
+ MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, method, inlineMethodResolver, false);
Instruction deodexedInstruction = methodAnalyzer.getInstructions().get(0);
Assert.assertEquals(Opcode.INVOKE_DIRECT, deodexedInstruction.getOpcode());