blob: 7ee3ff24ed65a3646fc73e1dee108872b7d92439 [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.Instance;
23import com.android.tools.perflib.heap.Type;
24import java.awt.image.BufferedImage;
25
26/**
27 * Utilities for extracting information from hprof instances.
28 */
29class InstanceUtils {
30 /**
31 * Returns true if the given instance is an instance of a class with the
32 * given name.
33 */
34 public static boolean isInstanceOfClass(Instance inst, String className) {
35 ClassObj cls = inst.getClassObj();
36 return (cls != null && className.equals(cls.getClassName()));
37 }
38
39 /**
40 * Read the char[] value from an hprof Instance.
41 * Returns null if the object can't be interpreted as a char[].
42 */
43 private static char[] asCharArray(Instance inst) {
44 if (! (inst instanceof ArrayInstance)) {
45 return null;
46 }
47
48 ArrayInstance array = (ArrayInstance) inst;
49 if (array.getArrayType() != Type.CHAR) {
50 return null;
51 }
52 return array.asCharArray(0, array.getValues().length);
53 }
54
55 /**
56 * Read the byte[] value from an hprof Instance.
57 * Returns null if the instance is not a byte array.
58 */
59 private static byte[] asByteArray(Instance inst) {
60 if (! (inst instanceof ArrayInstance)) {
61 return null;
62 }
63
64 ArrayInstance array = (ArrayInstance)inst;
65 if (array.getArrayType() != Type.BYTE) {
66 return null;
67 }
68
69 Object[] objs = array.getValues();
70 byte[] bytes = new byte[objs.length];
71 for (int i = 0; i < objs.length; i++) {
72 Byte b = (Byte)objs[i];
73 bytes[i] = b.byteValue();
74 }
75 return bytes;
76 }
77
78
79 // Read the string value from an hprof Instance.
80 // Returns null if the object can't be interpreted as a string.
81 public static String asString(Instance inst) {
82 if (!isInstanceOfClass(inst, "java.lang.String")) {
83 return null;
84 }
85 char[] value = getCharArrayField(inst, "value");
86 return (value == null) ? null : new String(value);
87 }
88
89 /**
90 * Read the bitmap data for the given android.graphics.Bitmap object.
91 * Returns null if the object isn't for android.graphics.Bitmap or the
92 * bitmap data couldn't be read.
93 */
94 public static BufferedImage asBitmap(Instance inst) {
95 if (!isInstanceOfClass(inst, "android.graphics.Bitmap")) {
96 return null;
97 }
98
99 Integer width = getIntField(inst, "mWidth");
100 if (width == null) {
101 return null;
102 }
103
104 Integer height = getIntField(inst, "mHeight");
105 if (height == null) {
106 return null;
107 }
108
109 byte[] buffer = getByteArrayField(inst, "mBuffer");
110 if (buffer == null) {
111 return null;
112 }
113
114 // Convert the raw data to an image
115 // Convert BGRA to ABGR
116 int[] abgr = new int[height * width];
117 for (int i = 0; i < abgr.length; i++) {
118 abgr[i] = (
119 (((int)buffer[i * 4 + 3] & 0xFF) << 24) +
120 (((int)buffer[i * 4 + 0] & 0xFF) << 16) +
121 (((int)buffer[i * 4 + 1] & 0xFF) << 8) +
122 ((int)buffer[i * 4 + 2] & 0xFF));
123 }
124
125 BufferedImage bitmap = new BufferedImage(
126 width, height, BufferedImage.TYPE_4BYTE_ABGR);
127 bitmap.setRGB(0, 0, width, height, abgr, 0, width);
128 return bitmap;
129 }
130
131 /**
132 * Read a field of an instance.
133 * Returns null if the field value is null or if the field couldn't be read.
134 */
135 private static Object getField(Instance inst, String fieldName) {
136 if (!(inst instanceof ClassInstance)) {
137 return null;
138 }
139
140 ClassInstance clsinst = (ClassInstance) inst;
141 Object value = null;
142 int count = 0;
143 for (ClassInstance.FieldValue field : clsinst.getValues()) {
144 if (fieldName.equals(field.getField().getName())) {
145 value = field.getValue();
146 count++;
147 }
148 }
149 return count == 1 ? value : null;
150 }
151
152 /**
153 * Read a reference field of an instance.
154 * Returns null if the field value is null, or if the field couldn't be read.
155 */
156 private static Instance getRefField(Instance inst, String fieldName) {
157 Object value = getField(inst, fieldName);
158 if (!(value instanceof Instance)) {
159 return null;
160 }
161 return (Instance)value;
162 }
163
164 /**
165 * Read an int field of an instance.
166 * The field is assumed to be an int type.
167 * Returns null if the field value is not an int or could not be read.
168 */
169 private static Integer getIntField(Instance inst, String fieldName) {
170 Object value = getField(inst, fieldName);
171 if (!(value instanceof Integer)) {
172 return null;
173 }
174 return (Integer)value;
175 }
176
177 /**
178 * Read the given field from the given instance.
179 * The field is assumed to be a byte[] field.
180 * Returns null if the field value is null, not a byte[] or could not be read.
181 */
182 private static byte[] getByteArrayField(Instance inst, String fieldName) {
183 Object value = getField(inst, fieldName);
184 if (!(value instanceof Instance)) {
185 return null;
186 }
187 return asByteArray((Instance)value);
188 }
189
190 private static char[] getCharArrayField(Instance inst, String fieldName) {
191 Object value = getField(inst, fieldName);
192 if (!(value instanceof Instance)) {
193 return null;
194 }
195 return asCharArray((Instance)value);
196 }
197
198 // Return the bitmap instance associated with this object, or null if there
199 // is none. This works for android.graphics.Bitmap instances and their
200 // underlying Byte[] instances.
201 public static Instance getAssociatedBitmapInstance(Instance inst) {
202 ClassObj cls = inst.getClassObj();
203 if (cls == null) {
204 return null;
205 }
206
207 if ("android.graphics.Bitmap".equals(cls.getClassName())) {
208 return inst;
209 }
210
211 if (inst instanceof ArrayInstance) {
212 ArrayInstance array = (ArrayInstance)inst;
213 if (array.getArrayType() == Type.BYTE && inst.getHardReferences().size() == 1) {
214 Instance ref = inst.getHardReferences().get(0);
215 ClassObj clsref = ref.getClassObj();
216 if (clsref != null && "android.graphics.Bitmap".equals(clsref.getClassName())) {
217 return ref;
218 }
219 }
220 }
221 return null;
222 }
223
224 /**
225 * Assuming inst represents a DexCache object, return the dex location for
226 * that dex cache. Returns null if the given instance doesn't represent a
227 * DexCache object or the location could not be found.
228 */
229 public static String getDexCacheLocation(Instance inst) {
230 if (isInstanceOfClass(inst, "java.lang.DexCache")) {
231 Instance location = getRefField(inst, "location");
232 if (location != null) {
233 return asString(location);
234 }
235 }
236 return null;
237 }
238}