• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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;
18 
19 import com.android.tools.perflib.heap.ArrayInstance;
20 import com.android.tools.perflib.heap.ClassInstance;
21 import com.android.tools.perflib.heap.ClassObj;
22 import com.android.tools.perflib.heap.Field;
23 import com.android.tools.perflib.heap.Heap;
24 import com.android.tools.perflib.heap.Instance;
25 import com.android.tools.perflib.heap.RootObj;
26 import com.android.tools.perflib.heap.RootType;
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Map;
34 
35 class ObjectHandler implements AhatHandler {
36 
37   private static final String ARRAY_ELEMENTS_ID = "elements";
38   private static final String DOMINATOR_PATH_ID = "dompath";
39   private static final String ALLOCATION_SITE_ID = "frames";
40   private static final String DOMINATED_OBJECTS_ID = "dominated";
41   private static final String INSTANCE_FIELDS_ID = "ifields";
42   private static final String STATIC_FIELDS_ID = "sfields";
43   private static final String HARD_REFS_ID = "refs";
44   private static final String SOFT_REFS_ID = "srefs";
45 
46   private AhatSnapshot mSnapshot;
47 
ObjectHandler(AhatSnapshot snapshot)48   public ObjectHandler(AhatSnapshot snapshot) {
49     mSnapshot = snapshot;
50   }
51 
52   @Override
handle(Doc doc, Query query)53   public void handle(Doc doc, Query query) throws IOException {
54     long id = query.getLong("id", 0);
55     Instance inst = mSnapshot.findInstance(id);
56     if (inst == null) {
57       doc.println(DocString.format("No object with id %08xl", id));
58       return;
59     }
60 
61     doc.title("Object %08x", inst.getUniqueId());
62     doc.big(Value.render(mSnapshot, inst));
63 
64     printAllocationSite(doc, query, inst);
65     printDominatorPath(doc, query, inst);
66 
67     doc.section("Object Info");
68     ClassObj cls = inst.getClassObj();
69     doc.descriptions();
70     doc.description(DocString.text("Class"), Value.render(mSnapshot, cls));
71     doc.description(DocString.text("Size"), DocString.format("%d", inst.getSize()));
72     doc.description(
73         DocString.text("Retained Size"),
74         DocString.format("%d", inst.getTotalRetainedSize()));
75     doc.description(DocString.text("Heap"), DocString.text(inst.getHeap().getName()));
76 
77     Collection<RootType> rootTypes = mSnapshot.getRootTypes(inst);
78     if (rootTypes != null) {
79       DocString types = new DocString();
80       String comma = "";
81       for (RootType type : rootTypes) {
82         types.append(comma);
83         types.append(type.getName());
84         comma = ", ";
85       }
86       doc.description(DocString.text("Root Types"), types);
87     }
88 
89     doc.end();
90 
91     printBitmap(doc, inst);
92     if (inst instanceof ClassInstance) {
93       printClassInstanceFields(doc, query, mSnapshot, (ClassInstance)inst);
94     } else if (inst instanceof ArrayInstance) {
95       printArrayElements(doc, query, mSnapshot, (ArrayInstance)inst);
96     } else if (inst instanceof ClassObj) {
97       printClassInfo(doc, query, mSnapshot, (ClassObj)inst);
98     }
99     printReferences(doc, query, mSnapshot, inst);
100     printDominatedObjects(doc, query, inst);
101   }
102 
printClassInstanceFields( Doc doc, Query query, AhatSnapshot snapshot, ClassInstance inst)103   private static void printClassInstanceFields(
104       Doc doc, Query query, AhatSnapshot snapshot, ClassInstance inst) {
105     doc.section("Fields");
106     doc.table(new Column("Type"), new Column("Name"), new Column("Value"));
107     SubsetSelector<ClassInstance.FieldValue> selector
108       = new SubsetSelector(query, INSTANCE_FIELDS_ID, inst.getValues());
109     for (ClassInstance.FieldValue field : selector.selected()) {
110       doc.row(
111           DocString.text(field.getField().getType().toString()),
112           DocString.text(field.getField().getName()),
113           Value.render(snapshot, field.getValue()));
114     }
115     doc.end();
116     selector.render(doc);
117   }
118 
printArrayElements( Doc doc, Query query, AhatSnapshot snapshot, ArrayInstance array)119   private static void printArrayElements(
120       Doc doc, Query query, AhatSnapshot snapshot, ArrayInstance array) {
121     doc.section("Array Elements");
122     doc.table(new Column("Index", Column.Align.RIGHT), new Column("Value"));
123     List<Object> elements = Arrays.asList(array.getValues());
124     SubsetSelector<Object> selector = new SubsetSelector(query, ARRAY_ELEMENTS_ID, elements);
125     int i = 0;
126     for (Object elem : selector.selected()) {
127       doc.row(DocString.format("%d", i), Value.render(snapshot, elem));
128       i++;
129     }
130     doc.end();
131     selector.render(doc);
132   }
133 
printClassInfo( Doc doc, Query query, AhatSnapshot snapshot, ClassObj clsobj)134   private static void printClassInfo(
135       Doc doc, Query query, AhatSnapshot snapshot, ClassObj clsobj) {
136     doc.section("Class Info");
137     doc.descriptions();
138     doc.description(DocString.text("Super Class"),
139         Value.render(snapshot, clsobj.getSuperClassObj()));
140     doc.description(DocString.text("Class Loader"),
141         Value.render(snapshot, clsobj.getClassLoader()));
142     doc.end();
143 
144     doc.section("Static Fields");
145     doc.table(new Column("Type"), new Column("Name"), new Column("Value"));
146     List<Map.Entry<Field, Object>> fields
147       = new ArrayList<Map.Entry<Field, Object>>(clsobj.getStaticFieldValues().entrySet());
148     SubsetSelector<Map.Entry<Field, Object>> selector
149       = new SubsetSelector(query, STATIC_FIELDS_ID, fields);
150     for (Map.Entry<Field, Object> field : selector.selected()) {
151       doc.row(
152           DocString.text(field.getKey().getType().toString()),
153           DocString.text(field.getKey().getName()),
154           Value.render(snapshot, field.getValue()));
155     }
156     doc.end();
157     selector.render(doc);
158   }
159 
printReferences( Doc doc, Query query, AhatSnapshot snapshot, Instance inst)160   private static void printReferences(
161       Doc doc, Query query, AhatSnapshot snapshot, Instance inst) {
162     doc.section("Objects with References to this Object");
163     if (inst.getHardReferences().isEmpty()) {
164       doc.println(DocString.text("(none)"));
165     } else {
166       doc.table(new Column("Object"));
167       List<Instance> references = inst.getHardReferences();
168       SubsetSelector<Instance> selector = new SubsetSelector(query, HARD_REFS_ID, references);
169       for (Instance ref : selector.selected()) {
170         doc.row(Value.render(snapshot, ref));
171       }
172       doc.end();
173       selector.render(doc);
174     }
175 
176     if (inst.getSoftReferences() != null) {
177       doc.section("Objects with Soft References to this Object");
178       doc.table(new Column("Object"));
179       List<Instance> references = inst.getSoftReferences();
180       SubsetSelector<Instance> selector = new SubsetSelector(query, SOFT_REFS_ID, references);
181       for (Instance ref : selector.selected()) {
182         doc.row(Value.render(snapshot, ref));
183       }
184       doc.end();
185       selector.render(doc);
186     }
187   }
188 
printAllocationSite(Doc doc, Query query, Instance inst)189   private void printAllocationSite(Doc doc, Query query, Instance inst) {
190     doc.section("Allocation Site");
191     Site site = mSnapshot.getSiteForInstance(inst);
192     SitePrinter.printSite(mSnapshot, doc, query, ALLOCATION_SITE_ID, site);
193   }
194 
195   // Draw the bitmap corresponding to this instance if there is one.
printBitmap(Doc doc, Instance inst)196   private static void printBitmap(Doc doc, Instance inst) {
197     Instance bitmap = InstanceUtils.getAssociatedBitmapInstance(inst);
198     if (bitmap != null) {
199       doc.section("Bitmap Image");
200       doc.println(DocString.image(
201             DocString.formattedUri("bitmap?id=%d", bitmap.getId()), "bitmap image"));
202     }
203   }
204 
printDominatorPath(Doc doc, Query query, Instance inst)205   private void printDominatorPath(Doc doc, Query query, Instance inst) {
206     doc.section("Dominator Path from Root");
207     List<Instance> path = new ArrayList<Instance>();
208     for (Instance parent = inst;
209         parent != null && !(parent instanceof RootObj);
210         parent = parent.getImmediateDominator()) {
211       path.add(parent);
212     }
213 
214     // Add 'null' as a marker for the root.
215     path.add(null);
216     Collections.reverse(path);
217 
218     HeapTable.TableConfig<Instance> table = new HeapTable.TableConfig<Instance>() {
219       public String getHeapsDescription() {
220         return "Bytes Retained by Heap";
221       }
222 
223       public long getSize(Instance element, Heap heap) {
224         if (element == null) {
225           return mSnapshot.getHeapSize(heap);
226         }
227         int index = mSnapshot.getHeapIndex(heap);
228         return element.getRetainedSize(index);
229       }
230 
231       public List<HeapTable.ValueConfig<Instance>> getValueConfigs() {
232         HeapTable.ValueConfig<Instance> value = new HeapTable.ValueConfig<Instance>() {
233           public String getDescription() {
234             return "Object";
235           }
236 
237           public DocString render(Instance element) {
238             if (element == null) {
239               return DocString.link(DocString.uri("rooted"), DocString.text("ROOT"));
240             } else {
241               return DocString.text("→ ").append(Value.render(mSnapshot, element));
242             }
243           }
244         };
245         return Collections.singletonList(value);
246       }
247     };
248     HeapTable.render(doc, query, DOMINATOR_PATH_ID, table, mSnapshot, path);
249   }
250 
printDominatedObjects(Doc doc, Query query, Instance inst)251   public void printDominatedObjects(Doc doc, Query query, Instance inst) {
252     doc.section("Immediately Dominated Objects");
253     List<Instance> instances = mSnapshot.getDominated(inst);
254     if (instances != null) {
255       DominatedList.render(mSnapshot, doc, query, DOMINATED_OBJECTS_ID, instances);
256     } else {
257       doc.println(DocString.text("(none)"));
258     }
259   }
260 }
261 
262