• 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 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