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.dx.dex.file;
     18 
     19 import com.android.dx.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      */
     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