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