From 36c94ad653a7de720e9ec237d97cab603fc5613a Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Sat, 1 Feb 2020 14:30:15 -0800 Subject: [PATCH] Add support for reading the new hidden api restrictions in dexlib2 --- .../baksmali/InstructionMethodItemTest.java | 5 + .../org/jf/dexlib2/HiddenApiRestriction.java | 110 ++++++++++++ .../org/jf/dexlib2/analysis/ClassProto.java | 7 +- .../analysis/CustomInlineMethodResolver.java | 2 +- .../analysis/InlineMethodResolver.java | 2 +- .../reflection/ReflectionConstructor.java | 5 + .../analysis/reflection/ReflectionField.java | 5 + .../analysis/reflection/ReflectionMethod.java | 5 + .../dexlib2/dexbacked/DexBackedClassDef.java | 166 +++++++++++++++++- .../dexlib2/dexbacked/DexBackedDexFile.java | 29 ++- .../jf/dexlib2/dexbacked/DexBackedField.java | 22 ++- .../jf/dexlib2/dexbacked/DexBackedMethod.java | 21 ++- .../org/jf/dexlib2/dexbacked/DexBuffer.java | 2 +- .../dexbacked/raw/HiddenApiClassDataItem.java | 136 ++++++++++++++ .../jf/dexlib2/dexbacked/raw/ItemType.java | 2 + .../dexbacked/raw/util/DexAnnotator.java | 7 +- .../util/VariableSizeListIterator.java | 4 +- .../main/java/org/jf/dexlib2/iface/Field.java | 11 ++ .../java/org/jf/dexlib2/iface/Member.java | 13 ++ .../java/org/jf/dexlib2/iface/Method.java | 11 ++ .../jf/dexlib2/immutable/ImmutableField.java | 16 +- .../jf/dexlib2/immutable/ImmutableMethod.java | 9 + .../jf/dexlib2/rewriter/FieldRewriter.java | 5 + .../jf/dexlib2/rewriter/MethodRewriter.java | 5 + .../dexlib2/writer/builder/BuilderField.java | 7 + .../dexlib2/writer/builder/BuilderMethod.java | 8 + .../jf/dexlib2/writer/pool/PoolMethod.java | 5 + .../analysis/CustomMethodInlineTableTest.java | 6 +- .../dexlib2/analysis/MethodAnalyzerTest.java | 12 +- .../org/jf/dexlib2/pool/RollbackTest.java | 8 +- .../org/jf/dexlib2/writer/CallSiteTest.java | 2 +- 31 files changed, 613 insertions(+), 35 deletions(-) create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/HiddenApiRestriction.java create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HiddenApiClassDataItem.java diff --git a/baksmali/src/test/java/org/jf/baksmali/InstructionMethodItemTest.java b/baksmali/src/test/java/org/jf/baksmali/InstructionMethodItemTest.java index fe7bb6e7..20a38037 100644 --- a/baksmali/src/test/java/org/jf/baksmali/InstructionMethodItemTest.java +++ b/baksmali/src/test/java/org/jf/baksmali/InstructionMethodItemTest.java @@ -38,6 +38,7 @@ import org.jf.baksmali.Adaptors.Format.InstructionMethodItem; import org.jf.baksmali.Adaptors.MethodDefinition; import org.jf.baksmali.Adaptors.RegisterFormatter; import org.jf.dexlib2.Format; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.ReferenceType; import org.jf.dexlib2.base.reference.BaseMethodReference; @@ -199,6 +200,10 @@ public class InstructionMethodItemTest { public String getReturnType() { return "V"; } + + @Nonnull @Override public Set getHiddenApiRestrictions() { + return ImmutableSet.of(); + } } private static class TestClassDef extends BaseTypeReference implements ClassDef { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/HiddenApiRestriction.java b/dexlib2/src/main/java/org/jf/dexlib2/HiddenApiRestriction.java new file mode 100644 index 00000000..7ba0210d --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/HiddenApiRestriction.java @@ -0,0 +1,110 @@ +/* + * Copyright 2020, 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; + +import com.google.common.collect.ImmutableSet; + +import java.util.Set; +import java.util.StringJoiner; + +public enum HiddenApiRestriction { + WHITELIST(0, "whitelist", false), + GREYLIST(1, "greylist", false), + BLACKLIST(2, "blacklist", false), + GREYLIST_MAX_O(3, "greylist-max-o", false), + GREYLIST_MAX_P(4, "greylist-max-p", false), + GREYLIST_MAX_Q(5, "greylist-max-q", false), + CORE_PLATFORM_API(8, "core-platform-api", true); + + private static final HiddenApiRestriction[] hiddenApiFlags = new HiddenApiRestriction[] { + WHITELIST, + GREYLIST, + BLACKLIST, + GREYLIST_MAX_O, + GREYLIST_MAX_P, + GREYLIST_MAX_Q + }; + + private static final HiddenApiRestriction[] domainSpecificApiFlags = new HiddenApiRestriction[] { + CORE_PLATFORM_API + }; + + private static final int HIDDENAPI_FLAG_MASK = 0x7; + + private final int value; + private final String name; + private final boolean isDomainSpecificApiFlag; + + HiddenApiRestriction(int value, String name, boolean isDomainSpecificApiFlag) { + this.value = value; + this.name = name; + this.isDomainSpecificApiFlag = isDomainSpecificApiFlag; + } + + public String toString() { + return name; + } + + public int getValue() { + return value; + } + + public boolean isSet(int value) { + if (isDomainSpecificApiFlag) { + return (value & ~HIDDENAPI_FLAG_MASK) == this.value; + } else { + return (value & HIDDENAPI_FLAG_MASK) == this.value; + } + } + + public boolean isDomainSpecificApiFlag() { + return isDomainSpecificApiFlag; + } + + public static Set getAllFlags(int value) { + HiddenApiRestriction normalRestriction = hiddenApiFlags[value & HIDDENAPI_FLAG_MASK]; + + int domainSpecificPart = (value & ~HIDDENAPI_FLAG_MASK); + if (domainSpecificPart == 0) { + return ImmutableSet.of(normalRestriction); + } + return ImmutableSet.of(normalRestriction, domainSpecificApiFlags[(domainSpecificPart >> 3) - 1]); + } + + public static String formatHiddenRestrictions(int value) { + StringJoiner joiner = new StringJoiner("|"); + for (HiddenApiRestriction hiddenApiRestriction : getAllFlags(value)) { + joiner.add(hiddenApiRestriction.toString()); + } + return joiner.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 af9889a8..886f10ba 100755 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassProto.java @@ -38,13 +38,14 @@ import com.google.common.base.Suppliers; import com.google.common.collect.*; import com.google.common.primitives.Ints; import org.jf.dexlib2.AccessFlags; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.analysis.util.TypeProtoUtils; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.*; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; -import org.jf.dexlib2.util.MethodUtil; import org.jf.dexlib2.util.AlignmentUtils; +import org.jf.dexlib2.util.MethodUtil; import org.jf.util.ExceptionWithContext; import org.jf.util.SparseArray; @@ -1285,6 +1286,10 @@ public class ClassProto implements TypeProto { return method.getAnnotations(); } + @Nonnull @Override public Set getHiddenApiRestrictions() { + return method.getHiddenApiRestrictions(); + } + @Nullable @Override public MethodImplementation getImplementation() { return method.getImplementation(); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/CustomInlineMethodResolver.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/CustomInlineMethodResolver.java index c88eb082..f3ed86f7 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/CustomInlineMethodResolver.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/CustomInlineMethodResolver.java @@ -133,6 +133,6 @@ public class CustomInlineMethodResolver extends InlineMethodResolver { throw new RuntimeException("Cannot resolve inline method: " + inlineMethod); } - return new ImmutableMethod(className, methodName, methodParams, methodRet, accessFlags, null, null); + return new ImmutableMethod(className, methodName, methodParams, methodRet, accessFlags, null, null, null); } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/InlineMethodResolver.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/InlineMethodResolver.java index 4b2e7e64..ea5c7b48 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/InlineMethodResolver.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/InlineMethodResolver.java @@ -67,7 +67,7 @@ public abstract class InlineMethodResolver { private static Method inlineMethod(int accessFlags, @Nonnull String cls, @Nonnull String name, @Nonnull String params, @Nonnull String returnType) { ImmutableList paramList = ImmutableList.copyOf(ParamUtil.parseParamString(params)); - return new ImmutableMethod(cls, name, paramList, returnType, accessFlags, null, null); + return new ImmutableMethod(cls, name, paramList, returnType, accessFlags, null, null, null); } @Nonnull public abstract Method resolveExecuteInline(@Nonnull AnalyzedInstruction instruction); diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionConstructor.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionConstructor.java index 84219599..9aa9b7f0 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionConstructor.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionConstructor.java @@ -32,6 +32,7 @@ package org.jf.dexlib2.analysis.reflection; import com.google.common.collect.ImmutableSet; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.analysis.reflection.util.ReflectionUtils; import org.jf.dexlib2.base.BaseMethodParameter; import org.jf.dexlib2.base.reference.BaseMethodReference; @@ -118,4 +119,8 @@ public class ReflectionConstructor extends BaseMethodReference implements Method @Nonnull @Override public String getReturnType() { return "V"; } + + @Nonnull @Override public Set getHiddenApiRestrictions() { + return ImmutableSet.of(); + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionField.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionField.java index c3a0e8c9..3f0578ad 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionField.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionField.java @@ -32,6 +32,7 @@ package org.jf.dexlib2.analysis.reflection; import com.google.common.collect.ImmutableSet; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.analysis.reflection.util.ReflectionUtils; import org.jf.dexlib2.base.reference.BaseFieldReference; import org.jf.dexlib2.iface.Annotation; @@ -72,4 +73,8 @@ public class ReflectionField extends BaseFieldReference implements Field { @Nonnull @Override public String getType() { return ReflectionUtils.javaToDexName(field.getType().getName()); } + + @Nonnull @Override public Set getHiddenApiRestrictions() { + return ImmutableSet.of(); + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionMethod.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionMethod.java index b7fb4756..b3a01253 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionMethod.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/reflection/ReflectionMethod.java @@ -32,6 +32,7 @@ package org.jf.dexlib2.analysis.reflection; import com.google.common.collect.ImmutableSet; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.analysis.reflection.util.ReflectionUtils; import org.jf.dexlib2.base.BaseMethodParameter; import org.jf.dexlib2.base.reference.BaseMethodReference; @@ -117,4 +118,8 @@ public class ReflectionMethod extends BaseMethodReference implements Method { @Nonnull @Override public String getReturnType() { return ReflectionUtils.javaToDexName(method.getReturnType().getName()); } + + @Nonnull @Override public Set getHiddenApiRestrictions() { + return ImmutableSet.of(); + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java index 6babd7e1..0989e9d0 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedClassDef.java @@ -39,6 +39,7 @@ import org.jf.dexlib2.dexbacked.raw.ClassDefItem; import org.jf.dexlib2.dexbacked.raw.TypeIdItem; import org.jf.dexlib2.dexbacked.util.AnnotationsDirectory; import org.jf.dexlib2.dexbacked.util.EncodedArrayItemIterator; +import org.jf.dexlib2.dexbacked.util.VariableSizeListIterator; import org.jf.dexlib2.dexbacked.util.VariableSizeLookaheadIterator; import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.reference.FieldReference; @@ -53,9 +54,14 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import static org.jf.dexlib2.writer.DexWriter.NO_OFFSET; + public class DexBackedClassDef extends BaseTypeReference implements ClassDef { + static final int NO_HIDDEN_API_RESTRICTIONS = 7; + @Nonnull public final DexBackedDexFile dexFile; private final int classDefOffset; + @Nullable private final HiddenApiRestrictionsReader hiddenApiRestrictionsReader; private final int staticFieldsOffset; private int instanceFieldsOffset = 0; @@ -70,7 +76,8 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { @Nullable private AnnotationsDirectory annotationsDirectory; public DexBackedClassDef(@Nonnull DexBackedDexFile dexFile, - int classDefOffset) { + int classDefOffset, + int hiddenApiRestrictionsOffset) { this.dexFile = dexFile; this.classDefOffset = classDefOffset; @@ -90,6 +97,11 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { staticFieldsOffset = reader.getOffset(); } + if (hiddenApiRestrictionsOffset != NO_OFFSET) { + hiddenApiRestrictionsReader = new HiddenApiRestrictionsReader(hiddenApiRestrictionsOffset); + } else { + hiddenApiRestrictionsReader = null; + } } @Nonnull @@ -154,13 +166,17 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { @Nonnull public Iterable getStaticFields(final boolean skipDuplicates) { if (staticFieldCount > 0) { - DexReader reader = dexFile.getDataBuffer().readerAt(staticFieldsOffset); + DexReader reader = dexFile.getDataBuffer().readerAt(staticFieldsOffset); final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory(); final int staticInitialValuesOffset = dexFile.getBuffer().readSmallUint(classDefOffset + ClassDefItem.STATIC_VALUES_OFFSET); final int fieldsStartOffset = reader.getOffset(); + + Iterator hiddenApiRestrictionIterator = hiddenApiRestrictionsReader == null ? + null : hiddenApiRestrictionsReader.getRestrictionsForStaticFields(); + return new Iterable() { @Nonnull @Override @@ -185,8 +201,14 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { return endOfData(); } + int hiddenApiRestrictions = NO_HIDDEN_API_RESTRICTIONS; + if (hiddenApiRestrictionIterator != null) { + hiddenApiRestrictions = hiddenApiRestrictionIterator.next(); + } + DexBackedField item = new DexBackedField(dexFile, reader, DexBackedClassDef.this, - previousIndex, staticInitialValueIterator, annotationIterator); + previousIndex, staticInitialValueIterator, annotationIterator, + hiddenApiRestrictions); FieldReference currentField = previousField; FieldReference nextField = ImmutableFieldReference.of(item); @@ -223,6 +245,9 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory(); final int fieldsStartOffset = reader.getOffset(); + Iterator hiddenApiRestrictionIterator = hiddenApiRestrictionsReader == null ? + null : hiddenApiRestrictionsReader.getRestrictionsForInstanceFields(); + return new Iterable() { @Nonnull @Override @@ -245,8 +270,13 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { return endOfData(); } + int hiddenApiRestrictions = NO_HIDDEN_API_RESTRICTIONS; + if (hiddenApiRestrictionIterator != null) { + hiddenApiRestrictions = hiddenApiRestrictionIterator.next(); + } + DexBackedField item = new DexBackedField(dexFile, reader, DexBackedClassDef.this, - previousIndex, annotationIterator); + previousIndex, annotationIterator, hiddenApiRestrictions); FieldReference currentField = previousField; FieldReference nextField = ImmutableFieldReference.of(item); @@ -291,6 +321,9 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory(); final int methodsStartOffset = reader.getOffset(); + Iterator hiddenApiRestrictionIterator = hiddenApiRestrictionsReader == null ? + null : hiddenApiRestrictionsReader.getRestrictionsForDirectMethods(); + return new Iterable() { @Nonnull @Override @@ -315,8 +348,14 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { return endOfData(); } + int hiddenApiRestrictions = NO_HIDDEN_API_RESTRICTIONS; + if (hiddenApiRestrictionIterator != null) { + hiddenApiRestrictions = hiddenApiRestrictionIterator.next(); + } + DexBackedMethod item = new DexBackedMethod(dexFile, reader, DexBackedClassDef.this, - previousIndex, methodAnnotationIterator, parameterAnnotationIterator); + previousIndex, methodAnnotationIterator, parameterAnnotationIterator, + hiddenApiRestrictions); MethodReference currentMethod = previousMethod; MethodReference nextMethod = ImmutableMethodReference.of(item); @@ -349,6 +388,9 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory(); final int methodsStartOffset = reader.getOffset(); + Iterator hiddenApiRestrictionIterator = hiddenApiRestrictionsReader == null ? + null : hiddenApiRestrictionsReader.getRestrictionsForVirtualMethods(); + return new Iterable() { final AnnotationsDirectory.AnnotationIterator methodAnnotationIterator = annotationsDirectory.getMethodAnnotationIterator(); @@ -372,8 +414,14 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { return endOfData(); } + int hiddenApiRestrictions = NO_HIDDEN_API_RESTRICTIONS; + if (hiddenApiRestrictionIterator != null) { + hiddenApiRestrictions = hiddenApiRestrictionIterator.next(); + } + DexBackedMethod item = new DexBackedMethod(dexFile, reader, DexBackedClassDef.this, - previousIndex, methodAnnotationIterator, parameterAnnotationIterator); + previousIndex, methodAnnotationIterator, parameterAnnotationIterator, + hiddenApiRestrictions); MethodReference currentMethod = previousMethod; MethodReference nextMethod = ImmutableMethodReference.of(item); @@ -506,4 +554,110 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef { } return size; } + + private class HiddenApiRestrictionsReader { + private final int startOffset; + + private int instanceFieldsStartOffset; + private int directMethodsStartOffset; + private int virtualMethodsStartOffset; + + public HiddenApiRestrictionsReader(int startOffset) { + this.startOffset = startOffset; + } + + private VariableSizeListIterator getRestrictionsForStaticFields() { + return new VariableSizeListIterator( + dexFile.getDataBuffer(), startOffset, staticFieldCount) { + @Override protected Integer readNextItem( + @Nonnull DexReader reader, int index) { + return reader.readSmallUleb128(); + } + + @Override public Integer next() { + if (nextIndex() == staticFieldCount) { + instanceFieldsStartOffset = getReaderOffset(); + } + return super.next(); + } + }; + } + + private int getInstanceFieldsStartOffset() { + if (instanceFieldsStartOffset == NO_OFFSET) { + DexReader reader = dexFile.getDataBuffer().readerAt(startOffset); + for (int i = 0; i < staticFieldCount; i++) { + reader.readSmallUleb128(); + } + instanceFieldsStartOffset = reader.getOffset(); + } + return instanceFieldsStartOffset; + } + + private Iterator getRestrictionsForInstanceFields() { + return new VariableSizeListIterator( + dexFile.getDataBuffer(), getInstanceFieldsStartOffset(), instanceFieldCount) { + @Override protected Integer readNextItem( + @Nonnull DexReader reader, int index) { + return reader.readSmallUleb128(); + } + + @Override public Integer next() { + if (nextIndex() == instanceFieldCount) { + directMethodsStartOffset = getReaderOffset(); + } + return super.next(); + } + }; + } + + private int getDirectMethodsStartOffset() { + if (directMethodsStartOffset == NO_OFFSET) { + DexReader reader = dexFile.getDataBuffer().readerAt(getInstanceFieldsStartOffset()); + for (int i = 0; i < instanceFieldCount; i++) { + reader.readSmallUleb128(); + } + directMethodsStartOffset = reader.getOffset(); + } + return directMethodsStartOffset; + } + + private Iterator getRestrictionsForDirectMethods() { + return new VariableSizeListIterator( + dexFile.getDataBuffer(), getDirectMethodsStartOffset(), directMethodCount) { + @Override protected Integer readNextItem( + @Nonnull DexReader reader, int index) { + return reader.readSmallUleb128(); + } + + @Override public Integer next() { + if (nextIndex() == directMethodCount) { + virtualMethodsStartOffset = getReaderOffset(); + } + return super.next(); + } + }; + } + + private int getVirtualMethodsStartOffset() { + if (virtualMethodsStartOffset == NO_OFFSET) { + DexReader reader = dexFile.getDataBuffer().readerAt(getDirectMethodsStartOffset()); + for (int i = 0; i < directMethodCount; i++) { + reader.readSmallUleb128(); + } + virtualMethodsStartOffset = reader.getOffset(); + } + return virtualMethodsStartOffset; + } + + private Iterator getRestrictionsForVirtualMethods() { + return new VariableSizeListIterator( + dexFile.getDataBuffer(), getVirtualMethodsStartOffset(), virtualMethodCount) { + @Override protected Integer readNextItem( + @Nonnull DexReader reader, int index) { + return reader.readSmallUleb128(); + } + }; + } + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java index 78d72896..95b7d946 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java @@ -50,6 +50,8 @@ import java.util.AbstractList; import java.util.List; import java.util.Set; +import static org.jf.dexlib2.writer.DexWriter.NO_OFFSET; + public class DexBackedDexFile implements DexFile { private final DexBuffer dexBuffer; @@ -70,6 +72,7 @@ public class DexBackedDexFile implements DexFile { private final int classCount; private final int classStartOffset; private final int mapOffset; + private final int hiddenApiRestrictionsOffset; protected DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) { dexBuffer = new DexBuffer(buf, offset); @@ -125,6 +128,13 @@ public class DexBackedDexFile implements DexFile { classCount = dexBuffer.readSmallUint(HeaderItem.CLASS_COUNT_OFFSET); classStartOffset = dexBuffer.readSmallUint(HeaderItem.CLASS_START_OFFSET); mapOffset = dexBuffer.readSmallUint(HeaderItem.MAP_OFFSET); + + MapItem mapItem = getMapItemForSection(ItemType.HIDDENAPI_CLASS_DATA_ITEM); + if (mapItem != null) { + hiddenApiRestrictionsOffset = mapItem.getOffset(); + } else { + hiddenApiRestrictionsOffset = NO_OFFSET; + } } /** @@ -444,7 +454,8 @@ public class DexBackedDexFile implements DexFile { private IndexedSection classSection = new IndexedSection() { @Override public DexBackedClassDef get(int index) { - return new DexBackedClassDef(DexBackedDexFile.this, getOffset(index)); + return new DexBackedClassDef(DexBackedDexFile.this, getOffset(index), + readHiddenApiRestrictionsOffset(index)); } @Override @@ -534,6 +545,22 @@ public class DexBackedDexFile implements DexFile { return new DexBackedMethodImplementation(dexFile, method, codeOffset); } + private int readHiddenApiRestrictionsOffset(int classIndex) { + if (hiddenApiRestrictionsOffset == NO_OFFSET) { + return NO_OFFSET; + } + + int offset = dexBuffer.readInt( + hiddenApiRestrictionsOffset + + HiddenApiClassDataItem.OFFSETS_LIST_OFFSET + + classIndex * HiddenApiClassDataItem.OFFSET_ITEM_SIZE); + if (offset == NO_OFFSET) { + return NO_OFFSET; + } + + return hiddenApiRestrictionsOffset + offset; + } + public static abstract class OptionalIndexedSection extends IndexedSection { /** * @param index The index of the item, or -1 for a null item. diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java index fcbeb5de..175b4c94 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedField.java @@ -31,6 +31,8 @@ package org.jf.dexlib2.dexbacked; +import com.google.common.collect.ImmutableSet; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseFieldReference; import org.jf.dexlib2.dexbacked.raw.FieldIdItem; import org.jf.dexlib2.dexbacked.reference.DexBackedFieldReference; @@ -43,6 +45,7 @@ import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.EnumSet; import java.util.Set; public class DexBackedField extends BaseFieldReference implements Field { @@ -56,6 +59,7 @@ public class DexBackedField extends BaseFieldReference implements Field { public final int fieldIndex; private final int startOffset; private final int initialValueOffset; + private final int hiddenApiRestrictions; private int fieldIdItemOffset; @@ -64,7 +68,8 @@ public class DexBackedField extends BaseFieldReference implements Field { @Nonnull DexBackedClassDef classDef, int previousFieldIndex, @Nonnull EncodedArrayItemIterator staticInitialValueIterator, - @Nonnull AnnotationsDirectory.AnnotationIterator annotationIterator) { + @Nonnull AnnotationsDirectory.AnnotationIterator annotationIterator, + int hiddenApiRestrictions) { this.dexFile = dexFile; this.classDef = classDef; @@ -78,13 +83,15 @@ public class DexBackedField extends BaseFieldReference implements Field { this.annotationSetOffset = annotationIterator.seekTo(fieldIndex); initialValueOffset = staticInitialValueIterator.getReaderOffset(); this.initialValue = staticInitialValueIterator.getNextOrNull(); + this.hiddenApiRestrictions = hiddenApiRestrictions; } public DexBackedField(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, @Nonnull DexBackedClassDef classDef, int previousFieldIndex, - @Nonnull AnnotationsDirectory.AnnotationIterator annotationIterator) { + @Nonnull AnnotationsDirectory.AnnotationIterator annotationIterator, + int hiddenApiRestrictions) { this.dexFile = dexFile; this.classDef = classDef; @@ -98,6 +105,7 @@ public class DexBackedField extends BaseFieldReference implements Field { this.annotationSetOffset = annotationIterator.seekTo(fieldIndex); initialValueOffset = 0; this.initialValue = null; + this.hiddenApiRestrictions = hiddenApiRestrictions; } @Nonnull @@ -124,6 +132,16 @@ public class DexBackedField extends BaseFieldReference implements Field { return AnnotationsDirectory.getAnnotations(dexFile, annotationSetOffset); } + @Nonnull + @Override + public Set getHiddenApiRestrictions() { + if (hiddenApiRestrictions == DexBackedClassDef.NO_HIDDEN_API_RESTRICTIONS) { + return ImmutableSet.of(); + } else { + return EnumSet.copyOf(HiddenApiRestriction.getAllFlags(hiddenApiRestrictions)); + } + } + /** * Skips the reader over the specified number of encoded_field structures * diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java index 14a6bdc4..f9ba78d2 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedMethod.java @@ -33,6 +33,7 @@ package org.jf.dexlib2.dexbacked; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.dexbacked.raw.MethodIdItem; import org.jf.dexlib2.dexbacked.raw.ProtoIdItem; @@ -48,6 +49,7 @@ import org.jf.util.AbstractForwardSequentialList; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.EnumSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -61,6 +63,7 @@ public class DexBackedMethod extends BaseMethodReference implements Method { private final int codeOffset; private final int parameterAnnotationSetListOffset; private final int methodAnnotationSetOffset; + private final int hiddenApiRestrictions; public final int methodIndex; private final int startOffset; @@ -72,7 +75,8 @@ public class DexBackedMethod extends BaseMethodReference implements Method { public DexBackedMethod(@Nonnull DexBackedDexFile dexFile, @Nonnull DexReader reader, @Nonnull DexBackedClassDef classDef, - int previousMethodIndex) { + int previousMethodIndex, + int hiddenApiRestrictions) { this.dexFile = dexFile; this.classDef = classDef; startOffset = reader.getOffset(); @@ -83,6 +87,7 @@ public class DexBackedMethod extends BaseMethodReference implements Method { this.methodIndex = methodIndexDiff + previousMethodIndex; this.accessFlags = reader.readSmallUleb128(); this.codeOffset = reader.readSmallUleb128(); + this.hiddenApiRestrictions = hiddenApiRestrictions; this.methodAnnotationSetOffset = 0; this.parameterAnnotationSetListOffset = 0; @@ -93,7 +98,8 @@ public class DexBackedMethod extends BaseMethodReference implements Method { @Nonnull DexBackedClassDef classDef, int previousMethodIndex, @Nonnull AnnotationsDirectory.AnnotationIterator methodAnnotationIterator, - @Nonnull AnnotationsDirectory.AnnotationIterator paramaterAnnotationIterator) { + @Nonnull AnnotationsDirectory.AnnotationIterator paramaterAnnotationIterator, + int hiddenApiRestrictions) { this.dexFile = dexFile; this.classDef = classDef; startOffset = reader.getOffset(); @@ -104,6 +110,7 @@ public class DexBackedMethod extends BaseMethodReference implements Method { this.methodIndex = methodIndexDiff + previousMethodIndex; this.accessFlags = reader.readSmallUleb128(); this.codeOffset = reader.readSmallUleb128(); + this.hiddenApiRestrictions = hiddenApiRestrictions; this.methodAnnotationSetOffset = methodAnnotationIterator.seekTo(methodIndex); this.parameterAnnotationSetListOffset = paramaterAnnotationIterator.seekTo(methodIndex); @@ -188,6 +195,16 @@ public class DexBackedMethod extends BaseMethodReference implements Method { return AnnotationsDirectory.getAnnotations(dexFile, methodAnnotationSetOffset); } + @Nonnull + @Override + public Set getHiddenApiRestrictions() { + if (hiddenApiRestrictions == DexBackedClassDef.NO_HIDDEN_API_RESTRICTIONS) { + return ImmutableSet.of(); + } else { + return EnumSet.copyOf(HiddenApiRestriction.getAllFlags(hiddenApiRestrictions)); + } + } + @Nullable @Override public DexBackedMethodImplementation getImplementation() { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBuffer.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBuffer.java index 80f3f8bc..50c45ca0 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBuffer.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBuffer.java @@ -141,7 +141,7 @@ public class DexBuffer { } @Nonnull - public DexReader readerAt(int offset) { + public DexReader readerAt(int offset) { return new DexReader(this, offset); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HiddenApiClassDataItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HiddenApiClassDataItem.java new file mode 100644 index 00000000..898f4d5d --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HiddenApiClassDataItem.java @@ -0,0 +1,136 @@ +/* + * Copyright 2013, 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.dexbacked.raw; + +import org.jf.dexlib2.HiddenApiRestriction; +import org.jf.dexlib2.dexbacked.DexBuffer; +import org.jf.dexlib2.dexbacked.DexReader; +import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator; +import org.jf.dexlib2.iface.ClassDef; +import org.jf.dexlib2.iface.Field; +import org.jf.dexlib2.iface.Method; +import org.jf.dexlib2.util.AnnotatedBytes; +import org.jf.dexlib2.util.ReferenceUtil; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class HiddenApiClassDataItem { + public static final int SIZE_OFFSET = 0x0; + public static final int OFFSETS_LIST_OFFSET = 0x4; + + public static final int OFFSET_ITEM_SIZE = 0x4; + + + @Nonnull + public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) { + return new SectionAnnotator(annotator, mapItem) { + @Nonnull @Override public String getItemName() { + return "hiddenapi_class_data_item"; + } + + @Override + protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { + int startOffset = out.getCursor(); + + out.annotate(4, "size = 0x%x", dexFile.getDataBuffer().readSmallUint(out.getCursor())); + + int index = 0; + for (ClassDef classDef : dexFile.getClasses()) { + out.annotate(0, "[%d] %s", index, ReferenceUtil.getReferenceString(classDef)); + out.indent(); + + int offset = dexFile.getDataBuffer().readSmallUint(out.getCursor()); + if (offset == 0) { + out.annotate(4, "offset = 0x%x", offset); + } else { + out.annotate(4, "offset = 0x%x (absolute offset: 0x%x)", offset, startOffset + offset); + } + + int nextOffset = out.getCursor(); + if (offset > 0) { + out.deindent(); + + out.moveTo(startOffset + offset); + + DexReader reader = dexFile.getBuffer().readerAt(out.getCursor()); + + for (Field field : classDef.getStaticFields()) { + out.annotate(0, "%s:", ReferenceUtil.getReferenceString(field)); + out.indent(); + int restrictions = reader.readSmallUleb128(); + out.annotateTo(reader.getOffset(), "restriction = 0x%x: %s", + restrictions, + HiddenApiRestriction.formatHiddenRestrictions(restrictions)); + out.deindent(); + } + for (Field field : classDef.getInstanceFields()) { + out.annotate(0, "%s:", ReferenceUtil.getReferenceString(field)); + out.indent(); + int restrictions = reader.readSmallUleb128(); + out.annotateTo(reader.getOffset(), "restriction = 0x%x: %s", + restrictions, + HiddenApiRestriction.formatHiddenRestrictions(restrictions)); + out.deindent(); + } + for (Method method : classDef.getDirectMethods()) { + out.annotate(0, "%s:", ReferenceUtil.getReferenceString(method)); + out.indent(); + int restrictions = reader.readSmallUleb128(); + out.annotateTo(reader.getOffset(), "restriction = 0x%x: %s", + restrictions, + HiddenApiRestriction.formatHiddenRestrictions(restrictions)); + out.deindent(); + } + for (Method method : classDef.getVirtualMethods()) { + out.annotate(0, "%s:", ReferenceUtil.getReferenceString(method)); + out.indent(); + int restrictions = reader.readSmallUleb128(); + out.annotateTo(reader.getOffset(), "restriction = 0x%x: %s", + restrictions, + HiddenApiRestriction.formatHiddenRestrictions(restrictions)); + out.deindent(); + } + + out.indent(); + } + + out.moveTo(nextOffset); + + out.deindent(); + + index++; + } + } + }; + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/ItemType.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/ItemType.java index 99564a3e..0f9a5dfa 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/ItemType.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/ItemType.java @@ -54,6 +54,7 @@ public class ItemType { public static final int ANNOTATION_ITEM = 0x2004; public static final int ENCODED_ARRAY_ITEM = 0x2005; public static final int ANNOTATION_DIRECTORY_ITEM = 0x2006; + public static final int HIDDENAPI_CLASS_DATA_ITEM = 0xF000; @Nonnull public static String getItemTypeName(int itemType) { @@ -78,6 +79,7 @@ public class ItemType { case ANNOTATION_ITEM: return "annotation_item"; case ENCODED_ARRAY_ITEM: return "encoded_array_item"; case ANNOTATION_DIRECTORY_ITEM: return "annotation_directory_item"; + case HIDDENAPI_CLASS_DATA_ITEM: return "hiddenapi_class_data_item"; default: return "unknown dex item type"; } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java index 0f570cb4..f463c712 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java @@ -78,7 +78,9 @@ public class DexAnnotator extends AnnotatedBytes { ItemType.STRING_DATA_ITEM, ItemType.ANNOTATION_ITEM, ItemType.ENCODED_ARRAY_ITEM, - ItemType.ANNOTATION_DIRECTORY_ITEM + ItemType.ANNOTATION_DIRECTORY_ITEM, + + ItemType.HIDDENAPI_CLASS_DATA_ITEM }; for (int i=0; i implements ListIterator { - @Nonnull private DexReader reader; + @Nonnull private DexReader reader; protected final int size; private final int startOffset; @@ -58,7 +58,7 @@ public abstract class VariableSizeListIterator implements ListIterator { * @param index The index of the item being read. This is guaranteed to be less than {@code size} * @return The item that was read */ - protected abstract T readNextItem(@Nonnull DexReader reader, int index); + protected abstract T readNextItem(@Nonnull DexReader reader, int index); public int getReaderOffset() { return reader.getOffset(); diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/Field.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/Field.java index 0091929b..179520f6 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/iface/Field.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/Field.java @@ -31,6 +31,7 @@ package org.jf.dexlib2.iface; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.value.EncodedValue; @@ -93,4 +94,14 @@ public interface Field extends FieldReference, Member { * @return A set of the annotations that are applied to this field */ @Override @Nonnull Set getAnnotations(); + + /** + * Gets the hidden api restrictions for this field. + * + * This will contain at most 1 normal flag (with isDomainSpecificApiFlag() = false), and 1 + * domain-specific api flag (with isDomainSpecificApiFlag() = true) + * + * @return A set of the hidden api restrictions for this field. + */ + @Nonnull Set getHiddenApiRestrictions(); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/Member.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/Member.java index 343c4032..bf57b849 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/iface/Member.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/Member.java @@ -31,7 +31,10 @@ package org.jf.dexlib2.iface; +import org.jf.dexlib2.HiddenApiRestriction; + import javax.annotation.Nonnull; +import java.util.Set; /** * This class represents a generic class member @@ -60,4 +63,14 @@ public interface Member extends Annotatable { * @return The access flags for this member */ int getAccessFlags(); + + /** + * Gets the hidden api restrictions for this member. + * + * This will contain at most 1 normal flag (with isDomainSpecificApiFlag() = false), and 1 + * domain-specific api flag (with isDomainSpecificApiFlag() = true) + * + * @return A set of the hidden api restrictions for this member. + */ + @Nonnull Set getHiddenApiRestrictions(); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/iface/Method.java b/dexlib2/src/main/java/org/jf/dexlib2/iface/Method.java index 5d3796ff..3a3d4df2 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/iface/Method.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/iface/Method.java @@ -31,6 +31,7 @@ package org.jf.dexlib2.iface; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.iface.reference.MethodReference; import javax.annotation.Nonnull; @@ -97,6 +98,16 @@ public interface Method extends MethodReference, Member { */ @Override @Nonnull Set getAnnotations(); + /** + * Gets the hidden api restrictions for this method. + * + * This will contain at most 1 normal flag (with isDomainSpecificApiFlag() = false), and 1 + * domain-specific api flag (with isDomainSpecificApiFlag() = true) + * + * @return A set of the hidden api restrictions for this method. + */ + @Nonnull Set getHiddenApiRestrictions(); + /** * Gets a MethodImplementation object that defines the implementation of the method. * diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableField.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableField.java index f60ebf9d..0202be92 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableField.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableField.java @@ -34,6 +34,7 @@ package org.jf.dexlib2.immutable; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Ordering; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseFieldReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Field; @@ -46,6 +47,7 @@ import org.jf.util.ImmutableUtils; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collection; +import java.util.Set; public class ImmutableField extends BaseFieldReference implements Field { @Nonnull protected final String definingClass; @@ -54,19 +56,23 @@ public class ImmutableField extends BaseFieldReference implements Field { protected final int accessFlags; @Nullable protected final ImmutableEncodedValue initialValue; @Nonnull protected final ImmutableSet annotations; + @Nonnull protected final ImmutableSet hiddenApiRestrictions; public ImmutableField(@Nonnull String definingClass, @Nonnull String name, @Nonnull String type, int accessFlags, @Nullable EncodedValue initialValue, - @Nullable Collection annotations) { + @Nullable Collection annotations, + @Nullable Set hiddenApiRestrictions) { this.definingClass = definingClass; this.name = name; this.type = type; this.accessFlags = accessFlags; this.initialValue = ImmutableEncodedValueFactory.ofNullable(initialValue); this.annotations = ImmutableAnnotation.immutableSetOf(annotations); + this.hiddenApiRestrictions = + hiddenApiRestrictions == null ? ImmutableSet.of() : ImmutableSet.copyOf(hiddenApiRestrictions); } public ImmutableField(@Nonnull String definingClass, @@ -74,13 +80,15 @@ public class ImmutableField extends BaseFieldReference implements Field { @Nonnull String type, int accessFlags, @Nullable ImmutableEncodedValue initialValue, - @Nullable ImmutableSet annotations) { + @Nullable ImmutableSet annotations, + @Nullable ImmutableSet hiddenApiRestrictions) { this.definingClass = definingClass; this.name = name; this.type = type; this.accessFlags = accessFlags; this.initialValue = initialValue; this.annotations = ImmutableUtils.nullToEmptySet(annotations); + this.hiddenApiRestrictions = ImmutableUtils.nullToEmptySet(hiddenApiRestrictions); } public static ImmutableField of(Field field) { @@ -93,7 +101,8 @@ public class ImmutableField extends BaseFieldReference implements Field { field.getType(), field.getAccessFlags(), field.getInitialValue(), - field.getAnnotations()); + field.getAnnotations(), + field.getHiddenApiRestrictions()); } @Nonnull @Override public String getDefiningClass() { return definingClass; } @@ -102,6 +111,7 @@ public class ImmutableField extends BaseFieldReference implements Field { @Override public int getAccessFlags() { return accessFlags; } @Override public EncodedValue getInitialValue() { return initialValue;} @Nonnull @Override public ImmutableSet getAnnotations() { return annotations; } + @Nonnull @Override public Set getHiddenApiRestrictions() { return hiddenApiRestrictions; } @Nonnull public static ImmutableSortedSet immutableSetOf(@Nullable Iterable list) { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableMethod.java b/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableMethod.java index 8d8d0692..cc1f02cd 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableMethod.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/immutable/ImmutableMethod.java @@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Ordering; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Method; @@ -54,6 +55,7 @@ public class ImmutableMethod extends BaseMethodReference implements Method { @Nonnull protected final String returnType; protected final int accessFlags; @Nonnull protected final ImmutableSet annotations; + @Nonnull protected final ImmutableSet hiddenApiRestrictions; @Nullable protected final ImmutableMethodImplementation methodImplementation; public ImmutableMethod(@Nonnull String definingClass, @@ -62,6 +64,7 @@ public class ImmutableMethod extends BaseMethodReference implements Method { @Nonnull String returnType, int accessFlags, @Nullable Set annotations, + @Nullable Set hiddenApiRestrictions, @Nullable MethodImplementation methodImplementation) { this.definingClass = definingClass; this.name = name; @@ -69,6 +72,8 @@ public class ImmutableMethod extends BaseMethodReference implements Method { this.returnType = returnType; this.accessFlags = accessFlags; this.annotations = ImmutableAnnotation.immutableSetOf(annotations); + this.hiddenApiRestrictions = + hiddenApiRestrictions == null ? ImmutableSet.of() : ImmutableSet.copyOf(hiddenApiRestrictions); this.methodImplementation = ImmutableMethodImplementation.of(methodImplementation); } @@ -78,6 +83,7 @@ public class ImmutableMethod extends BaseMethodReference implements Method { @Nonnull String returnType, int accessFlags, @Nullable ImmutableSet annotations, + @Nullable ImmutableSet hiddenApiRestrictions, @Nullable ImmutableMethodImplementation methodImplementation) { this.definingClass = definingClass; this.name = name; @@ -85,6 +91,7 @@ public class ImmutableMethod extends BaseMethodReference implements Method { this.returnType = returnType; this.accessFlags = accessFlags; this.annotations = ImmutableUtils.nullToEmptySet(annotations); + this.hiddenApiRestrictions = ImmutableUtils.nullToEmptySet(hiddenApiRestrictions); this.methodImplementation = methodImplementation; } @@ -99,6 +106,7 @@ public class ImmutableMethod extends BaseMethodReference implements Method { method.getReturnType(), method.getAccessFlags(), method.getAnnotations(), + method.getHiddenApiRestrictions(), method.getImplementation()); } @@ -109,6 +117,7 @@ public class ImmutableMethod extends BaseMethodReference implements Method { @Override @Nonnull public String getReturnType() { return returnType; } @Override public int getAccessFlags() { return accessFlags; } @Override @Nonnull public ImmutableSet getAnnotations() { return annotations; } + @Nonnull @Override public Set getHiddenApiRestrictions() { return hiddenApiRestrictions; } @Override @Nullable public ImmutableMethodImplementation getImplementation() { return methodImplementation; } @Nonnull diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldRewriter.java index 1e5eb6d6..42ce79ac 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldRewriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/FieldRewriter.java @@ -31,6 +31,7 @@ package org.jf.dexlib2.rewriter; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseFieldReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Field; @@ -81,5 +82,9 @@ public class FieldRewriter implements Rewriter { @Nonnull public Set getAnnotations() { return RewriterUtils.rewriteSet(rewriters.getAnnotationRewriter(), field.getAnnotations()); } + + @Nonnull @Override public Set getHiddenApiRestrictions() { + return field.getHiddenApiRestrictions(); + } } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodRewriter.java index 01af6e24..fa1b737a 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodRewriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/MethodRewriter.java @@ -31,6 +31,7 @@ package org.jf.dexlib2.rewriter; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Method; @@ -92,6 +93,10 @@ public class MethodRewriter implements Rewriter { return RewriterUtils.rewriteSet(rewriters.getAnnotationRewriter(), method.getAnnotations()); } + @Nonnull @Override public Set getHiddenApiRestrictions() { + return method.getHiddenApiRestrictions(); + } + @Override @Nullable public MethodImplementation getImplementation() { return RewriterUtils.rewriteNullable(rewriters.getMethodImplementationRewriter(), method.getImplementation()); diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderField.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderField.java index c5185cde..4b8c2d0c 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderField.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderField.java @@ -31,12 +31,15 @@ package org.jf.dexlib2.writer.builder; +import com.google.common.collect.ImmutableSet; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseFieldReference; import org.jf.dexlib2.iface.Field; import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Set; public class BuilderField extends BaseFieldReference implements Field { @Nonnull final BuilderFieldReference fieldReference; @@ -77,4 +80,8 @@ public class BuilderField extends BaseFieldReference implements Field { @Nonnull @Override public String getType() { return fieldReference.fieldType.getType(); } + + @Nonnull @Override public Set getHiddenApiRestrictions() { + return ImmutableSet.of(); + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethod.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethod.java index dc48c98c..217605f7 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethod.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderMethod.java @@ -31,6 +31,8 @@ package org.jf.dexlib2.writer.builder; +import com.google.common.collect.ImmutableSet; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.Method; import org.jf.dexlib2.iface.MethodImplementation; @@ -39,6 +41,7 @@ import org.jf.dexlib2.writer.DexWriter; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; +import java.util.Set; public class BuilderMethod extends BaseMethodReference implements Method { @Nonnull final BuilderMethodReference methodReference; @@ -69,5 +72,10 @@ public class BuilderMethod extends BaseMethodReference implements Method { @Override @Nonnull public List getParameters() { return parameters; } @Override public int getAccessFlags() { return accessFlags; } @Override @Nonnull public BuilderAnnotationSet getAnnotations() { return annotations; } + + @Nonnull @Override public Set getHiddenApiRestrictions() { + return ImmutableSet.of(); + } + @Override @Nullable public MethodImplementation getImplementation() { return methodImplementation; } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolMethod.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolMethod.java index f5d2c5c1..e7e73a57 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolMethod.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolMethod.java @@ -32,6 +32,7 @@ package org.jf.dexlib2.writer.pool; import com.google.common.base.Function; +import org.jf.dexlib2.HiddenApiRestriction; import org.jf.dexlib2.base.reference.BaseMethodReference; import org.jf.dexlib2.iface.Annotation; import org.jf.dexlib2.iface.Method; @@ -87,6 +88,10 @@ class PoolMethod extends BaseMethodReference implements Method { return method.getAnnotations(); } + @Nonnull @Override public Set getHiddenApiRestrictions() { + return method.getHiddenApiRestrictions(); + } + @Override @Nullable public MethodImplementation getImplementation() { return method.getImplementation(); } 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 c117f03b..cef54fb5 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/CustomMethodInlineTableTest.java @@ -60,7 +60,7 @@ public class CustomMethodInlineTableTest { ImmutableMethodImplementation methodImpl = new ImmutableMethodImplementation(1, instructions, null, null); ImmutableMethod method = new ImmutableMethod("Lblah;", "blah", null, "V", AccessFlags.PUBLIC.getValue(), null, - methodImpl); + null, methodImpl); ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, null, null, ImmutableList.of(method)); @@ -91,7 +91,7 @@ public class CustomMethodInlineTableTest { ImmutableMethodImplementation methodImpl = new ImmutableMethodImplementation(1, instructions, null, null); ImmutableMethod method = new ImmutableMethod("Lblah;", "blah", null, "V", AccessFlags.STATIC.getValue(), null, - methodImpl); + null, methodImpl); ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, null, ImmutableList.of(method), null); @@ -122,7 +122,7 @@ public class CustomMethodInlineTableTest { ImmutableMethodImplementation methodImpl = new ImmutableMethodImplementation(1, instructions, null, null); ImmutableMethod method = new ImmutableMethod("Lblah;", "blah", null, "V", AccessFlags.PRIVATE.getValue(), null, - methodImpl); + null, methodImpl); ClassDef classDef = new ImmutableClassDef("Lblah;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, null, ImmutableList.of(method), null); diff --git a/dexlib2/src/test/java/org/jf/dexlib2/analysis/MethodAnalyzerTest.java b/dexlib2/src/test/java/org/jf/dexlib2/analysis/MethodAnalyzerTest.java index 215ba179..ae8281ac 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/analysis/MethodAnalyzerTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/analysis/MethodAnalyzerTest.java @@ -76,7 +76,7 @@ public class MethodAnalyzerTest { Method method = new ImmutableMethod("Lmain;", "narrowing", Collections.singletonList(new ImmutableMethodParameter("Ljava/lang/Object;", null, null)), "V", - AccessFlags.PUBLIC.getValue(), null, methodImplementation); + AccessFlags.PUBLIC.getValue(), null, null, methodImplementation); ClassDef classDef = new ImmutableClassDef("Lmain;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, Collections.singletonList(method)); DexFile dexFile = new ImmutableDexFile(forArtVersion(56), Collections.singletonList(classDef)); @@ -107,7 +107,7 @@ public class MethodAnalyzerTest { Method method = new ImmutableMethod("Lmain;", "narrowing", Collections.singletonList(new ImmutableMethodParameter("Ljava/lang/Object;", null, null)), "V", - AccessFlags.PUBLIC.getValue(), null, methodImplementation); + AccessFlags.PUBLIC.getValue(), null, null, methodImplementation); ClassDef classDef = new ImmutableClassDef("Lmain;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, Collections.singletonList(method)); DexFile dexFile = new ImmutableDexFile(Opcodes.forApi(19), Collections.singletonList(classDef)); @@ -139,7 +139,7 @@ public class MethodAnalyzerTest { Method method = new ImmutableMethod("Lmain;", "narrowing", Collections.singletonList(new ImmutableMethodParameter("Ljava/lang/Object;", null, null)), "V", - AccessFlags.PUBLIC.getValue(), null, methodImplementation); + AccessFlags.PUBLIC.getValue(), null, null, methodImplementation); ClassDef classDef = new ImmutableClassDef("Lmain;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, Collections.singletonList(method)); DexFile dexFile = new ImmutableDexFile(forArtVersion(56), Collections.singletonList(classDef)); @@ -170,7 +170,7 @@ public class MethodAnalyzerTest { Method method = new ImmutableMethod("Lmain;", "narrowing", Collections.singletonList(new ImmutableMethodParameter("Ljava/lang/Object;", null, null)), "V", - AccessFlags.PUBLIC.getValue(), null, methodImplementation); + AccessFlags.PUBLIC.getValue(), null, null, methodImplementation); ClassDef classDef = new ImmutableClassDef("Lmain;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, Collections.singletonList(method)); DexFile dexFile = new ImmutableDexFile(Opcodes.getDefault(), Collections.singletonList(classDef)); @@ -203,7 +203,7 @@ public class MethodAnalyzerTest { Method method = new ImmutableMethod("Lmain;", "narrowing", Collections.singletonList(new ImmutableMethodParameter("Ljava/lang/Object;", null, null)), "V", - AccessFlags.PUBLIC.getValue(), null, methodImplementation); + AccessFlags.PUBLIC.getValue(), null, null, methodImplementation); ClassDef classDef = new ImmutableClassDef("Lmain;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, Collections.singletonList(method)); DexFile dexFile = new ImmutableDexFile(forArtVersion(56), Collections.singletonList(classDef)); @@ -238,7 +238,7 @@ public class MethodAnalyzerTest { Method method = new ImmutableMethod("Lmain;", "narrowing", Collections.singletonList(new ImmutableMethodParameter("Ljava/lang/Object;", null, null)), "V", - AccessFlags.PUBLIC.getValue(), null, methodImplementation); + AccessFlags.PUBLIC.getValue(), null, null, methodImplementation); ClassDef classDef = new ImmutableClassDef("Lmain;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, null, null, Collections.singletonList(method)); DexFile dexFile = new ImmutableDexFile(Opcodes.getDefault(), Collections.singletonList(classDef)); diff --git a/dexlib2/src/test/java/org/jf/dexlib2/pool/RollbackTest.java b/dexlib2/src/test/java/org/jf/dexlib2/pool/RollbackTest.java index 0241eb17..3f433f0a 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/pool/RollbackTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/pool/RollbackTest.java @@ -56,23 +56,23 @@ public class RollbackTest { ClassDef class1 = new ImmutableClassDef("Lcls1;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, Lists.newArrayList(new ImmutableAnnotation(AnnotationVisibility.RUNTIME, "Lannotation;", null)), Lists.newArrayList( - new ImmutableField("Lcls1;", "field1", "I", AccessFlags.PUBLIC.getValue(), null, null) + new ImmutableField("Lcls1;", "field1", "I", AccessFlags.PUBLIC.getValue(), null, null, null) ), Lists.newArrayList( new ImmutableMethod("Lcls1", "method1", Lists.newArrayList(new ImmutableMethodParameter("L", null, null)), "V", - AccessFlags.PUBLIC.getValue(), null, null)) + AccessFlags.PUBLIC.getValue(), null, null, null)) ); ClassDef class2 = new ImmutableClassDef("Lcls2;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null, Lists.newArrayList(new ImmutableAnnotation(AnnotationVisibility.RUNTIME, "Lannotation2;", null)), Lists.newArrayList( - new ImmutableField("Lcls2;", "field2", "D", AccessFlags.PUBLIC.getValue(), null, null) + new ImmutableField("Lcls2;", "field2", "D", AccessFlags.PUBLIC.getValue(), null, null, null) ), Lists.newArrayList( new ImmutableMethod("Lcls2;", "method2", Lists.newArrayList(new ImmutableMethodParameter("D", null, null)), "V", - AccessFlags.PUBLIC.getValue(), null, null)) + AccessFlags.PUBLIC.getValue(), null, null, null)) ); DexBackedDexFile dexFile1; diff --git a/dexlib2/src/test/java/org/jf/dexlib2/writer/CallSiteTest.java b/dexlib2/src/test/java/org/jf/dexlib2/writer/CallSiteTest.java index c909fb28..e5a0763a 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/writer/CallSiteTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/writer/CallSiteTest.java @@ -70,7 +70,7 @@ public class CallSiteTest { null, null, Lists.newArrayList( new ImmutableMethod("Lcls1", "method1", - ImmutableList.of(), "V", AccessFlags.PUBLIC.getValue(), null, + ImmutableList.of(), "V", AccessFlags.PUBLIC.getValue(), null, null, new ImmutableMethodImplementation(10, ImmutableList.of( new ImmutableInstruction35c(Opcode.INVOKE_CUSTOM, 0, 0, 0, 0, 0, 0, new ImmutableCallSiteReference("call_site_1",