blob: 5e321e267e9357850df03c068558bfdcfcc7be1f [file] [log] [blame]
Richard Uhlerb730b782015-07-15 16:01:58 -07001/*
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
17package com.android.ahat;
18
19import com.android.tools.perflib.heap.ArrayInstance;
20import com.android.tools.perflib.heap.ClassInstance;
21import com.android.tools.perflib.heap.ClassObj;
22import com.android.tools.perflib.heap.Field;
23import com.android.tools.perflib.heap.Heap;
24import com.android.tools.perflib.heap.Instance;
25import com.android.tools.perflib.heap.RootObj;
26import java.io.IOException;
27import java.util.ArrayList;
28import java.util.Collections;
29import java.util.List;
30import java.util.Map;
31
32class ObjectHandler extends AhatHandler {
33 public ObjectHandler(AhatSnapshot snapshot) {
34 super(snapshot);
35 }
36
37 @Override
38 public void handle(Doc doc, Query query) throws IOException {
39 long id = query.getLong("id", 0);
40 Instance inst = mSnapshot.findInstance(id);
41 if (inst == null) {
Richard Uhlerc21e4e62015-08-31 16:16:14 -070042 doc.println(DocString.format("No object with id %08xl", id));
Richard Uhlerb730b782015-07-15 16:01:58 -070043 return;
44 }
45
46 doc.title("Object %08x", inst.getUniqueId());
47 doc.big(Value.render(inst));
48
49 printAllocationSite(doc, inst);
50 printDominatorPath(doc, inst);
51
52 doc.section("Object Info");
53 ClassObj cls = inst.getClassObj();
54 doc.descriptions();
55 doc.description(DocString.text("Class"), Value.render(cls));
Richard Uhlerc21e4e62015-08-31 16:16:14 -070056 doc.description(DocString.text("Size"), DocString.format("%d", inst.getSize()));
Richard Uhlerb730b782015-07-15 16:01:58 -070057 doc.description(
58 DocString.text("Retained Size"),
Richard Uhlerc21e4e62015-08-31 16:16:14 -070059 DocString.format("%d", inst.getTotalRetainedSize()));
Richard Uhlerb730b782015-07-15 16:01:58 -070060 doc.description(DocString.text("Heap"), DocString.text(inst.getHeap().getName()));
61 doc.end();
62
63 printBitmap(doc, inst);
64 if (inst instanceof ClassInstance) {
65 printClassInstanceFields(doc, (ClassInstance)inst);
66 } else if (inst instanceof ArrayInstance) {
67 printArrayElements(doc, (ArrayInstance)inst);
68 } else if (inst instanceof ClassObj) {
69 printClassInfo(doc, (ClassObj)inst);
70 }
71 printReferences(doc, inst);
72 printDominatedObjects(doc, query, inst);
73 }
74
75 private static void printClassInstanceFields(Doc doc, ClassInstance inst) {
76 doc.section("Fields");
77 doc.table(new Column("Type"), new Column("Name"), new Column("Value"));
78 for (ClassInstance.FieldValue field : inst.getValues()) {
79 doc.row(
80 DocString.text(field.getField().getType().toString()),
81 DocString.text(field.getField().getName()),
82 Value.render(field.getValue()));
83 }
84 doc.end();
85 }
86
87 private static void printArrayElements(Doc doc, ArrayInstance array) {
88 doc.section("Array Elements");
89 doc.table(new Column("Index", Column.Align.RIGHT), new Column("Value"));
90 Object[] elements = array.getValues();
91 for (int i = 0; i < elements.length; i++) {
Richard Uhlerc21e4e62015-08-31 16:16:14 -070092 doc.row(DocString.format("%d", i), Value.render(elements[i]));
Richard Uhlerb730b782015-07-15 16:01:58 -070093 }
94 doc.end();
95 }
96
97 private static void printClassInfo(Doc doc, ClassObj clsobj) {
98 doc.section("Class Info");
99 doc.descriptions();
100 doc.description(DocString.text("Super Class"), Value.render(clsobj.getSuperClassObj()));
101 doc.description(DocString.text("Class Loader"), Value.render(clsobj.getClassLoader()));
102 doc.end();
103
104 doc.section("Static Fields");
105 doc.table(new Column("Type"), new Column("Name"), new Column("Value"));
106 for (Map.Entry<Field, Object> field : clsobj.getStaticFieldValues().entrySet()) {
107 doc.row(
108 DocString.text(field.getKey().getType().toString()),
109 DocString.text(field.getKey().getName()),
110 Value.render(field.getValue()));
111 }
112 doc.end();
113 }
114
115 private static void printReferences(Doc doc, Instance inst) {
116 doc.section("Objects with References to this Object");
117 if (inst.getHardReferences().isEmpty()) {
118 doc.println(DocString.text("(none)"));
119 } else {
120 doc.table(new Column("Object"));
121 for (Instance ref : inst.getHardReferences()) {
122 doc.row(Value.render(ref));
123 }
124 doc.end();
125 }
126
127 if (inst.getSoftReferences() != null) {
128 doc.section("Objects with Soft References to this Object");
129 doc.table(new Column("Object"));
130 for (Instance ref : inst.getSoftReferences()) {
131 doc.row(Value.render(inst));
132 }
133 doc.end();
134 }
135 }
136
137 private void printAllocationSite(Doc doc, Instance inst) {
138 doc.section("Allocation Site");
139 Site site = mSnapshot.getSiteForInstance(inst);
140 SitePrinter.printSite(doc, mSnapshot, site);
141 }
142
143 // Draw the bitmap corresponding to this instance if there is one.
144 private static void printBitmap(Doc doc, Instance inst) {
145 Instance bitmap = InstanceUtils.getAssociatedBitmapInstance(inst);
146 if (bitmap != null) {
147 doc.section("Bitmap Image");
148 doc.println(DocString.image(
Richard Uhlerc21e4e62015-08-31 16:16:14 -0700149 DocString.formattedUri("bitmap?id=%d", bitmap.getId()), "bitmap image"));
Richard Uhlerb730b782015-07-15 16:01:58 -0700150 }
151 }
152
153 private void printDominatorPath(Doc doc, Instance inst) {
154 doc.section("Dominator Path from Root");
155 List<Instance> path = new ArrayList<Instance>();
156 for (Instance parent = inst;
157 parent != null && !(parent instanceof RootObj);
158 parent = parent.getImmediateDominator()) {
159 path.add(parent);
160 }
161
162 // Add 'null' as a marker for the root.
163 path.add(null);
164 Collections.reverse(path);
165
166 HeapTable.TableConfig<Instance> table = new HeapTable.TableConfig<Instance>() {
167 public String getHeapsDescription() {
168 return "Bytes Retained by Heap";
169 }
170
171 public long getSize(Instance element, Heap heap) {
172 if (element == null) {
173 return mSnapshot.getHeapSize(heap);
174 }
175 int index = mSnapshot.getHeapIndex(heap);
176 return element.getRetainedSize(index);
177 }
178
179 public List<HeapTable.ValueConfig<Instance>> getValueConfigs() {
180 HeapTable.ValueConfig<Instance> value = new HeapTable.ValueConfig<Instance>() {
181 public String getDescription() {
182 return "Object";
183 }
184
185 public DocString render(Instance element) {
186 if (element == null) {
187 return DocString.link(DocString.uri("roots"), DocString.text("ROOT"));
188 } else {
189 return DocString.text("→ ").append(Value.render(element));
190 }
191 }
192 };
193 return Collections.singletonList(value);
194 }
195 };
196 HeapTable.render(doc, table, mSnapshot, path);
197 }
198
199 public void printDominatedObjects(Doc doc, Query query, Instance inst) {
200 doc.section("Immediately Dominated Objects");
201 List<Instance> instances = mSnapshot.getDominated(inst);
202 if (instances != null) {
203 DominatedList.render(mSnapshot, doc, instances, query);
204 } else {
205 doc.println(DocString.text("(none)"));
206 }
207 }
208}
209