InstanceUtils.java revision b730b78dac047c6d8ead93ad77605bcb7414f5ce
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 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} 239