1/* 2 * Copyright 2012, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32package org.jf.dexlib2.dexbacked; 33 34import com.google.common.collect.ImmutableList; 35import com.google.common.collect.Iterators; 36import org.jf.dexlib2.base.reference.BaseMethodReference; 37import org.jf.dexlib2.dexbacked.raw.MethodIdItem; 38import org.jf.dexlib2.dexbacked.raw.ProtoIdItem; 39import org.jf.dexlib2.dexbacked.raw.TypeListItem; 40import org.jf.dexlib2.dexbacked.util.AnnotationsDirectory; 41import org.jf.dexlib2.dexbacked.util.FixedSizeList; 42import org.jf.dexlib2.dexbacked.util.ParameterIterator; 43import org.jf.dexlib2.iface.Annotation; 44import org.jf.dexlib2.iface.Method; 45import org.jf.dexlib2.iface.MethodParameter; 46import org.jf.util.AbstractForwardSequentialList; 47 48import javax.annotation.Nonnull; 49import javax.annotation.Nullable; 50import java.util.Iterator; 51import java.util.List; 52import java.util.Set; 53 54public class DexBackedMethod extends BaseMethodReference implements Method { 55 @Nonnull public final DexBackedDexFile dexFile; 56 @Nonnull public final DexBackedClassDef classDef; 57 58 public final int accessFlags; 59 60 private final int codeOffset; 61 private final int parameterAnnotationSetListOffset; 62 private final int methodAnnotationSetOffset; 63 64 public final int methodIndex; 65 66 private int methodIdItemOffset; 67 private int protoIdItemOffset; 68 private int parametersOffset = -1; 69 70 public DexBackedMethod(@Nonnull DexReader reader, 71 @Nonnull DexBackedClassDef classDef, 72 int previousMethodIndex) { 73 this.dexFile = reader.dexBuf; 74 this.classDef = classDef; 75 76 // large values may be used for the index delta, which cause the cumulative index to overflow upon 77 // addition, effectively allowing out of order entries. 78 int methodIndexDiff = reader.readLargeUleb128(); 79 this.methodIndex = methodIndexDiff + previousMethodIndex; 80 this.accessFlags = reader.readSmallUleb128(); 81 this.codeOffset = reader.readSmallUleb128(); 82 83 this.methodAnnotationSetOffset = 0; 84 this.parameterAnnotationSetListOffset = 0; 85 } 86 87 public DexBackedMethod(@Nonnull DexReader reader, 88 @Nonnull DexBackedClassDef classDef, 89 int previousMethodIndex, 90 @Nonnull AnnotationsDirectory.AnnotationIterator methodAnnotationIterator, 91 @Nonnull AnnotationsDirectory.AnnotationIterator paramaterAnnotationIterator) { 92 this.dexFile = reader.dexBuf; 93 this.classDef = classDef; 94 95 // large values may be used for the index delta, which cause the cumulative index to overflow upon 96 // addition, effectively allowing out of order entries. 97 int methodIndexDiff = reader.readLargeUleb128(); 98 this.methodIndex = methodIndexDiff + previousMethodIndex; 99 this.accessFlags = reader.readSmallUleb128(); 100 this.codeOffset = reader.readSmallUleb128(); 101 102 this.methodAnnotationSetOffset = methodAnnotationIterator.seekTo(methodIndex); 103 this.parameterAnnotationSetListOffset = paramaterAnnotationIterator.seekTo(methodIndex); 104 } 105 106 public int getMethodIndex() { return methodIndex; } 107 @Nonnull @Override public String getDefiningClass() { return classDef.getType(); } 108 @Override public int getAccessFlags() { return accessFlags; } 109 110 @Nonnull 111 @Override 112 public String getName() { 113 return dexFile.getString(dexFile.readSmallUint(getMethodIdItemOffset() + MethodIdItem.NAME_OFFSET)); 114 } 115 116 @Nonnull 117 @Override 118 public String getReturnType() { 119 return dexFile.getType(dexFile.readSmallUint(getProtoIdItemOffset() + ProtoIdItem.RETURN_TYPE_OFFSET)); 120 } 121 122 @Nonnull 123 @Override 124 public List<? extends MethodParameter> getParameters() { 125 int parametersOffset = getParametersOffset(); 126 if (parametersOffset > 0) { 127 final List<String> parameterTypes = getParameterTypes(); 128 129 return new AbstractForwardSequentialList<MethodParameter>() { 130 @Nonnull @Override public Iterator<MethodParameter> iterator() { 131 return new ParameterIterator(parameterTypes, 132 getParameterAnnotations(), 133 getParameterNames()); 134 } 135 136 @Override public int size() { 137 return parameterTypes.size(); 138 } 139 }; 140 } 141 return ImmutableList.of(); 142 } 143 144 @Nonnull 145 public List<? extends Set<? extends DexBackedAnnotation>> getParameterAnnotations() { 146 return AnnotationsDirectory.getParameterAnnotations(dexFile, parameterAnnotationSetListOffset); 147 } 148 149 @Nonnull 150 public Iterator<String> getParameterNames() { 151 DexBackedMethodImplementation methodImpl = getImplementation(); 152 if (methodImpl != null) { 153 return methodImpl.getParameterNames(null); 154 } 155 return Iterators.emptyIterator(); 156 } 157 158 @Nonnull 159 @Override 160 public List<String> getParameterTypes() { 161 final int parametersOffset = getParametersOffset(); 162 if (parametersOffset > 0) { 163 final int parameterCount = dexFile.readSmallUint(parametersOffset + TypeListItem.SIZE_OFFSET); 164 final int paramListStart = parametersOffset + TypeListItem.LIST_OFFSET; 165 return new FixedSizeList<String>() { 166 @Nonnull 167 @Override 168 public String readItem(final int index) { 169 return dexFile.getType(dexFile.readUshort(paramListStart + 2*index)); 170 } 171 @Override public int size() { return parameterCount; } 172 }; 173 } 174 return ImmutableList.of(); 175 } 176 177 @Nonnull 178 @Override 179 public Set<? extends Annotation> getAnnotations() { 180 return AnnotationsDirectory.getAnnotations(dexFile, methodAnnotationSetOffset); 181 } 182 183 @Nullable 184 @Override 185 public DexBackedMethodImplementation getImplementation() { 186 if (codeOffset > 0) { 187 return new DexBackedMethodImplementation(dexFile, this, codeOffset); 188 } 189 return null; 190 } 191 192 private int getMethodIdItemOffset() { 193 if (methodIdItemOffset == 0) { 194 methodIdItemOffset = dexFile.getMethodIdItemOffset(methodIndex); 195 } 196 return methodIdItemOffset; 197 } 198 199 private int getProtoIdItemOffset() { 200 if (protoIdItemOffset == 0) { 201 int protoIndex = dexFile.readUshort(getMethodIdItemOffset() + MethodIdItem.PROTO_OFFSET); 202 protoIdItemOffset = dexFile.getProtoIdItemOffset(protoIndex); 203 } 204 return protoIdItemOffset; 205 } 206 207 private int getParametersOffset() { 208 if (parametersOffset == -1) { 209 parametersOffset = dexFile.readSmallUint(getProtoIdItemOffset() + ProtoIdItem.PARAMETERS_OFFSET); 210 } 211 return parametersOffset; 212 } 213 214 /** 215 * Skips the reader over the specified number of encoded_method structures 216 * 217 * @param reader The reader to skip 218 * @param count The number of encoded_method structures to skip over 219 */ 220 public static void skipMethods(@Nonnull DexReader reader, int count) { 221 for (int i=0; i<count; i++) { 222 reader.skipUleb128(); 223 reader.skipUleb128(); 224 reader.skipUleb128(); 225 } 226 } 227} 228