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