1 /* 2 * Copyright (C) 2007 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 com.android.dx.dex.file; 18 19 import com.android.dex.SizeOf; 20 import com.android.dx.rop.annotation.Annotations; 21 import com.android.dx.rop.annotation.AnnotationsList; 22 import com.android.dx.rop.code.AccessFlags; 23 import com.android.dx.rop.cst.Constant; 24 import com.android.dx.rop.cst.CstArray; 25 import com.android.dx.rop.cst.CstFieldRef; 26 import com.android.dx.rop.cst.CstMethodRef; 27 import com.android.dx.rop.cst.CstString; 28 import com.android.dx.rop.cst.CstType; 29 import com.android.dx.rop.type.StdTypeList; 30 import com.android.dx.rop.type.TypeList; 31 import com.android.dx.util.AnnotatedOutput; 32 import com.android.dx.util.Hex; 33 import com.android.dx.util.Writers; 34 import java.io.PrintWriter; 35 import java.io.Writer; 36 import java.util.ArrayList; 37 38 /** 39 * Representation of a Dalvik class, which is basically a set of 40 * members (fields or methods) along with a few more pieces of 41 * information. 42 */ 43 public final class ClassDefItem extends IndexedItem { 44 45 /** {@code non-null;} type constant for this class */ 46 private final CstType thisClass; 47 48 /** access flags */ 49 private final int accessFlags; 50 51 /** 52 * {@code null-ok;} superclass or {@code null} if this class is a/the 53 * root class 54 */ 55 private final CstType superclass; 56 57 /** {@code null-ok;} list of implemented interfaces */ 58 private TypeListItem interfaces; 59 60 /** {@code null-ok;} source file name or {@code null} if unknown */ 61 private final CstString sourceFile; 62 63 /** {@code non-null;} associated class data object */ 64 private final ClassDataItem classData; 65 66 /** 67 * {@code null-ok;} item wrapper for the static values, initialized 68 * in {@link #addContents} 69 */ 70 private EncodedArrayItem staticValuesItem; 71 72 /** {@code non-null;} annotations directory */ 73 private AnnotationsDirectoryItem annotationsDirectory; 74 75 /** 76 * Constructs an instance. Its sets of members and annotations are 77 * initially empty. 78 * 79 * @param thisClass {@code non-null;} type constant for this class 80 * @param accessFlags access flags 81 * @param superclass {@code null-ok;} superclass or {@code null} if 82 * this class is a/the root class 83 * @param interfaces {@code non-null;} list of implemented interfaces 84 * @param sourceFile {@code null-ok;} source file name or 85 * {@code null} if unknown 86 */ ClassDefItem(CstType thisClass, int accessFlags, CstType superclass, TypeList interfaces, CstString sourceFile)87 public ClassDefItem(CstType thisClass, int accessFlags, 88 CstType superclass, TypeList interfaces, CstString sourceFile) { 89 if (thisClass == null) { 90 throw new NullPointerException("thisClass == null"); 91 } 92 93 /* 94 * TODO: Maybe check accessFlags and superclass, at 95 * least for easily-checked stuff? 96 */ 97 98 if (interfaces == null) { 99 throw new NullPointerException("interfaces == null"); 100 } 101 102 this.thisClass = thisClass; 103 this.accessFlags = accessFlags; 104 this.superclass = superclass; 105 this.interfaces = 106 (interfaces.size() == 0) ? null : new TypeListItem(interfaces); 107 this.sourceFile = sourceFile; 108 this.classData = new ClassDataItem(thisClass); 109 this.staticValuesItem = null; 110 this.annotationsDirectory = new AnnotationsDirectoryItem(); 111 } 112 113 /** {@inheritDoc} */ 114 @Override itemType()115 public ItemType itemType() { 116 return ItemType.TYPE_CLASS_DEF_ITEM; 117 } 118 119 /** {@inheritDoc} */ 120 @Override writeSize()121 public int writeSize() { 122 return SizeOf.CLASS_DEF_ITEM; 123 } 124 125 /** {@inheritDoc} */ 126 @Override addContents(DexFile file)127 public void addContents(DexFile file) { 128 TypeIdsSection typeIds = file.getTypeIds(); 129 MixedItemSection byteData = file.getByteData(); 130 MixedItemSection wordData = file.getWordData(); 131 MixedItemSection typeLists = file.getTypeLists(); 132 StringIdsSection stringIds = file.getStringIds(); 133 134 typeIds.intern(thisClass); 135 136 if (!classData.isEmpty()) { 137 MixedItemSection classDataSection = file.getClassData(); 138 classDataSection.add(classData); 139 140 CstArray staticValues = classData.getStaticValuesConstant(); 141 if (staticValues != null) { 142 staticValuesItem = 143 byteData.intern(new EncodedArrayItem(staticValues)); 144 } 145 } 146 147 if (superclass != null) { 148 typeIds.intern(superclass); 149 } 150 151 if (interfaces != null) { 152 interfaces = typeLists.intern(interfaces); 153 } 154 155 if (sourceFile != null) { 156 stringIds.intern(sourceFile); 157 } 158 159 if (! annotationsDirectory.isEmpty()) { 160 if (annotationsDirectory.isInternable()) { 161 annotationsDirectory = wordData.intern(annotationsDirectory); 162 } else { 163 wordData.add(annotationsDirectory); 164 } 165 } 166 } 167 168 /** {@inheritDoc} */ 169 @Override writeTo(DexFile file, AnnotatedOutput out)170 public void writeTo(DexFile file, AnnotatedOutput out) { 171 boolean annotates = out.annotates(); 172 TypeIdsSection typeIds = file.getTypeIds(); 173 int classIdx = typeIds.indexOf(thisClass); 174 int superIdx = (superclass == null) ? -1 : 175 typeIds.indexOf(superclass); 176 int interOff = OffsettedItem.getAbsoluteOffsetOr0(interfaces); 177 int annoOff = annotationsDirectory.isEmpty() ? 0 : 178 annotationsDirectory.getAbsoluteOffset(); 179 int sourceFileIdx = (sourceFile == null) ? -1 : 180 file.getStringIds().indexOf(sourceFile); 181 int dataOff = classData.isEmpty()? 0 : classData.getAbsoluteOffset(); 182 int staticValuesOff = 183 OffsettedItem.getAbsoluteOffsetOr0(staticValuesItem); 184 185 if (annotates) { 186 out.annotate(0, indexString() + ' ' + thisClass.toHuman()); 187 out.annotate(4, " class_idx: " + Hex.u4(classIdx)); 188 out.annotate(4, " access_flags: " + 189 AccessFlags.classString(accessFlags)); 190 out.annotate(4, " superclass_idx: " + Hex.u4(superIdx) + 191 " // " + ((superclass == null) ? "<none>" : 192 superclass.toHuman())); 193 out.annotate(4, " interfaces_off: " + Hex.u4(interOff)); 194 if (interOff != 0) { 195 TypeList list = interfaces.getList(); 196 int sz = list.size(); 197 for (int i = 0; i < sz; i++) { 198 out.annotate(0, " " + list.getType(i).toHuman()); 199 } 200 } 201 out.annotate(4, " source_file_idx: " + Hex.u4(sourceFileIdx) + 202 " // " + ((sourceFile == null) ? "<none>" : 203 sourceFile.toHuman())); 204 out.annotate(4, " annotations_off: " + Hex.u4(annoOff)); 205 out.annotate(4, " class_data_off: " + Hex.u4(dataOff)); 206 out.annotate(4, " static_values_off: " + 207 Hex.u4(staticValuesOff)); 208 } 209 210 out.writeInt(classIdx); 211 out.writeInt(accessFlags); 212 out.writeInt(superIdx); 213 out.writeInt(interOff); 214 out.writeInt(sourceFileIdx); 215 out.writeInt(annoOff); 216 out.writeInt(dataOff); 217 out.writeInt(staticValuesOff); 218 } 219 220 /** 221 * Gets the constant corresponding to this class. 222 * 223 * @return {@code non-null;} the constant 224 */ getThisClass()225 public CstType getThisClass() { 226 return thisClass; 227 } 228 229 /** 230 * Gets the access flags. 231 * 232 * @return the access flags 233 */ getAccessFlags()234 public int getAccessFlags() { 235 return accessFlags; 236 } 237 238 /** 239 * Gets the superclass. 240 * 241 * @return {@code null-ok;} the superclass or {@code null} if 242 * this class is a/the root class 243 */ getSuperclass()244 public CstType getSuperclass() { 245 return superclass; 246 } 247 248 /** 249 * Gets the list of interfaces implemented. 250 * 251 * @return {@code non-null;} the interfaces list 252 */ getInterfaces()253 public TypeList getInterfaces() { 254 if (interfaces == null) { 255 return StdTypeList.EMPTY; 256 } 257 258 return interfaces.getList(); 259 } 260 261 /** 262 * Gets the source file name. 263 * 264 * @return {@code null-ok;} the source file name or {@code null} if unknown 265 */ getSourceFile()266 public CstString getSourceFile() { 267 return sourceFile; 268 } 269 270 /** 271 * Adds a static field. 272 * 273 * @param field {@code non-null;} the field to add 274 * @param value {@code null-ok;} initial value for the field, if any 275 */ addStaticField(EncodedField field, Constant value)276 public void addStaticField(EncodedField field, Constant value) { 277 classData.addStaticField(field, value); 278 } 279 280 /** 281 * Adds an instance field. 282 * 283 * @param field {@code non-null;} the field to add 284 */ addInstanceField(EncodedField field)285 public void addInstanceField(EncodedField field) { 286 classData.addInstanceField(field); 287 } 288 289 /** 290 * Adds a direct ({@code static} and/or {@code private}) method. 291 * 292 * @param method {@code non-null;} the method to add 293 */ addDirectMethod(EncodedMethod method)294 public void addDirectMethod(EncodedMethod method) { 295 classData.addDirectMethod(method); 296 } 297 298 /** 299 * Adds a virtual method. 300 * 301 * @param method {@code non-null;} the method to add 302 */ addVirtualMethod(EncodedMethod method)303 public void addVirtualMethod(EncodedMethod method) { 304 classData.addVirtualMethod(method); 305 } 306 307 /** 308 * Gets all the methods in this class. The returned list is not linked 309 * in any way to the underlying lists contained in this instance, but 310 * the objects contained in the list are shared. 311 * 312 * @return {@code non-null;} list of all methods 313 */ getMethods()314 public ArrayList<EncodedMethod> getMethods() { 315 return classData.getMethods(); 316 } 317 318 /** 319 * Sets the direct annotations on this class. These are annotations 320 * made on the class, per se, as opposed to on one of its members. 321 * It is only valid to call this method at most once per instance. 322 * 323 * @param annotations {@code non-null;} annotations to set for this class 324 * @param dexFile {@code non-null;} dex output 325 */ setClassAnnotations(Annotations annotations, DexFile dexFile)326 public void setClassAnnotations(Annotations annotations, DexFile dexFile) { 327 annotationsDirectory.setClassAnnotations(annotations, dexFile); 328 } 329 330 /** 331 * Adds a field annotations item to this class. 332 * 333 * @param field {@code non-null;} field in question 334 * @param annotations {@code non-null;} associated annotations to add 335 * @param dexFile {@code non-null;} dex output 336 */ addFieldAnnotations(CstFieldRef field, Annotations annotations, DexFile dexFile)337 public void addFieldAnnotations(CstFieldRef field, 338 Annotations annotations, DexFile dexFile) { 339 annotationsDirectory.addFieldAnnotations(field, annotations, dexFile); 340 } 341 342 /** 343 * Adds a method annotations item to this class. 344 * 345 * @param method {@code non-null;} method in question 346 * @param annotations {@code non-null;} associated annotations to add 347 * @param dexFile {@code non-null;} dex output 348 */ addMethodAnnotations(CstMethodRef method, Annotations annotations, DexFile dexFile)349 public void addMethodAnnotations(CstMethodRef method, 350 Annotations annotations, DexFile dexFile) { 351 annotationsDirectory.addMethodAnnotations(method, annotations, dexFile); 352 } 353 354 /** 355 * Adds a parameter annotations item to this class. 356 * 357 * @param method {@code non-null;} method in question 358 * @param list {@code non-null;} associated list of annotation sets to add 359 * @param dexFile {@code non-null;} dex output 360 */ addParameterAnnotations(CstMethodRef method, AnnotationsList list, DexFile dexFile)361 public void addParameterAnnotations(CstMethodRef method, 362 AnnotationsList list, DexFile dexFile) { 363 annotationsDirectory.addParameterAnnotations(method, list, dexFile); 364 } 365 366 /** 367 * Gets the method annotations for a given method, if any. This is 368 * meant for use by debugging / dumping code. 369 * 370 * @param method {@code non-null;} the method 371 * @return {@code null-ok;} the method annotations, if any 372 */ getMethodAnnotations(CstMethodRef method)373 public Annotations getMethodAnnotations(CstMethodRef method) { 374 return annotationsDirectory.getMethodAnnotations(method); 375 } 376 377 /** 378 * Gets the parameter annotations for a given method, if any. This is 379 * meant for use by debugging / dumping code. 380 * 381 * @param method {@code non-null;} the method 382 * @return {@code null-ok;} the parameter annotations, if any 383 */ getParameterAnnotations(CstMethodRef method)384 public AnnotationsList getParameterAnnotations(CstMethodRef method) { 385 return annotationsDirectory.getParameterAnnotations(method); 386 } 387 388 /** 389 * Prints out the contents of this instance, in a debugging-friendly 390 * way. 391 * 392 * @param out {@code non-null;} where to output to 393 * @param verbose whether to be verbose with the output 394 */ debugPrint(Writer out, boolean verbose)395 public void debugPrint(Writer out, boolean verbose) { 396 PrintWriter pw = Writers.printWriterFor(out); 397 398 pw.println(getClass().getName() + " {"); 399 pw.println(" accessFlags: " + Hex.u2(accessFlags)); 400 pw.println(" superclass: " + superclass); 401 pw.println(" interfaces: " + 402 ((interfaces == null) ? "<none>" : interfaces)); 403 pw.println(" sourceFile: " + 404 ((sourceFile == null) ? "<none>" : sourceFile.toQuoted())); 405 406 classData.debugPrint(out, verbose); 407 annotationsDirectory.debugPrint(pw); 408 409 pw.println("}"); 410 } 411 } 412