1 /*
2  * Copyright (C) 2008 Google Inc.
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.hit;
18 
19 import java.io.ByteArrayInputStream;
20 import java.io.DataInputStream;
21 import java.util.ArrayList;
22 import java.util.HashSet;
23 import java.util.Set;
24 
25 public class ClassObj extends Instance implements Comparable<ClassObj> {
26     String mClassName;
27     long mSuperclassId;
28 
29     String[] mFieldNames;
30     int[] mFieldTypes;
31 
32     String[] mStaticFieldNames;
33     int[] mStaticFieldTypes;
34     byte[] mStaticFieldValues;
35 
36     ArrayList<Instance> mInstances = new ArrayList<Instance>();
37     Set<ClassObj> mSubclasses = new HashSet<ClassObj>();
38 
39     int mSize;
40 
ClassObj(long id, StackTrace stack, String className)41     public ClassObj(long id, StackTrace stack, String className) {
42         mId = id;
43         mStack = stack;
44         mClassName = className;
45     }
46 
47     @Override
resolveReferences(State state)48     public final void resolveReferences(State state) {
49         ByteArrayInputStream bais =
50             new ByteArrayInputStream(mStaticFieldValues);
51         DataInputStream dis = new DataInputStream(bais);
52         int[] types = mStaticFieldTypes;
53         final int N = types.length;
54 
55         /*
56          * Spin through the list of static fields, find all object references,
57          * and list ourselves as a reference holder.  Also add them to
58          * the list of root objects.
59          */
60         try {
61             for (int i = 0; i < N; i++) {
62                 int type = types[i];
63                 int size = Types.getTypeSize(type);
64 
65                 if (type == Types.OBJECT) {
66                     long id;
67 
68                     if (size == 4) {
69                         id = dis.readInt();
70                     } else {
71                         id = dis.readLong();
72                     }
73 
74                     RootObj root = new RootObj(RootType.JAVA_STATIC, id);
75 
76                     if (id == 0) {
77                         root.mComment = String.format(
78                             "Static field %s:%s null",
79                                 mClassName,
80                                 mStaticFieldNames[i]);
81                     } else {
82                         Instance instance = state.findReference(id);
83 
84                         instance.addParent(this);
85 
86                         root.mComment = String.format(
87                             "Static field %s:%s %s [%s] 0x%08x",
88                                 mClassName,
89                                 mStaticFieldNames[i],
90                                 instance.getTypeName(),
91                                 instance.mHeap.mName,
92                                 id);
93                     }
94 
95                     mHeap.addRoot(root);
96                 } else {
97                     dis.skipBytes(size);
98                 }
99             }
100         } catch (Exception e) {
101             e.printStackTrace();
102             System.exit(1);
103         }
104 
105         //  Lastly, add ourself as a subclass of our superclass
106         if (mSuperclassId != 0) {
107             ClassObj superclass = state.findClass(mSuperclassId);
108 
109             superclass.addSubclass(this);
110         }
111     }
112 
addSubclass(ClassObj subclass)113     public final void addSubclass(ClassObj subclass) {
114         mSubclasses.add(subclass);
115     }
116 
dumpSubclasses()117     public final void dumpSubclasses() {
118         for (ClassObj subclass: mSubclasses) {
119             System.out.println("     " + subclass.mClassName);
120         }
121     }
122 
toString()123     public final String toString() {
124         return mClassName.replace('/', '.');
125     }
126 
addInstance(Instance instance)127     public final void addInstance(Instance instance) {
128         mInstances.add(instance);
129     }
130 
setSuperclassId(long id)131     public final void setSuperclassId(long id) {
132         mSuperclassId = id;
133     }
134 
setFieldNames(String[] names)135     public final void setFieldNames(String[] names) {
136         mFieldNames = names;
137     }
138 
setFieldTypes(int[] types)139     public final void setFieldTypes(int[] types) {
140         mFieldTypes = types;
141     }
142 
setStaticFieldNames(String[] names)143     public final void setStaticFieldNames(String[] names) {
144         mStaticFieldNames = names;
145     }
146 
setStaticFieldTypes(int[] types)147     public final void setStaticFieldTypes(int[] types) {
148         mStaticFieldTypes = types;
149     }
150 
setStaticFieldValues(byte[] values)151     public final void setStaticFieldValues(byte[] values) {
152         mStaticFieldValues = values;
153     }
154 
dump()155     public final void dump() {
156         System.out.println("+----------  ClassObj dump for: " + mClassName);
157 
158         System.out.println("+-----  Static fields");
159 
160         for (int i = 0; i < mStaticFieldNames.length; i++) {
161             System.out.println(mStaticFieldNames[i] + ": "
162                 + mStaticFieldTypes[i]);
163         }
164 
165         System.out.println("+-----  Instance fields");
166 
167         for (int i = 0; i < mFieldNames.length; i++) {
168             System.out.println(mFieldNames[i] + ": " + mFieldTypes[i]);
169         }
170     }
171 
172     @Override
getTypeName()173     public final String getTypeName() {
174         return "class " + mClassName;
175     }
176 
177     @Override
visit(Set<Instance> resultSet, Filter filter)178     public final void visit(Set<Instance> resultSet, Filter filter) {
179         if (resultSet.contains(this)) {
180             return;
181         }
182 
183         if (filter != null) {
184             if (filter.accept(this)) {
185                 resultSet.add(this);
186             }
187         } else {
188             resultSet.add(this);
189         }
190 
191         ByteArrayInputStream bais =
192             new ByteArrayInputStream(mStaticFieldValues);
193         DataInputStream dis = new DataInputStream(bais);
194         int[] types = mStaticFieldTypes;
195         final int N = types.length;
196         State state = mHeap.mState;
197 
198         /*
199          * Spin through the list of static fields, find all object references,
200          * and visit them.
201          */
202         try {
203             for (int i = 0; i < N; i++) {
204                 int type = types[i];
205                 int size = Types.getTypeSize(type);
206 
207                 if (type == Types.OBJECT) {
208                     long id;
209 
210                     if (size == 4) {
211                         id = dis.readInt();
212                     } else {
213                         id = dis.readLong();
214                     }
215 
216                     Instance instance = state.findReference(id);
217 
218                     if (instance != null) {
219                         instance.visit(resultSet, filter);
220                     }
221                 } else {
222                     dis.skipBytes(size);
223                 }
224             }
225         } catch (Exception e) {
226             e.printStackTrace();
227         }
228     }
229 
compareTo(ClassObj o)230     public final int compareTo(ClassObj o) {
231         return mClassName.compareTo(o.mClassName);
232     }
233 
equals(Object o)234     public final boolean equals(Object o) {
235         if (! (o instanceof ClassObj)) {
236             return false;
237         }
238 
239         return 0 == compareTo((ClassObj) o);
240     }
241 }
242