1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dex.reader; 18 19 import java.lang.reflect.Modifier; 20 import java.util.ArrayList; 21 import java.util.HashMap; 22 import java.util.HashSet; 23 import java.util.LinkedList; 24 import java.util.List; 25 import java.util.Map; 26 import java.util.Set; 27 28 import dex.reader.DexFileReader.ClassDefItem; 29 import dex.reader.DexFileReader.FieldIdItem; 30 import dex.reader.DexFileReader.MethodsIdItem; 31 import dex.reader.DexFileReader.ProtIdItem; 32 import dex.structure.DexAnnotation; 33 import dex.structure.DexClass; 34 import dex.structure.DexField; 35 import dex.structure.DexMethod; 36 37 /* package */final class DexClassImpl implements DexClass { 38 // constant 39 private final int NO_INDEX = -1; 40 // dex bytes 41 private final DexBuffer buffer; 42 // allready parsed 43 private final ClassDefItem classDefItem; 44 private final int[] typeIds; 45 private final String[] stringPool; 46 private ProtIdItem[] protoIdItems; 47 private FieldIdItem[] fieldIdItems; 48 private MethodsIdItem[] methodIdItems; 49 50 // 51 private List<DexField> fields; 52 private List<DexMethod> methods; 53 private List<String> interfaces; 54 private ClassDataItem classDataItem; 55 private AnnotationsDirectoryItem annotationDir; 56 private Map<Integer, FieldAnnotation> idToFieldAnnotation = 57 new HashMap<Integer, FieldAnnotation>(); 58 private Map<Integer, MethodAnnotation> idToMethodAnnotation = 59 new HashMap<Integer, MethodAnnotation>(); 60 private Map<Integer, ParameterAnnotation> idToParameterAnnotation = 61 new HashMap<Integer, ParameterAnnotation>(); 62 63 private Set<DexAnnotation> annotations; 64 private TypeFormatter formatter = new TypeFormatter(); 65 66 private boolean hasClassData; 67 68 69 public DexClassImpl(DexBuffer buffer, ClassDefItem classDefItem, 70 String[] stringPool, int[] typeIds, ProtIdItem[] protoIdItems, 71 FieldIdItem[] fieldIdItems, MethodsIdItem[] methodIdItems) { 72 this.buffer = buffer; 73 this.classDefItem = classDefItem; 74 this.stringPool = stringPool; 75 this.typeIds = typeIds; 76 this.protoIdItems = protoIdItems; 77 this.fieldIdItems = fieldIdItems; 78 this.methodIdItems = methodIdItems; 79 hasClassData = classDefItem.class_data_off != 0; 80 parseClassData(); 81 parseAnnotationDirectory(); 82 parseClassAnnotations(); 83 } 84 85 static class AnnotationsDirectoryItem { 86 int class_annotations_off; // uint 87 int fields_size; // uint 88 int methods_size; // uint 89 int annotated_params_size; // uint 90 FieldAnnotation[] fieldAnnotations; 91 MethodAnnotation[] methodAnnotations; 92 ParameterAnnotation[] parameterAnnotations; 93 } 94 95 static class AnnotationSetItem { 96 int size;// uint 97 int[] annotationOffItem; 98 } 99 100 static class FieldAnnotation { 101 int fieldIdx;// uint 102 int annotationsOff;// uint 103 AnnotationSetItem[] annotationSetItems; 104 } 105 106 static class MethodAnnotation { 107 int methodIdx;// uint 108 int annotationsOff;// uint 109 AnnotationSetItem[] annotationSetItems; 110 } 111 112 static class ParameterAnnotation { 113 int methodIdx;// uint 114 int annotationsOff;// uint 115 // AnnotationSetRefListItem[] annotationSetRefListItems; 116 } 117 118 private void parseAnnotationDirectory() { 119 if (classDefItem.annotations_off != 0) { 120 buffer.setPosition(classDefItem.annotations_off); 121 annotationDir = new AnnotationsDirectoryItem(); 122 annotationDir.class_annotations_off = buffer.readUInt(); 123 annotationDir.fields_size = buffer.readUInt(); 124 annotationDir.methods_size = buffer.readUInt(); 125 annotationDir.annotated_params_size = buffer.readUInt(); 126 127 if (annotationDir.fields_size != 0) { 128 annotationDir.fieldAnnotations = 129 new FieldAnnotation[annotationDir.fields_size]; 130 for (int i = 0; i < annotationDir.fields_size; i++) { 131 annotationDir.fieldAnnotations[i] = new FieldAnnotation(); 132 annotationDir.fieldAnnotations[i].fieldIdx = buffer 133 .readUInt(); 134 annotationDir.fieldAnnotations[i].annotationsOff = buffer 135 .readUInt(); 136 idToFieldAnnotation.put( 137 annotationDir.fieldAnnotations[i].fieldIdx, 138 annotationDir.fieldAnnotations[i]); 139 } 140 } 141 if (annotationDir.methods_size != 0) { 142 annotationDir.methodAnnotations = 143 new MethodAnnotation[annotationDir.methods_size]; 144 for (int i = 0; i < annotationDir.methods_size; i++) { 145 annotationDir.methodAnnotations[i] = new MethodAnnotation(); 146 annotationDir.methodAnnotations[i].methodIdx = buffer 147 .readUInt(); 148 annotationDir.methodAnnotations[i].annotationsOff = buffer 149 .readUInt(); 150 idToMethodAnnotation.put( 151 annotationDir.methodAnnotations[i].methodIdx, 152 annotationDir.methodAnnotations[i]); 153 } 154 } 155 if (annotationDir.annotated_params_size != 0) { 156 annotationDir.parameterAnnotations = 157 new ParameterAnnotation[annotationDir 158 .annotated_params_size]; 159 for (int i = 0; i < annotationDir.annotated_params_size; i++) { 160 annotationDir.parameterAnnotations[i] = 161 new ParameterAnnotation(); 162 annotationDir.parameterAnnotations[i].methodIdx = buffer 163 .readUInt(); 164 annotationDir.parameterAnnotations[i].annotationsOff = 165 buffer.readUInt(); 166 idToParameterAnnotation.put( 167 annotationDir.parameterAnnotations[i].methodIdx, 168 annotationDir.parameterAnnotations[i]); 169 } 170 } 171 } 172 } 173 174 static class ClassDataItem { 175 int static_fields_size;// uleb128 176 int instance_fields_size;// uleb128 177 int direct_methods_size;// uleb128 178 int virtual_methods_size;// uleb128 179 EncodedField[] staticFields; 180 EncodedField[] instanceFields; 181 EncodedMethod[] directMethods; 182 EncodedMethod[] virtualMethods; 183 } 184 185 static class EncodedField { 186 int field_idx_diff; // uleb128 187 int access_flags; // uleb128 188 } 189 190 static class EncodedMethod { 191 int method_idx_diff;// uleb128 192 int access_flags;// uleb128 193 int code_off; // uleb128 194 } 195 196 private void parseClassData() { 197 if (hasClassData) { 198 buffer.setPosition(classDefItem.class_data_off); 199 classDataItem = new ClassDataItem(); 200 classDataItem.static_fields_size = buffer.readUleb128(); 201 classDataItem.instance_fields_size = buffer.readUleb128(); 202 classDataItem.direct_methods_size = buffer.readUleb128(); 203 classDataItem.virtual_methods_size = buffer.readUleb128(); 204 classDataItem.staticFields = parseFields( 205 classDataItem.static_fields_size); 206 classDataItem.instanceFields = parseFields( 207 classDataItem.instance_fields_size); 208 classDataItem.directMethods = parseMethods( 209 classDataItem.direct_methods_size); 210 classDataItem.virtualMethods = parseMethods( 211 classDataItem.virtual_methods_size); 212 } 213 } 214 215 private EncodedField[] parseFields(int size) { 216 EncodedField[] fields = new EncodedField[size]; 217 for (int i = 0; i < fields.length; i++) { 218 fields[i] = new EncodedField(); 219 fields[i].field_idx_diff = buffer.readUleb128(); 220 fields[i].access_flags = buffer.readUleb128(); 221 } 222 return fields; 223 } 224 225 private EncodedMethod[] parseMethods(int size) { 226 EncodedMethod[] methods = new EncodedMethod[size]; 227 for (int i = 0; i < methods.length; i++) { 228 methods[i] = new EncodedMethod(); 229 methods[i].method_idx_diff = buffer.readUleb128(); 230 methods[i].access_flags = buffer.readUleb128(); 231 methods[i].code_off = buffer.readUleb128(); 232 } 233 return methods; 234 } 235 236 private void parseClassAnnotations() { 237 annotations = new HashSet<DexAnnotation>(); 238 if (annotationDir != null && annotationDir.class_annotations_off != 0) { 239 buffer.setPosition(annotationDir.class_annotations_off); 240 final int size = buffer.readUInt(); 241 for (int i = 0; i < size; i++) { 242 annotations.add(new DexAnnotationImpl(buffer.createCopy(), 243 buffer.readUInt(), typeIds, stringPool, fieldIdItems)); 244 } 245 } 246 } 247 248 public synchronized List<DexField> getFields() { 249 if (fields == null) { 250 fields = new ArrayList<DexField>(); 251 if (hasClassData) { 252 fields.addAll(getDexFields(classDataItem.staticFields)); 253 fields.addAll(getDexFields(classDataItem.instanceFields)); 254 } 255 } 256 return fields; 257 } 258 259 private List<DexField> getDexFields(EncodedField[] fields) { 260 List<DexField> dexFields = new ArrayList<DexField>(fields.length); 261 if (fields.length != 0) { 262 int fieldIdIdx = 0; 263 for (int i = 0; i < fields.length; i++) { 264 int accessFlags = fields[i].access_flags; 265 fieldIdIdx = (i == 0) ? fields[i].field_idx_diff : fieldIdIdx 266 + fields[i].field_idx_diff; 267 dexFields.add(new DexFieldImpl(buffer.createCopy(), this, 268 fieldIdItems[fieldIdIdx], accessFlags, 269 idToFieldAnnotation.get(fieldIdIdx), stringPool, 270 typeIds, fieldIdItems)); 271 } 272 } 273 return dexFields; 274 } 275 276 public synchronized List<DexMethod> getMethods() { 277 if (methods == null) { 278 methods = new ArrayList<DexMethod>(); 279 if (hasClassData) { 280 methods.addAll(getDexMethods(classDataItem.directMethods)); 281 methods.addAll(getDexMethods(classDataItem.virtualMethods)); 282 } 283 } 284 return methods; 285 } 286 287 private List<DexMethod> getDexMethods(EncodedMethod[] methods) { 288 List<DexMethod> dexMethods = new ArrayList<DexMethod>(methods.length); 289 if (methods.length != 0) { 290 int methodIdIdx = 0; 291 EncodedMethod method = null; 292 for (int i = 0; i < methods.length; i++) { 293 method = methods[i]; 294 methodIdIdx = (i == 0) ? method.method_idx_diff : methodIdIdx 295 + method.method_idx_diff; 296 dexMethods.add(new DexMethodImpl(buffer, this, 297 methodIdItems[methodIdIdx], 298 protoIdItems[methodIdItems[methodIdIdx].proto_idx], 299 method.access_flags, idToMethodAnnotation 300 .get(methodIdIdx), idToParameterAnnotation 301 .get(methodIdIdx), stringPool, typeIds, 302 fieldIdItems)); 303 } 304 } 305 return dexMethods; 306 } 307 308 309 310 public synchronized List<String> getInterfaces() { 311 if (interfaces == null) { 312 interfaces = new LinkedList<String>(); 313 if (classDefItem.interfaces_off != 0) { 314 buffer.setPosition(classDefItem.interfaces_off); 315 int size = buffer.readUInt(); 316 for (int i = 0; i < size; i++) { 317 interfaces.add(stringPool[typeIds[buffer.readUShort()]]); 318 } 319 } 320 } 321 return interfaces; 322 } 323 324 // returns null if no super class is present 325 public String getSuperClass() { 326 return classDefItem.superclass_idx == NO_INDEX ? null 327 : stringPool[typeIds[classDefItem.superclass_idx]]; 328 } 329 330 public Set<DexAnnotation> getAnnotations() { 331 return annotations; 332 } 333 334 public String getName() { 335 return stringPool[typeIds[classDefItem.class_idx]]; 336 } 337 338 public int getModifiers() { 339 return classDefItem.access_flags; 340 } 341 342 @Override 343 public String toString() { 344 StringBuilder builder = new StringBuilder(); 345 builder.append(formatter.formatAnnotations(getAnnotations())); 346 builder.append(Modifier.toString(getModifiers())); 347 builder.append(" class "); 348 builder.append(formatter.format(getName())); 349 if (getSuperClass() != null) { 350 builder.append(" extends "); 351 builder.append(formatter.format(getSuperClass())); 352 } 353 if (!getInterfaces().isEmpty()) { 354 builder.append(" implements "); 355 builder.append(formatter.format(getInterfaces())); 356 } 357 return builder.toString(); 358 } 359 360 } 361