ahat: show sample path through strong references.

Instead of showing a sample path through weak references, which is
much less useful for debugging why the object is retained.

Change-Id: I2b8d8bc9368cdcabd7a369e45278ba9b44a38e40
Bug: 64592321
Test: m ahat-test, with new gcRootPathNotWeak test added.
diff --git a/tools/ahat/src/heapdump/AhatInstance.java b/tools/ahat/src/heapdump/AhatInstance.java
index 8905b76..39a844a 100644
--- a/tools/ahat/src/heapdump/AhatInstance.java
+++ b/tools/ahat/src/heapdump/AhatInstance.java
@@ -396,13 +396,6 @@
     return new PathElement(inst.mNextInstanceToGcRoot, inst.mNextInstanceToGcRootField);
   }
 
-  void setNextInstanceToGcRoot(AhatInstance inst, String field) {
-    if (mNextInstanceToGcRoot == null && !isRoot()) {
-      mNextInstanceToGcRoot = inst;
-      mNextInstanceToGcRootField = field;
-    }
-  }
-
   /** Returns a human-readable identifier for this object.
    * For class objects, the string is the class name.
    * For class instances, the string is the class name followed by '@' and the
@@ -456,8 +449,9 @@
     while (!bfs.isEmpty()) {
       Reference ref = bfs.poll();
 
-      if (ref.ref.mHardReverseReferences == null) {
-        // This is the first time we are seeing ref.ref.
+      if (ref.ref.mHardReverseReferences == null && ref.strong) {
+        // This is the first time we are seeing ref.ref through a strong
+        // reference.
         ref.ref.mNextInstanceToGcRoot = ref.src;
         ref.ref.mNextInstanceToGcRootField = ref.field;
         ref.ref.mHardReverseReferences = new ArrayList<AhatInstance>();
diff --git a/tools/ahat/test-dump/Main.java b/tools/ahat/test-dump/Main.java
index 13fd102..14c09af 100644
--- a/tools/ahat/test-dump/Main.java
+++ b/tools/ahat/test-dump/Main.java
@@ -91,6 +91,8 @@
           new ObjectTree(null, new ObjectTree(null, null)),
           new ObjectTree(null, null)),
       null};
+    public Reference aLongStrongPathToSamplePathObject;
+    public WeakReference aShortWeakPathToSamplePathObject;
     public Object[] basicStringRef;
     public AddedObject addedObject;
     public UnchangedObject unchangedObject = new UnchangedObject();
@@ -113,6 +115,11 @@
           Main.class.getClassLoader(), 0x12345, 50000);
       registry.registerNativeAllocation(anObject, 0xABCDABCD);
 
+      aLongStrongPathToSamplePathObject = new Reference(new Reference(new Object()));
+      aShortWeakPathToSamplePathObject = new WeakReference(
+          ((Reference)aLongStrongPathToSamplePathObject.referent).referent,
+          referenceQueue);
+
       addedObject = baseline ? null : new AddedObject();
       removedObject = baseline ? new RemovedObject() : null;
       modifiedObject = new ModifiedObject();
diff --git a/tools/ahat/test/InstanceTest.java b/tools/ahat/test/InstanceTest.java
index f0e7f44..e05782c 100644
--- a/tools/ahat/test/InstanceTest.java
+++ b/tools/ahat/test/InstanceTest.java
@@ -285,6 +285,18 @@
   }
 
   @Test
+  public void gcRootPathNotWeak() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatInstance strong = dump.getDumpedAhatInstance("aLongStrongPathToSamplePathObject");
+    AhatInstance strong2 = strong.getField("referent").asAhatInstance();
+    AhatInstance object = strong2.getField("referent").asAhatInstance();
+
+    List<PathElement> path = object.getPathFromGcRoot();
+    assertEquals(strong2, path.get(path.size() - 2).instance);
+  }
+
+  @Test
   public void retainedSize() throws IOException {
     TestDump dump = TestDump.getTestDump();