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.ahat.heapdump.AhatClassObj; 20 import com.android.ahat.heapdump.AhatInstance; 21 import com.android.ahat.heapdump.Reachability; 22 import com.android.ahat.heapdump.Site; 23 import com.android.ahat.heapdump.Value; 24 import java.net.URI; 25 26 /** 27 * Class for generating a DocString summary of an instance or value. 28 */ 29 class Summarizer { 30 31 // For string literals, we limit the number of characters we show to 32 // kMaxChars in case the string is really long. 33 private static int kMaxChars = 200; 34 35 /** 36 * Creates a DocString representing a summary of the given instance. 37 */ summarize(AhatInstance inst)38 public static DocString summarize(AhatInstance inst) { 39 DocString formatted = new DocString(); 40 if (inst == null) { 41 formatted.append("null"); 42 return formatted; 43 } 44 45 // Annotate new objects as new. 46 if (inst.getBaseline().isPlaceHolder()) { 47 formatted.append(DocString.added("new ")); 48 } 49 50 // Annotate deleted objects as deleted. 51 if (inst.isPlaceHolder()) { 52 formatted.append(DocString.removed("del ")); 53 } 54 55 // Annotate non-strongly reachable objects as such. 56 Reachability reachability = inst.getReachability(); 57 if (reachability != Reachability.STRONG) { 58 formatted.append(reachability.toString() + " "); 59 } 60 61 // Annotate roots as roots. 62 if (inst.isRoot()) { 63 formatted.append("root "); 64 } 65 66 DocString linkText = DocString.text(inst.toString()); 67 if (inst.isPlaceHolder()) { 68 // Don't make links to placeholder objects. 69 formatted.append(linkText); 70 } else { 71 URI objTarget = DocString.formattedUri("object?id=0x%x", inst.getId()); 72 formatted.appendLink(objTarget, linkText); 73 } 74 75 // Annotate Strings with their values. 76 String stringValue = inst.asString(kMaxChars); 77 if (stringValue != null) { 78 formatted.appendFormat(" \"%s", stringValue); 79 formatted.append(kMaxChars == stringValue.length() ? "..." : "\""); 80 } 81 82 // Annotate Reference with its referent 83 AhatInstance referent = inst.getReferent(); 84 if (referent != null) { 85 formatted.append(" for "); 86 87 // It should not be possible for a referent to refer back to the 88 // reference object, even indirectly, so there shouldn't be any issues 89 // with infinite recursion here. 90 formatted.append(summarize(referent)); 91 } 92 93 // Annotate DexCache with its location. 94 String dexCacheLocation = inst.getDexCacheLocation(kMaxChars); 95 if (dexCacheLocation != null) { 96 formatted.appendFormat(" for %s", dexCacheLocation); 97 if (kMaxChars == dexCacheLocation.length()) { 98 formatted.append("..."); 99 } 100 } 101 102 // Annotate bitmaps with a thumbnail. 103 AhatInstance bitmap = inst.getAssociatedBitmapInstance(); 104 if (bitmap != null) { 105 URI uri = DocString.formattedUri("bitmap?id=0x%x", bitmap.getId()); 106 formatted.appendThumbnail(uri, "bitmap image"); 107 } 108 109 // Annotate $classOverhead arrays 110 AhatClassObj cls = inst.getAssociatedClassForOverhead(); 111 if (cls != null) { 112 formatted.append(" overhead for "); 113 formatted.append(summarize(cls)); 114 } 115 116 // Annotate BinderProxy with its interface name. 117 String binderProxyInterface = inst.getBinderProxyInterfaceName(); 118 if (binderProxyInterface != null) { 119 formatted.appendFormat(" for %s", binderProxyInterface); 120 } 121 122 // Annotate Binder tokens with their descriptor 123 String binderTokenDescriptor = inst.getBinderTokenDescriptor(); 124 if (binderTokenDescriptor != null) { 125 formatted.appendFormat(" binder token (%s)", binderTokenDescriptor); 126 } 127 // Annotate Binder services with their interface name. 128 String binderStubInterface = inst.getBinderStubInterfaceName(); 129 if (binderStubInterface != null) { 130 formatted.appendFormat(" binder service (%s)", binderStubInterface); 131 } 132 133 return formatted; 134 } 135 136 /** 137 * Creates a DocString summarizing the given value. 138 */ summarize(Value value)139 public static DocString summarize(Value value) { 140 if (value == null) { 141 return DocString.text("null"); 142 } 143 if (value.isAhatInstance()) { 144 return summarize(value.asAhatInstance()); 145 } 146 return DocString.text(value.toString()); 147 } 148 149 /** 150 * Creates a DocString summarizing the given site. 151 */ summarize(Site site)152 public static DocString summarize(Site site) { 153 DocString text = DocString.text(site.getMethodName()); 154 text.append(site.getSignature()); 155 text.append(" - "); 156 text.append(site.getFilename()); 157 if (site.getLineNumber() > 0) { 158 text.append(":").append(Integer.toString(site.getLineNumber())); 159 } 160 URI uri = DocString.formattedUri("site?id=%d", site.getId()); 161 return DocString.link(uri, text); 162 } 163 } 164