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