Annotate References with their referent.
Also, don't include annotations in an object's link. That way we can
distinguish between the object link and any links in the annotations.
Change-Id: I3fef3f5b2c343699f527cad9efa7c93a4b35a3a4
diff --git a/tools/ahat/src/InstanceUtils.java b/tools/ahat/src/InstanceUtils.java
index c2d75c4..7fa53c7 100644
--- a/tools/ahat/src/InstanceUtils.java
+++ b/tools/ahat/src/InstanceUtils.java
@@ -244,6 +244,24 @@
return null;
}
+ private static boolean isJavaLangRefReference(Instance inst) {
+ ClassObj cls = (inst == null) ? null : inst.getClassObj();
+ while (cls != null) {
+ if ("java.lang.ref.Reference".equals(cls.getClassName())) {
+ return true;
+ }
+ cls = cls.getSuperClassObj();
+ }
+ return false;
+ }
+
+ public static Instance getReferent(Instance inst) {
+ if (isJavaLangRefReference(inst)) {
+ return getRefField(inst, "referent");
+ }
+ return null;
+ }
+
/**
* Assuming inst represents a DexCache object, return the dex location for
* that dex cache. Returns null if the given instance doesn't represent a
diff --git a/tools/ahat/src/Value.java b/tools/ahat/src/Value.java
index 4eb27b1..7c969b3 100644
--- a/tools/ahat/src/Value.java
+++ b/tools/ahat/src/Value.java
@@ -45,25 +45,36 @@
}
link.append(inst.toString());
+ URI objTarget = DocString.formattedUri("object?id=%d", inst.getId());
+ DocString formatted = DocString.link(objTarget, link);
// Annotate Strings with their values.
String stringValue = InstanceUtils.asString(inst, kMaxChars);
if (stringValue != null) {
- link.appendFormat("\"%s", stringValue);
- link.append(kMaxChars == stringValue.length() ? "..." : "\"");
+ formatted.appendFormat(" \"%s", stringValue);
+ formatted.append(kMaxChars == stringValue.length() ? "..." : "\"");
+ }
+
+ // Annotate Reference with its referent
+ Instance referent = InstanceUtils.getReferent(inst);
+ if (referent != null) {
+ formatted.append(" for ");
+
+ // It should not be possible for a referent to refer back to the
+ // reference object, even indirectly, so there shouldn't be any issues
+ // with infinite recursion here.
+ formatted.append(renderInstance(referent));
}
// Annotate DexCache with its location.
String dexCacheLocation = InstanceUtils.getDexCacheLocation(inst, kMaxChars);
if (dexCacheLocation != null) {
- link.appendFormat(" for %s", dexCacheLocation);
+ formatted.appendFormat(" for %s", dexCacheLocation);
if (kMaxChars == dexCacheLocation.length()) {
- link.append("...");
+ formatted.append("...");
}
}
- URI objTarget = DocString.formattedUri("object?id=%d", inst.getId());
- DocString formatted = DocString.link(objTarget, link);
// Annotate bitmaps with a thumbnail.
Instance bitmap = InstanceUtils.getAssociatedBitmapInstance(inst);
diff --git a/tools/ahat/test-dump/Main.java b/tools/ahat/test-dump/Main.java
index cea1dc1..7b8774a 100644
--- a/tools/ahat/test-dump/Main.java
+++ b/tools/ahat/test-dump/Main.java
@@ -16,6 +16,9 @@
import dalvik.system.VMDebug;
import java.io.IOException;
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
/**
* Program used to create a heap dump for test purposes.
@@ -33,6 +36,9 @@
public String basicString = "hello, world";
public String nullString = null;
public Object anObject = new Object();
+ public ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
+ public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
+ public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
}
public static void main(String[] args) throws IOException {
diff --git a/tools/ahat/test/InstanceUtilsTest.java b/tools/ahat/test/InstanceUtilsTest.java
index 11f82a2..32f48ce 100644
--- a/tools/ahat/test/InstanceUtilsTest.java
+++ b/tools/ahat/test/InstanceUtilsTest.java
@@ -73,4 +73,19 @@
assertNotNull(obj);
assertNull(InstanceUtils.asString(obj));
}
+
+ @Test
+ public void basicReference() throws IOException {
+ TestDump dump = TestDump.getTestDump();
+
+ Instance pref = (Instance)dump.getDumpedThing("aPhantomReference");
+ Instance wref = (Instance)dump.getDumpedThing("aWeakReference");
+ Instance referent = (Instance)dump.getDumpedThing("anObject");
+ assertNotNull(pref);
+ assertNotNull(wref);
+ assertNotNull(referent);
+ assertEquals(referent, InstanceUtils.getReferent(pref));
+ assertEquals(referent, InstanceUtils.getReferent(wref));
+ assertNull(InstanceUtils.getReferent(referent));
+ }
}