1 /*
2  * Copyright (C) 2016 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.ahat.heapdump;
18 
19 import java.util.AbstractList;
20 import java.util.Arrays;
21 import java.util.List;
22 
23 /**
24  * A class from a parsed heap dump.
25  * In addition to those methods inherited from {@link AhatInstance}, the class
26  * provides methods for accessing information about the class object, such as
27  * the class loader, superclass, static field values and instance field
28  * descriptors.
29  */
30 public class AhatClassObj extends AhatInstance {
31   private String mClassName;
32   private AhatClassObj mSuperClassObj;
33   private AhatInstance mClassLoader;
34   private FieldValue[] mStaticFieldValues;
35   private Field[] mInstanceFields;
36   private long mStaticFieldsSize;
37   private long mInstanceSize;
38 
AhatClassObj(long id, String className)39   AhatClassObj(long id, String className) {
40     super(id);
41     mClassName = className;
42   }
43 
initialize(AhatClassObj superClass, long instanceSize, Field[] instanceFields, long staticFieldsSize)44   void initialize(AhatClassObj superClass,
45                   long instanceSize,
46                   Field[] instanceFields,
47                   long staticFieldsSize) {
48     mSuperClassObj = superClass;
49     mInstanceSize = instanceSize;
50     mInstanceFields = instanceFields;
51     mStaticFieldsSize = staticFieldsSize;
52   }
53 
initialize(AhatInstance classLoader, FieldValue[] staticFields)54   void initialize(AhatInstance classLoader, FieldValue[] staticFields) {
55     mClassLoader = classLoader;
56     mStaticFieldValues = staticFields;
57   }
58 
59   @Override
getExtraJavaSize()60   long getExtraJavaSize() {
61     return mStaticFieldsSize;
62   }
63 
64   /**
65    * Returns the name of the class this is a class object for.
66    * For example, "java.lang.String".
67    *
68    * @return the name of the class
69    */
getName()70   public String getName() {
71     return mClassName;
72   }
73 
74   /**
75    * Returns the superclass of this class object.
76    *
77    * @return the superclass object
78    */
getSuperClassObj()79   public AhatClassObj getSuperClassObj() {
80     return mSuperClassObj;
81   }
82 
83   /**
84    * Returns the class loader of this class object.
85    *
86    * @return the class loader object
87    */
getClassLoader()88   public AhatInstance getClassLoader() {
89     return mClassLoader;
90   }
91 
92   /**
93    * Returns the size of instances of this object.
94    * The size returned is as reported in the heap dump.
95    *
96    * @return the class instance size
97    */
getInstanceSize()98   public long getInstanceSize() {
99     return mInstanceSize;
100   }
101 
102   /**
103    * Returns the static field values for this class object.
104    *
105    * @return the static field values
106    */
getStaticFieldValues()107   public List<FieldValue> getStaticFieldValues() {
108     return Arrays.asList(mStaticFieldValues);
109   }
110 
111   /**
112    * Returns the value of a static field of this class. Returns null if the
113    * field value is null, or the field couldn't be found.
114    *
115    * @param fieldName the name of the static field to get the value of
116    * @return the field value
117    */
getStaticField(String fieldName)118   public Value getStaticField(String fieldName) {
119     for (FieldValue field : mStaticFieldValues) {
120       if (fieldName.equals(field.name)) {
121         return field.value;
122       }
123     }
124     return null;
125   }
126 
127   /**
128    * Returns the fields of instances of this class.
129    * Does not include fields from the super class of this class.
130    *
131    * @return the instance fields
132    */
getInstanceFields()133   public Field[] getInstanceFields() {
134     return mInstanceFields;
135   }
136 
137   @Override
getReferences()138   Iterable<Reference> getReferences() {
139     List<Reference> refs = new AbstractList<Reference>() {
140       @Override
141       public int size() {
142         return mStaticFieldValues.length;
143       }
144 
145       @Override
146       public Reference get(int index) {
147         FieldValue field = mStaticFieldValues[index];
148         Value value = field.value;
149         if (value != null && value.isAhatInstance()) {
150           return new Reference(AhatClassObj.this,
151                                "." + field.name,
152                                value.asAhatInstance(),
153                                Reachability.STRONG);
154         }
155         return null;
156       }
157     };
158     return new SkipNullsIterator(refs);
159   }
160 
isClassObj()161   @Override public boolean isClassObj() {
162     return true;
163   }
164 
165   /**
166    * Returns true if this is a subclass of another class with the given name.
167    *
168    * @param className the name of the class to check for subclass
169    * @return true if this is a subclass of another class with the given name
170    */
isSubClassOf(String className)171   public boolean isSubClassOf(String className) {
172     AhatClassObj cls = this;
173     while (cls != null) {
174       if (className.equals(cls.getName())) {
175         return true;
176       }
177       cls = cls.getSuperClassObj();
178     }
179     return false;
180   }
181 
asClassObj()182   @Override public AhatClassObj asClassObj() {
183     return this;
184   }
185 
toString()186   @Override public String toString() {
187     return "class " + mClassName;
188   }
189 
newPlaceHolderInstance()190   @Override AhatInstance newPlaceHolderInstance() {
191     return new AhatPlaceHolderClassObj(this);
192   }
193 }
194