DexBackedMethod.java revision 0acc897cddb531d60bc61f5a5cbc872e40b4df58
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.util.AnnotationsDirectory; 38import org.jf.dexlib2.dexbacked.util.FixedSizeList; 39import org.jf.dexlib2.dexbacked.util.ParameterIterator; 40import org.jf.dexlib2.iface.Annotation; 41import org.jf.dexlib2.iface.Method; 42import org.jf.dexlib2.iface.MethodParameter; 43import org.jf.util.AbstractForwardSequentialList; 44 45import javax.annotation.Nonnull; 46import javax.annotation.Nullable; 47import java.util.Iterator; 48import java.util.List; 49import java.util.Set; 50 51public class DexBackedMethod extends BaseMethodReference implements Method { 52 @Nonnull public final DexBuffer dexBuf; 53 @Nonnull public final DexBackedClassDef classDef; 54 55 public final int accessFlags; 56 57 private final int codeOffset; 58 private final int parameterAnnotationSetListOffset; 59 private final int methodAnnotationSetOffset; 60 61 public final int methodIndex; 62 63 private int methodIdItemOffset; 64 private int protoIdItemOffset; 65 private int parametersOffset = -1; 66 67 // method_id_item offsets 68 private static final int PROTO_OFFSET = 2; 69 private static final int NAME_OFFSET = 4; 70 71 // proto_id_item offsets 72 private static final int RETURN_TYPE_OFFSET = 4; 73 private static final int PARAMETERS_OFFSET = 8; 74 75 public DexBackedMethod(@Nonnull DexReader reader, 76 @Nonnull DexBackedClassDef classDef, 77 int previousMethodIndex) { 78 this.dexBuf = reader.dexBuf; 79 this.classDef = classDef; 80 81 int methodIndexDiff = reader.readSmallUleb128(); 82 this.methodIndex = methodIndexDiff + previousMethodIndex; 83 this.accessFlags = reader.readSmallUleb128(); 84 this.codeOffset = reader.readSmallUleb128(); 85 86 this.methodAnnotationSetOffset = 0; 87 this.parameterAnnotationSetListOffset = 0; 88 } 89 90 public DexBackedMethod(@Nonnull DexReader reader, 91 @Nonnull DexBackedClassDef classDef, 92 int previousMethodIndex, 93 @Nonnull AnnotationsDirectory.AnnotationIterator methodAnnotationIterator, 94 @Nonnull AnnotationsDirectory.AnnotationIterator paramaterAnnotationIterator) { 95 this.dexBuf = reader.dexBuf; 96 this.classDef = classDef; 97 98 int methodIndexDiff = reader.readSmallUleb128(); 99 this.methodIndex = methodIndexDiff + previousMethodIndex; 100 this.accessFlags = reader.readSmallUleb128(); 101 this.codeOffset = reader.readSmallUleb128(); 102 103 this.methodAnnotationSetOffset = methodAnnotationIterator.seekTo(methodIndex); 104 this.parameterAnnotationSetListOffset = paramaterAnnotationIterator.seekTo(methodIndex); 105 } 106 107 public int getMethodIndex() { return methodIndex; } 108 @Nonnull @Override public String getDefiningClass() { return classDef.getType(); } 109 @Override public int getAccessFlags() { return accessFlags; } 110 111 @Nonnull 112 @Override 113 public String getName() { 114 return dexBuf.getString(dexBuf.readSmallUint(getMethodIdItemOffset() + NAME_OFFSET)); 115 } 116 117 @Nonnull 118 @Override 119 public String getReturnType() { 120 return dexBuf.getType(dexBuf.readSmallUint(getProtoIdItemOffset() + RETURN_TYPE_OFFSET)); 121 } 122 123 @Nonnull 124 @Override 125 public List<? extends MethodParameter> getParameters() { 126 int parametersOffset = getParametersOffset(); 127 if (parametersOffset > 0) { 128 final List<String> parameterTypes = getParameterTypes(); 129 130 return new AbstractForwardSequentialList<MethodParameter>() { 131 @Nonnull @Override public Iterator<MethodParameter> iterator() { 132 return new ParameterIterator(parameterTypes, 133 getParameterAnnotations(), 134 getParameterNames()); 135 } 136 137 @Override public int size() { 138 return parameterTypes.size(); 139 } 140 }; 141 } 142 return ImmutableList.of(); 143 } 144 145 @Nonnull 146 public List<? extends Set<? extends DexBackedAnnotation>> getParameterAnnotations() { 147 return AnnotationsDirectory.getParameterAnnotations(dexBuf, parameterAnnotationSetListOffset); 148 } 149 150 @Nonnull 151 public Iterator<String> getParameterNames() { 152 DexBackedMethodImplementation methodImpl = getImplementation(); 153 if (methodImpl != null) { 154 return methodImpl.getParameterNames(null); 155 } 156 return Iterators.emptyIterator(); 157 } 158 159 @Nonnull 160 @Override 161 public List<String> getParameterTypes() { 162 final int parametersOffset = getParametersOffset(); 163 if (parametersOffset > 0) { 164 final int parameterCount = dexBuf.readSmallUint(parametersOffset + DexBuffer.TYPE_LIST_SIZE_OFFSET); 165 final int paramListStart = parametersOffset + DexBuffer.TYPE_LIST_LIST_OFFSET; 166 return new FixedSizeList<String>() { 167 @Nonnull 168 @Override 169 public String readItem(final int index) { 170 return dexBuf.getType(dexBuf.readUshort(paramListStart + 2*index)); 171 } 172 @Override public int size() { return parameterCount; } 173 }; 174 } 175 return ImmutableList.of(); 176 } 177 178 @Nonnull 179 @Override 180 public Set<? extends Annotation> getAnnotations() { 181 return AnnotationsDirectory.getAnnotations(dexBuf, methodAnnotationSetOffset); 182 } 183 184 @Nullable 185 @Override 186 public DexBackedMethodImplementation getImplementation() { 187 if (codeOffset > 0) { 188 return new DexBackedMethodImplementation(dexBuf, this, codeOffset); 189 } 190 return null; 191 } 192 193 private int getMethodIdItemOffset() { 194 if (methodIdItemOffset == 0) { 195 methodIdItemOffset = dexBuf.getMethodIdItemOffset(methodIndex); 196 } 197 return methodIdItemOffset; 198 } 199 200 private int getProtoIdItemOffset() { 201 if (protoIdItemOffset == 0) { 202 int protoIndex = dexBuf.readUshort(getMethodIdItemOffset() + PROTO_OFFSET); 203 protoIdItemOffset = dexBuf.getProtoIdItemOffset(protoIndex); 204 } 205 return protoIdItemOffset; 206 } 207 208 private int getParametersOffset() { 209 if (parametersOffset == -1) { 210 parametersOffset = dexBuf.readSmallUint(getProtoIdItemOffset() + PARAMETERS_OFFSET); 211 } 212 return parametersOffset; 213 } 214} 215