• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
35 import java.io.PrintWriter;
36 import java.io.Writer;
37 import 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  */
44 public 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      */
ClassDefItem(CstType thisClass, int accessFlags, CstType superclass, TypeList interfaces, CstString sourceFile)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
itemType()116     public ItemType itemType() {
117         return ItemType.TYPE_CLASS_DEF_ITEM;
118     }
119 
120     /** {@inheritDoc} */
121     @Override
writeSize()122     public int writeSize() {
123         return SizeOf.CLASS_DEF_ITEM;
124     }
125 
126     /** {@inheritDoc} */
127     @Override
addContents(DexFile file)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
writeTo(DexFile file, AnnotatedOutput out)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      */
getThisClass()226     public CstType getThisClass() {
227         return thisClass;
228     }
229 
230     /**
231      * Gets the access flags.
232      *
233      * @return the access flags
234      */
getAccessFlags()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      */
getSuperclass()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      */
getInterfaces()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      */
getSourceFile()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      */
addStaticField(EncodedField field, Constant value)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      */
addInstanceField(EncodedField field)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      */
addDirectMethod(EncodedMethod method)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      */
addVirtualMethod(EncodedMethod method)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      */
getMethods()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      * @param dexFile {@code non-null;} dex output
326      */
setClassAnnotations(Annotations annotations, DexFile dexFile)327     public void setClassAnnotations(Annotations annotations, DexFile dexFile) {
328         annotationsDirectory.setClassAnnotations(annotations, dexFile);
329     }
330 
331     /**
332      * Adds a field annotations item to this class.
333      *
334      * @param field {@code non-null;} field in question
335      * @param annotations {@code non-null;} associated annotations to add
336      * @param dexFile {@code non-null;} dex output
337      */
addFieldAnnotations(CstFieldRef field, Annotations annotations, DexFile dexFile)338     public void addFieldAnnotations(CstFieldRef field,
339             Annotations annotations, DexFile dexFile) {
340         annotationsDirectory.addFieldAnnotations(field, annotations, dexFile);
341     }
342 
343     /**
344      * Adds a method annotations item to this class.
345      *
346      * @param method {@code non-null;} method in question
347      * @param annotations {@code non-null;} associated annotations to add
348      * @param dexFile {@code non-null;} dex output
349      */
addMethodAnnotations(CstMethodRef method, Annotations annotations, DexFile dexFile)350     public void addMethodAnnotations(CstMethodRef method,
351             Annotations annotations, DexFile dexFile) {
352         annotationsDirectory.addMethodAnnotations(method, annotations, dexFile);
353     }
354 
355     /**
356      * Adds a parameter annotations item to this class.
357      *
358      * @param method {@code non-null;} method in question
359      * @param list {@code non-null;} associated list of annotation sets to add
360      * @param dexFile {@code non-null;} dex output
361      */
addParameterAnnotations(CstMethodRef method, AnnotationsList list, DexFile dexFile)362     public void addParameterAnnotations(CstMethodRef method,
363             AnnotationsList list, DexFile dexFile) {
364         annotationsDirectory.addParameterAnnotations(method, list, dexFile);
365     }
366 
367     /**
368      * Gets the method annotations for a given method, if any. This is
369      * meant for use by debugging / dumping code.
370      *
371      * @param method {@code non-null;} the method
372      * @return {@code null-ok;} the method annotations, if any
373      */
getMethodAnnotations(CstMethodRef method)374     public Annotations getMethodAnnotations(CstMethodRef method) {
375         return annotationsDirectory.getMethodAnnotations(method);
376     }
377 
378     /**
379      * Gets the parameter annotations for a given method, if any. This is
380      * meant for use by debugging / dumping code.
381      *
382      * @param method {@code non-null;} the method
383      * @return {@code null-ok;} the parameter annotations, if any
384      */
getParameterAnnotations(CstMethodRef method)385     public AnnotationsList getParameterAnnotations(CstMethodRef method) {
386         return annotationsDirectory.getParameterAnnotations(method);
387     }
388 
389     /**
390      * Prints out the contents of this instance, in a debugging-friendly
391      * way.
392      *
393      * @param out {@code non-null;} where to output to
394      * @param verbose whether to be verbose with the output
395      */
debugPrint(Writer out, boolean verbose)396     public void debugPrint(Writer out, boolean verbose) {
397         PrintWriter pw = Writers.printWriterFor(out);
398 
399         pw.println(getClass().getName() + " {");
400         pw.println("  accessFlags: " + Hex.u2(accessFlags));
401         pw.println("  superclass: " + superclass);
402         pw.println("  interfaces: " +
403                 ((interfaces == null) ? "<none>" : interfaces));
404         pw.println("  sourceFile: " +
405                 ((sourceFile == null) ? "<none>" : sourceFile.toQuoted()));
406 
407         classData.debugPrint(out, verbose);
408         annotationsDirectory.debugPrint(pw);
409 
410         pw.println("}");
411     }
412 }
413