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 17package com.android.dx.dex.file; 18 19import com.android.dex.SizeOf; 20import com.android.dx.rop.annotation.Annotations; 21import com.android.dx.rop.annotation.AnnotationsList; 22import com.android.dx.rop.code.AccessFlags; 23import com.android.dx.rop.cst.Constant; 24import com.android.dx.rop.cst.CstArray; 25import com.android.dx.rop.cst.CstFieldRef; 26import com.android.dx.rop.cst.CstMethodRef; 27import com.android.dx.rop.cst.CstString; 28import com.android.dx.rop.cst.CstType; 29import com.android.dx.rop.type.StdTypeList; 30import com.android.dx.rop.type.TypeList; 31import com.android.dx.util.AnnotatedOutput; 32import com.android.dx.util.Hex; 33import com.android.dx.util.Writers; 34import java.io.PrintWriter; 35import java.io.Writer; 36import 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 */ 43public 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 */ 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 115 public ItemType itemType() { 116 return ItemType.TYPE_CLASS_DEF_ITEM; 117 } 118 119 /** {@inheritDoc} */ 120 @Override 121 public int writeSize() { 122 return SizeOf.CLASS_DEF_ITEM; 123 } 124 125 /** {@inheritDoc} */ 126 @Override 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 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 */ 225 public CstType getThisClass() { 226 return thisClass; 227 } 228 229 /** 230 * Gets the access flags. 231 * 232 * @return the access flags 233 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 325 public void setClassAnnotations(Annotations annotations) { 326 annotationsDirectory.setClassAnnotations(annotations); 327 } 328 329 /** 330 * Adds a field annotations item to this class. 331 * 332 * @param field {@code non-null;} field in question 333 * @param annotations {@code non-null;} associated annotations to add 334 */ 335 public void addFieldAnnotations(CstFieldRef field, 336 Annotations annotations) { 337 annotationsDirectory.addFieldAnnotations(field, annotations); 338 } 339 340 /** 341 * Adds a method annotations item to this class. 342 * 343 * @param method {@code non-null;} method in question 344 * @param annotations {@code non-null;} associated annotations to add 345 */ 346 public void addMethodAnnotations(CstMethodRef method, 347 Annotations annotations) { 348 annotationsDirectory.addMethodAnnotations(method, annotations); 349 } 350 351 /** 352 * Adds a parameter annotations item to this class. 353 * 354 * @param method {@code non-null;} method in question 355 * @param list {@code non-null;} associated list of annotation sets to add 356 */ 357 public void addParameterAnnotations(CstMethodRef method, 358 AnnotationsList list) { 359 annotationsDirectory.addParameterAnnotations(method, list); 360 } 361 362 /** 363 * Gets the method annotations for a given method, if any. This is 364 * meant for use by debugging / dumping code. 365 * 366 * @param method {@code non-null;} the method 367 * @return {@code null-ok;} the method annotations, if any 368 */ 369 public Annotations getMethodAnnotations(CstMethodRef method) { 370 return annotationsDirectory.getMethodAnnotations(method); 371 } 372 373 /** 374 * Gets the parameter annotations for a given method, if any. This is 375 * meant for use by debugging / dumping code. 376 * 377 * @param method {@code non-null;} the method 378 * @return {@code null-ok;} the parameter annotations, if any 379 */ 380 public AnnotationsList getParameterAnnotations(CstMethodRef method) { 381 return annotationsDirectory.getParameterAnnotations(method); 382 } 383 384 /** 385 * Prints out the contents of this instance, in a debugging-friendly 386 * way. 387 * 388 * @param out {@code non-null;} where to output to 389 * @param verbose whether to be verbose with the output 390 */ 391 public void debugPrint(Writer out, boolean verbose) { 392 PrintWriter pw = Writers.printWriterFor(out); 393 394 pw.println(getClass().getName() + " {"); 395 pw.println(" accessFlags: " + Hex.u2(accessFlags)); 396 pw.println(" superclass: " + superclass); 397 pw.println(" interfaces: " + 398 ((interfaces == null) ? "<none>" : interfaces)); 399 pw.println(" sourceFile: " + 400 ((sourceFile == null) ? "<none>" : sourceFile.toQuoted())); 401 402 classData.debugPrint(out, verbose); 403 annotationsDirectory.debugPrint(pw); 404 405 pw.println("}"); 406 } 407} 408