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 41 public ClassObj(long id, StackTrace stack, String className) { 42 mId = id; 43 mStack = stack; 44 mClassName = className; 45 } 46 47 @Override 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 113 public final void addSubclass(ClassObj subclass) { 114 mSubclasses.add(subclass); 115 } 116 117 public final void dumpSubclasses() { 118 for (ClassObj subclass: mSubclasses) { 119 System.out.println(" " + subclass.mClassName); 120 } 121 } 122 123 public final String toString() { 124 return mClassName.replace('/', '.'); 125 } 126 127 public final void addInstance(Instance instance) { 128 mInstances.add(instance); 129 } 130 131 public final void setSuperclassId(long id) { 132 mSuperclassId = id; 133 } 134 135 public final void setFieldNames(String[] names) { 136 mFieldNames = names; 137 } 138 139 public final void setFieldTypes(int[] types) { 140 mFieldTypes = types; 141 } 142 143 public final void setStaticFieldNames(String[] names) { 144 mStaticFieldNames = names; 145 } 146 147 public final void setStaticFieldTypes(int[] types) { 148 mStaticFieldTypes = types; 149 } 150 151 public final void setStaticFieldValues(byte[] values) { 152 mStaticFieldValues = values; 153 } 154 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 173 public final String getTypeName() { 174 return "class " + mClassName; 175 } 176 177 @Override 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 230 public final int compareTo(ClassObj o) { 231 return mClassName.compareTo(o.mClassName); 232 } 233 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