Refactor ahat's perflib api.

This change substantially refactors how ahat accesses heap dump data.
Rather than use the perflib API directly with some additional
information accessed on the side via AhatSnapshot, we introduce an
entirely new API for accessing all the information we need from a heap
dump. Perflib is used when processing the heap dump to populate the
information initially, but afterwards all views and handlers go
through the new com.android.ahat.heapdump API.

The primary motivation for this change is to facilitate adding support
for diffing two heap dumps to ahat. The new API provides flexibility
that will make it easier to form links between objects in different
snapshots and introduce place holder objects to show when there is an
object in another snapshot that has no corresponding object in this
snapshot.

A large number of test cases were added to cover missing cases
discovered in the process of refactoring ahat's perflib API.

The external user-facing UI may have minor cosmetic changes, but
otherwise is unchanged.

Test: m ahat-test, with many new tests added.
Bug: 33770653

Change-Id: I1a6b05ea469ebbbac67d99129dd9faa457b4d17e
diff --git a/tools/ahat/test/InstanceTest.java b/tools/ahat/test/InstanceTest.java
new file mode 100644
index 0000000..7173b11
--- /dev/null
+++ b/tools/ahat/test/InstanceTest.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.AhatClassObj;
+import com.android.ahat.heapdump.AhatHeap;
+import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.AhatSnapshot;
+import com.android.ahat.heapdump.PathElement;
+import com.android.ahat.heapdump.Value;
+import com.android.tools.perflib.heap.hprof.HprofClassDump;
+import com.android.tools.perflib.heap.hprof.HprofConstant;
+import com.android.tools.perflib.heap.hprof.HprofDumpRecord;
+import com.android.tools.perflib.heap.hprof.HprofHeapDump;
+import com.android.tools.perflib.heap.hprof.HprofInstanceDump;
+import com.android.tools.perflib.heap.hprof.HprofInstanceField;
+import com.android.tools.perflib.heap.hprof.HprofLoadClass;
+import com.android.tools.perflib.heap.hprof.HprofPrimitiveArrayDump;
+import com.android.tools.perflib.heap.hprof.HprofRecord;
+import com.android.tools.perflib.heap.hprof.HprofRootDebugger;
+import com.android.tools.perflib.heap.hprof.HprofStaticField;
+import com.android.tools.perflib.heap.hprof.HprofStringBuilder;
+import com.android.tools.perflib.heap.hprof.HprofType;
+import com.google.common.io.ByteArrayDataOutput;
+import com.google.common.io.ByteStreams;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class InstanceTest {
+  @Test
+  public void asStringBasic() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("basicString");
+    assertEquals("hello, world", str.asString());
+  }
+
+  @Test
+  public void asStringNonAscii() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
+    assertEquals("Sigma (Ʃ) is not ASCII", str.asString());
+  }
+
+  @Test
+  public void asStringEmbeddedZero() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
+    assertEquals("embedded\0...", str.asString());
+  }
+
+  @Test
+  public void asStringCharArray() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("charArray");
+    assertEquals("char thing", str.asString());
+  }
+
+  @Test
+  public void asStringTruncated() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("basicString");
+    assertEquals("hello", str.asString(5));
+  }
+
+  @Test
+  public void asStringTruncatedNonAscii() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
+    assertEquals("Sigma (Ʃ)", str.asString(9));
+  }
+
+  @Test
+  public void asStringTruncatedEmbeddedZero() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
+    assertEquals("embed", str.asString(5));
+  }
+
+  @Test
+  public void asStringCharArrayTruncated() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("charArray");
+    assertEquals("char ", str.asString(5));
+  }
+
+  @Test
+  public void asStringExactMax() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("basicString");
+    assertEquals("hello, world", str.asString(12));
+  }
+
+  @Test
+  public void asStringExactMaxNonAscii() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
+    assertEquals("Sigma (Ʃ) is not ASCII", str.asString(22));
+  }
+
+  @Test
+  public void asStringExactMaxEmbeddedZero() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
+    assertEquals("embedded\0...", str.asString(12));
+  }
+
+  @Test
+  public void asStringCharArrayExactMax() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("charArray");
+    assertEquals("char thing", str.asString(10));
+  }
+
+  @Test
+  public void asStringNotTruncated() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("basicString");
+    assertEquals("hello, world", str.asString(50));
+  }
+
+  @Test
+  public void asStringNotTruncatedNonAscii() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
+    assertEquals("Sigma (Ʃ) is not ASCII", str.asString(50));
+  }
+
+  @Test
+  public void asStringNotTruncatedEmbeddedZero() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
+    assertEquals("embedded\0...", str.asString(50));
+  }
+
+  @Test
+  public void asStringCharArrayNotTruncated() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("charArray");
+    assertEquals("char thing", str.asString(50));
+  }
+
+  @Test
+  public void asStringNegativeMax() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("basicString");
+    assertEquals("hello, world", str.asString(-3));
+  }
+
+  @Test
+  public void asStringNegativeMaxNonAscii() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
+    assertEquals("Sigma (Ʃ) is not ASCII", str.asString(-3));
+  }
+
+  @Test
+  public void asStringNegativeMaxEmbeddedZero() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
+    assertEquals("embedded\0...", str.asString(-3));
+  }
+
+  @Test
+  public void asStringCharArrayNegativeMax() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance str = dump.getDumpedAhatInstance("charArray");
+    assertEquals("char thing", str.asString(-3));
+  }
+
+  @Test
+  public void asStringNull() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("nullString");
+    assertNull(obj);
+  }
+
+  @Test
+  public void asStringNotString() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("anObject");
+    assertNotNull(obj);
+    assertNull(obj.asString());
+  }
+
+  @Test
+  public void basicReference() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatInstance pref = dump.getDumpedAhatInstance("aPhantomReference");
+    AhatInstance wref = dump.getDumpedAhatInstance("aWeakReference");
+    AhatInstance nref = dump.getDumpedAhatInstance("aNullReferentReference");
+    AhatInstance referent = dump.getDumpedAhatInstance("anObject");
+    assertNotNull(pref);
+    assertNotNull(wref);
+    assertNotNull(nref);
+    assertNotNull(referent);
+    assertEquals(referent, pref.getReferent());
+    assertEquals(referent, wref.getReferent());
+    assertNull(nref.getReferent());
+    assertNull(referent.getReferent());
+  }
+
+  @Test
+  public void gcRootPath() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatClassObj main = dump.getAhatSnapshot().findClass("Main");
+    AhatInstance gcPathArray = dump.getDumpedAhatInstance("gcPathArray");
+    Value value = gcPathArray.asArrayInstance().getValue(2);
+    AhatInstance base = value.asAhatInstance();
+    AhatInstance left = base.getRefField("left");
+    AhatInstance right = base.getRefField("right");
+    AhatInstance target = left.getRefField("right");
+
+    List<PathElement> path = target.getPathFromGcRoot();
+    assertEquals(6, path.size());
+
+    assertEquals(main, path.get(0).instance);
+    assertEquals(".stuff", path.get(0).field);
+    assertTrue(path.get(0).isDominator);
+
+    assertEquals(".gcPathArray", path.get(1).field);
+    assertTrue(path.get(1).isDominator);
+
+    assertEquals(gcPathArray, path.get(2).instance);
+    assertEquals("[2]", path.get(2).field);
+    assertTrue(path.get(2).isDominator);
+
+    assertEquals(base, path.get(3).instance);
+    assertTrue(path.get(3).isDominator);
+
+    // There are two possible paths. Either it can go through the 'left' node,
+    // or the 'right' node.
+    if (path.get(3).field.equals(".left")) {
+      assertEquals(".left", path.get(3).field);
+
+      assertEquals(left, path.get(4).instance);
+      assertEquals(".right", path.get(4).field);
+      assertFalse(path.get(4).isDominator);
+
+    } else {
+      assertEquals(".right", path.get(3).field);
+
+      assertEquals(right, path.get(4).instance);
+      assertEquals(".left", path.get(4).field);
+      assertFalse(path.get(4).isDominator);
+    }
+
+    assertEquals(target, path.get(5).instance);
+    assertEquals("", path.get(5).field);
+    assertTrue(path.get(5).isDominator);
+  }
+
+  @Test
+  public void retainedSize() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    // anObject should not be an immediate dominator of any other object. This
+    // means its retained size should be equal to its size for the heap it was
+    // allocated on, and should be 0 for all other heaps.
+    AhatInstance anObject = dump.getDumpedAhatInstance("anObject");
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
+    long size = anObject.getSize();
+    assertEquals(size, anObject.getTotalRetainedSize());
+    assertEquals(size, anObject.getRetainedSize(anObject.getHeap()));
+    for (AhatHeap heap : snapshot.getHeaps()) {
+      if (!heap.equals(anObject.getHeap())) {
+        assertEquals(String.format("For heap '%s'", heap.getName()),
+            0, anObject.getRetainedSize(heap));
+      }
+    }
+  }
+
+  @Test
+  public void objectNotABitmap() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("anObject");
+    assertNull(obj.asBitmap());
+  }
+
+  @Test
+  public void arrayNotABitmap() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("gcPathArray");
+    assertNull(obj.asBitmap());
+  }
+
+  @Test
+  public void classObjNotABitmap() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getAhatSnapshot().findClass("Main");
+    assertNull(obj.asBitmap());
+  }
+
+  @Test
+  public void classInstanceToString() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("aPhantomReference");
+    long id = obj.getId();
+    assertEquals(String.format("java.lang.ref.PhantomReference@%08x", id), obj.toString());
+  }
+
+  @Test
+  public void classObjToString() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getAhatSnapshot().findClass("Main");
+    assertEquals("Main", obj.toString());
+  }
+
+  @Test
+  public void arrayInstanceToString() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("gcPathArray");
+    long id = obj.getId();
+
+    // There's a bug in perfib's proguard deobfuscation for arrays.
+    // To work around that bug for the time being, only test the suffix of
+    // the toString result. Ideally we test for string equality against
+    // "Main$ObjectTree[4]@%08x", id.
+    assertTrue(obj.toString().endsWith(String.format("[4]@%08x", id)));
+  }
+
+  @Test
+  public void primArrayInstanceToString() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("bigArray");
+    long id = obj.getId();
+    assertEquals(String.format("byte[1000000]@%08x", id), obj.toString());
+  }
+
+  @Test
+  public void isNotRoot() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("anObject");
+    assertFalse(obj.isRoot());
+    assertNull(obj.getRootTypes());
+  }
+
+  @Test
+  public void reverseReferencesAreNotUnreachable() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+    AhatInstance obj = dump.getDumpedAhatInstance("basicString");
+    assertEquals(2, obj.getHardReverseReferences().size());
+    assertEquals(0, obj.getSoftReverseReferences().size());
+  }
+
+  @Test
+  public void asStringEmbedded() throws IOException {
+    // Set up a heap dump with an instance of java.lang.String of
+    // "hello" with instance id 0x42 that is backed by a char array that is
+    // bigger. This is how ART used to represent strings, and we should still
+    // support it in case the heap dump is from a previous platform version.
+    HprofStringBuilder strings = new HprofStringBuilder(0);
+    List<HprofRecord> records = new ArrayList<HprofRecord>();
+    List<HprofDumpRecord> dump = new ArrayList<HprofDumpRecord>();
+
+    final int stringClassObjectId = 1;
+    records.add(new HprofLoadClass(0, 0, stringClassObjectId, 0, strings.get("java.lang.String")));
+    dump.add(new HprofClassDump(stringClassObjectId, 0, 0, 0, 0, 0, 0, 0, 0,
+          new HprofConstant[0], new HprofStaticField[0],
+          new HprofInstanceField[]{
+            new HprofInstanceField(strings.get("count"), HprofType.TYPE_INT),
+            new HprofInstanceField(strings.get("hashCode"), HprofType.TYPE_INT),
+            new HprofInstanceField(strings.get("offset"), HprofType.TYPE_INT),
+            new HprofInstanceField(strings.get("value"), HprofType.TYPE_OBJECT)}));
+
+    dump.add(new HprofPrimitiveArrayDump(0x41, 0, HprofType.TYPE_CHAR,
+          new long[]{'n', 'o', 't', ' ', 'h', 'e', 'l', 'l', 'o', 'o', 'p'}));
+
+    ByteArrayDataOutput values = ByteStreams.newDataOutput();
+    values.writeInt(5);     // count
+    values.writeInt(0);     // hashCode
+    values.writeInt(4);     // offset
+    values.writeInt(0x41);  // value
+    dump.add(new HprofInstanceDump(0x42, 0, stringClassObjectId, values.toByteArray()));
+    dump.add(new HprofRootDebugger(stringClassObjectId));
+    dump.add(new HprofRootDebugger(0x42));
+
+    records.add(new HprofHeapDump(0, dump.toArray(new HprofDumpRecord[0])));
+    AhatSnapshot snapshot = SnapshotBuilder.makeSnapshot(strings, records);
+    AhatInstance chars = snapshot.findInstance(0x41);
+    assertNotNull(chars);
+    assertEquals("not helloop", chars.asString());
+
+    AhatInstance stringInstance = snapshot.findInstance(0x42);
+    assertNotNull(stringInstance);
+    assertEquals("hello", stringInstance.asString());
+  }
+}
diff --git a/tools/ahat/test/InstanceUtilsTest.java b/tools/ahat/test/InstanceUtilsTest.java
deleted file mode 100644
index fe2706d..0000000
--- a/tools/ahat/test/InstanceUtilsTest.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ahat;
-
-import com.android.tools.perflib.heap.ArrayInstance;
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Instance;
-import java.io.IOException;
-import java.util.List;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import org.junit.Test;
-
-public class InstanceUtilsTest {
-  @Test
-  public void asStringBasic() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("basicString");
-    assertEquals("hello, world", InstanceUtils.asString(str));
-  }
-
-  @Test
-  public void asStringNonAscii() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("nonAscii");
-    assertEquals("Sigma (\u01a9) is not ASCII", InstanceUtils.asString(str));
-  }
-
-  @Test
-  public void asStringEmbeddedZero() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("embeddedZero");
-    assertEquals("embedded\0...", InstanceUtils.asString(str));
-  }
-
-  @Test
-  public void asStringCharArray() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("charArray");
-    assertEquals("char thing", InstanceUtils.asString(str));
-  }
-
-  @Test
-  public void asStringTruncated() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("basicString");
-    assertEquals("hello", InstanceUtils.asString(str, 5));
-  }
-
-  @Test
-  public void asStringTruncatedNonAscii() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("nonAscii");
-    assertEquals("Sigma (\u01a9)", InstanceUtils.asString(str, 9));
-  }
-
-  @Test
-  public void asStringTruncatedEmbeddedZero() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("embeddedZero");
-    assertEquals("embed", InstanceUtils.asString(str, 5));
-  }
-
-  @Test
-  public void asStringCharArrayTruncated() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("charArray");
-    assertEquals("char ", InstanceUtils.asString(str, 5));
-  }
-
-  @Test
-  public void asStringExactMax() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("basicString");
-    assertEquals("hello, world", InstanceUtils.asString(str, 12));
-  }
-
-  @Test
-  public void asStringExactMaxNonAscii() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("nonAscii");
-    assertEquals("Sigma (\u01a9) is not ASCII", InstanceUtils.asString(str, 22));
-  }
-
-  @Test
-  public void asStringExactMaxEmbeddedZero() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("embeddedZero");
-    assertEquals("embedded\0...", InstanceUtils.asString(str, 12));
-  }
-
-  @Test
-  public void asStringCharArrayExactMax() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("charArray");
-    assertEquals("char thing", InstanceUtils.asString(str, 10));
-  }
-
-  @Test
-  public void asStringNotTruncated() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("basicString");
-    assertEquals("hello, world", InstanceUtils.asString(str, 50));
-  }
-
-  @Test
-  public void asStringNotTruncatedNonAscii() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("nonAscii");
-    assertEquals("Sigma (\u01a9) is not ASCII", InstanceUtils.asString(str, 50));
-  }
-
-  @Test
-  public void asStringNotTruncatedEmbeddedZero() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("embeddedZero");
-    assertEquals("embedded\0...", InstanceUtils.asString(str, 50));
-  }
-
-  @Test
-  public void asStringCharArrayNotTruncated() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("charArray");
-    assertEquals("char thing", InstanceUtils.asString(str, 50));
-  }
-
-  @Test
-  public void asStringNegativeMax() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("basicString");
-    assertEquals("hello, world", InstanceUtils.asString(str, -3));
-  }
-
-  @Test
-  public void asStringNegativeMaxNonAscii() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("nonAscii");
-    assertEquals("Sigma (\u01a9) is not ASCII", InstanceUtils.asString(str, -3));
-  }
-
-  @Test
-  public void asStringNegativeMaxEmbeddedZero() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("embeddedZero");
-    assertEquals("embedded\0...", InstanceUtils.asString(str, -3));
-  }
-
-  @Test
-  public void asStringCharArrayNegativeMax() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance str = (Instance)dump.getDumpedThing("charArray");
-    assertEquals("char thing", InstanceUtils.asString(str, -3));
-  }
-
-  @Test
-  public void asStringNull() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance obj = (Instance)dump.getDumpedThing("nullString");
-    assertNull(InstanceUtils.asString(obj));
-  }
-
-  @Test
-  public void asStringNotString() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-    Instance obj = (Instance)dump.getDumpedThing("anObject");
-    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));
-  }
-
-  @Test
-  public void gcRootPath() throws IOException {
-    TestDump dump = TestDump.getTestDump();
-
-    ClassObj main = dump.getAhatSnapshot().findClass("Main");
-    ArrayInstance gcPathArray = (ArrayInstance)dump.getDumpedThing("gcPathArray");
-    Object[] values = gcPathArray.getValues();
-    Instance base = (Instance)values[2];
-    Instance left = InstanceUtils.getRefField(base, "left");
-    Instance right = InstanceUtils.getRefField(base, "right");
-    Instance target = InstanceUtils.getRefField(left, "right");
-
-    List<InstanceUtils.PathElement> path = InstanceUtils.getPathFromGcRoot(target);
-    assertEquals(6, path.size());
-
-    assertEquals(main, path.get(0).instance);
-    assertEquals(".stuff", path.get(0).field);
-    assertTrue(path.get(0).isDominator);
-
-    assertEquals(".gcPathArray", path.get(1).field);
-    assertTrue(path.get(1).isDominator);
-
-    assertEquals(gcPathArray, path.get(2).instance);
-    assertEquals("[2]", path.get(2).field);
-    assertTrue(path.get(2).isDominator);
-
-    assertEquals(base, path.get(3).instance);
-    assertTrue(path.get(3).isDominator);
-
-    // There are two possible paths. Either it can go through the 'left' node,
-    // or the 'right' node.
-    if (path.get(3).field.equals(".left")) {
-      assertEquals(".left", path.get(3).field);
-
-      assertEquals(left, path.get(4).instance);
-      assertEquals(".right", path.get(4).field);
-      assertFalse(path.get(4).isDominator);
-
-    } else {
-      assertEquals(".right", path.get(3).field);
-
-      assertEquals(right, path.get(4).instance);
-      assertEquals(".left", path.get(4).field);
-      assertFalse(path.get(4).isDominator);
-    }
-
-    assertEquals(target, path.get(5).instance);
-    assertEquals("", path.get(5).field);
-    assertTrue(path.get(5).isDominator);
-  }
-}
diff --git a/tools/ahat/test/NativeAllocationTest.java b/tools/ahat/test/NativeAllocationTest.java
index 7ad4c1d..9babab9 100644
--- a/tools/ahat/test/NativeAllocationTest.java
+++ b/tools/ahat/test/NativeAllocationTest.java
@@ -16,12 +16,15 @@
 
 package com.android.ahat;
 
-import com.android.tools.perflib.heap.Instance;
+import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.AhatSnapshot;
+import com.android.ahat.heapdump.NativeAllocation;
 import java.io.IOException;
-import static org.junit.Assert.fail;
-import static org.junit.Assert.assertEquals;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
 public class NativeAllocationTest {
 
   @Test
@@ -29,9 +32,9 @@
     TestDump dump = TestDump.getTestDump();
 
     AhatSnapshot snapshot = dump.getAhatSnapshot();
-    Instance referent = (Instance)dump.getDumpedThing("anObject");
-    for (InstanceUtils.NativeAllocation alloc : snapshot.getNativeAllocations()) {
-      if (alloc.referent == referent) {
+    AhatInstance referent = dump.getDumpedAhatInstance("anObject");
+    for (NativeAllocation alloc : snapshot.getNativeAllocations()) {
+      if (alloc.referent.equals(referent)) {
         assertEquals(42 , alloc.size);
         assertEquals(referent.getHeap(), alloc.heap);
         assertEquals(0xABCDABCD , alloc.pointer);
diff --git a/tools/ahat/test/ObjectHandlerTest.java b/tools/ahat/test/ObjectHandlerTest.java
new file mode 100644
index 0000000..cd0ba23
--- /dev/null
+++ b/tools/ahat/test/ObjectHandlerTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.AhatSnapshot;
+import java.io.IOException;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+public class ObjectHandlerTest {
+  @Test
+  public void noCrashClassInstance() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatInstance object = dump.getDumpedAhatInstance("aPhantomReference");
+    assertNotNull(object);
+
+    AhatHandler handler = new ObjectHandler(dump.getAhatSnapshot());
+    TestHandler.testNoCrash(handler, "http://localhost:7100/object?id=" + object.getId());
+  }
+
+  @Test
+  public void noCrashClassObj() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
+    AhatHandler handler = new ObjectHandler(snapshot);
+
+    AhatInstance object = snapshot.findClass("Main");
+    assertNotNull(object);
+
+    TestHandler.testNoCrash(handler, "http://localhost:7100/object?id=" + object.getId());
+  }
+
+  @Test
+  public void noCrashSystemClassObj() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
+    AhatHandler handler = new ObjectHandler(snapshot);
+
+    AhatInstance object = snapshot.findClass("java.lang.String");
+    assertNotNull(object);
+
+    TestHandler.testNoCrash(handler, "http://localhost:7100/object?id=" + object.getId());
+  }
+
+  @Test
+  public void noCrashArrayInstance() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatInstance object = dump.getDumpedAhatInstance("gcPathArray");
+    assertNotNull(object);
+
+    AhatHandler handler = new ObjectHandler(dump.getAhatSnapshot());
+    TestHandler.testNoCrash(handler, "http://localhost:7100/object?id=" + object.getId());
+  }
+}
diff --git a/tools/ahat/test/OverviewHandlerTest.java b/tools/ahat/test/OverviewHandlerTest.java
new file mode 100644
index 0000000..a46bfce
--- /dev/null
+++ b/tools/ahat/test/OverviewHandlerTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.AhatSnapshot;
+import java.io.File;
+import java.io.IOException;
+import org.junit.Test;
+
+public class OverviewHandlerTest {
+
+  @Test
+  public void noCrash() throws IOException {
+    AhatSnapshot snapshot = TestDump.getTestDump().getAhatSnapshot();
+    AhatHandler handler = new OverviewHandler(snapshot, new File("my.hprof.file"));
+    TestHandler.testNoCrash(handler, "http://localhost:7100");
+  }
+}
diff --git a/tools/ahat/test/PerformanceTest.java b/tools/ahat/test/PerformanceTest.java
index 6e46800..e13974b 100644
--- a/tools/ahat/test/PerformanceTest.java
+++ b/tools/ahat/test/PerformanceTest.java
@@ -16,13 +16,15 @@
 
 package com.android.ahat;
 
-import com.android.tools.perflib.heap.Instance;
+import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.AhatSnapshot;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintStream;
+import org.junit.Test;
+
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import org.junit.Test;
 
 public class PerformanceTest {
   private static class NullOutputStream extends OutputStream {
@@ -36,7 +38,7 @@
     // for any object, including big arrays.
     TestDump dump = TestDump.getTestDump();
 
-    Instance bigArray = (Instance)dump.getDumpedThing("bigArray");
+    AhatInstance bigArray = dump.getDumpedAhatInstance("bigArray");
     assertNotNull(bigArray);
 
     AhatSnapshot snapshot = dump.getAhatSnapshot();
diff --git a/tools/ahat/test/QueryTest.java b/tools/ahat/test/QueryTest.java
index 40e3322..5bcf8ea 100644
--- a/tools/ahat/test/QueryTest.java
+++ b/tools/ahat/test/QueryTest.java
@@ -18,9 +18,10 @@
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import static org.junit.Assert.assertEquals;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+
 public class QueryTest {
   @Test
   public void simple() throws URISyntaxException {
diff --git a/tools/ahat/test/RootedHandlerTest.java b/tools/ahat/test/RootedHandlerTest.java
new file mode 100644
index 0000000..f325b8e
--- /dev/null
+++ b/tools/ahat/test/RootedHandlerTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.AhatSnapshot;
+import java.io.IOException;
+import org.junit.Test;
+
+public class RootedHandlerTest {
+  @Test
+  public void noCrash() throws IOException {
+    AhatSnapshot snapshot = TestDump.getTestDump().getAhatSnapshot();
+    AhatHandler handler = new RootedHandler(snapshot);
+    TestHandler.testNoCrash(handler, "http://localhost:7100/rooted");
+  }
+}
diff --git a/tools/ahat/test/SiteHandlerTest.java b/tools/ahat/test/SiteHandlerTest.java
new file mode 100644
index 0000000..37596be
--- /dev/null
+++ b/tools/ahat/test/SiteHandlerTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.AhatSnapshot;
+import java.io.IOException;
+import org.junit.Test;
+
+public class SiteHandlerTest {
+  @Test
+  public void noCrash() throws IOException {
+    AhatSnapshot snapshot = TestDump.getTestDump().getAhatSnapshot();
+    AhatHandler handler = new SiteHandler(snapshot);
+    TestHandler.testNoCrash(handler, "http://localhost:7100/sites");
+  }
+}
diff --git a/tools/ahat/test/SnapshotBuilder.java b/tools/ahat/test/SnapshotBuilder.java
new file mode 100644
index 0000000..0eea635
--- /dev/null
+++ b/tools/ahat/test/SnapshotBuilder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.AhatSnapshot;
+import com.android.tools.perflib.heap.ProguardMap;
+import com.android.tools.perflib.heap.hprof.Hprof;
+import com.android.tools.perflib.heap.hprof.HprofRecord;
+import com.android.tools.perflib.heap.hprof.HprofStringBuilder;
+import com.android.tools.perflib.heap.io.InMemoryBuffer;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Class with utilities to help constructing snapshots for tests.
+ */
+public class SnapshotBuilder {
+
+  // Helper function to make a snapshot with id size 4 given an
+  // HprofStringBuilder and list of HprofRecords
+  public static AhatSnapshot makeSnapshot(HprofStringBuilder strings, List<HprofRecord> records)
+    throws IOException {
+    // TODO: When perflib can handle the case where strings are referred to
+    // before they are defined, just add the string records to the records
+    // list.
+    List<HprofRecord> actualRecords = new ArrayList<HprofRecord>();
+    actualRecords.addAll(strings.getStringRecords());
+    actualRecords.addAll(records);
+
+    Hprof hprof = new Hprof("JAVA PROFILE 1.0.3", 4, new Date(), actualRecords);
+    ByteArrayOutputStream os = new ByteArrayOutputStream();
+    hprof.write(os);
+    InMemoryBuffer buffer = new InMemoryBuffer(os.toByteArray());
+    return AhatSnapshot.fromDataBuffer(buffer, new ProguardMap());
+  }
+}
diff --git a/tools/ahat/test/SortTest.java b/tools/ahat/test/SortTest.java
deleted file mode 100644
index 02ff7db..0000000
--- a/tools/ahat/test/SortTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ahat;
-
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Heap;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import static org.junit.Assert.assertEquals;
-import org.junit.Test;
-
-public class SortTest {
-  @Test
-  public void objectsInfo() {
-    Heap heapA = new Heap(0xA, "A");
-    Heap heapB = new Heap(0xB, "B");
-    ClassObj classA = new ClassObj(0x1A, null, "classA", 0);
-    ClassObj classB = new ClassObj(0x1B, null, "classB", 0);
-    ClassObj classC = new ClassObj(0x1C, null, "classC", 0);
-    Site.ObjectsInfo infoA = new Site.ObjectsInfo(heapA, classA, 4, 14);
-    Site.ObjectsInfo infoB = new Site.ObjectsInfo(heapB, classB, 2, 15);
-    Site.ObjectsInfo infoC = new Site.ObjectsInfo(heapA, classC, 3, 13);
-    Site.ObjectsInfo infoD = new Site.ObjectsInfo(heapB, classA, 5, 12);
-    Site.ObjectsInfo infoE = new Site.ObjectsInfo(heapA, classB, 1, 11);
-    List<Site.ObjectsInfo> list = new ArrayList<Site.ObjectsInfo>();
-    list.add(infoA);
-    list.add(infoB);
-    list.add(infoC);
-    list.add(infoD);
-    list.add(infoE);
-
-    // Sort by size.
-    Collections.sort(list, new Sort.ObjectsInfoBySize());
-    assertEquals(infoB, list.get(0));
-    assertEquals(infoA, list.get(1));
-    assertEquals(infoC, list.get(2));
-    assertEquals(infoD, list.get(3));
-    assertEquals(infoE, list.get(4));
-
-    // Sort by class name.
-    Collections.sort(list, new Sort.ObjectsInfoByClassName());
-    assertEquals(classA, list.get(0).classObj);
-    assertEquals(classA, list.get(1).classObj);
-    assertEquals(classB, list.get(2).classObj);
-    assertEquals(classB, list.get(3).classObj);
-    assertEquals(classC, list.get(4).classObj);
-
-    // Sort by heap name.
-    Collections.sort(list, new Sort.ObjectsInfoByHeapName());
-    assertEquals(heapA, list.get(0).heap);
-    assertEquals(heapA, list.get(1).heap);
-    assertEquals(heapA, list.get(2).heap);
-    assertEquals(heapB, list.get(3).heap);
-    assertEquals(heapB, list.get(4).heap);
-
-    // Sort first by class name, then by size.
-    Collections.sort(list, new Sort.WithPriority<Site.ObjectsInfo>(
-          new Sort.ObjectsInfoByClassName(),
-          new Sort.ObjectsInfoBySize()));
-    assertEquals(infoA, list.get(0));
-    assertEquals(infoD, list.get(1));
-    assertEquals(infoB, list.get(2));
-    assertEquals(infoE, list.get(3));
-    assertEquals(infoC, list.get(4));
-  }
-}
diff --git a/tools/ahat/test/TestDump.java b/tools/ahat/test/TestDump.java
index ebce61c..531c9dd 100644
--- a/tools/ahat/test/TestDump.java
+++ b/tools/ahat/test/TestDump.java
@@ -16,14 +16,15 @@
 
 package com.android.ahat;
 
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Field;
-import com.android.tools.perflib.heap.Instance;
+import com.android.ahat.heapdump.AhatClassObj;
+import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.AhatSnapshot;
+import com.android.ahat.heapdump.FieldValue;
+import com.android.ahat.heapdump.Value;
 import com.android.tools.perflib.heap.ProguardMap;
 import java.io.File;
 import java.io.IOException;
 import java.text.ParseException;
-import java.util.Map;
 
 /**
  * The TestDump class is used to get an AhatSnapshot for the test-dump
@@ -71,18 +72,27 @@
   }
 
   /**
-   * Return the value of a field in the DumpedStuff instance in the
+   * Returns the value of a field in the DumpedStuff instance in the
    * snapshot for the test-dump program.
    */
-  public Object getDumpedThing(String name) {
-    ClassObj main = mSnapshot.findClass("Main");
-    Instance stuff = null;
-    for (Map.Entry<Field, Object> fields : main.getStaticFieldValues().entrySet()) {
-      if ("stuff".equals(fields.getKey().getName())) {
-        stuff = (Instance) fields.getValue();
+  public Value getDumpedValue(String name) {
+    AhatClassObj main = mSnapshot.findClass("Main");
+    AhatInstance stuff = null;
+    for (FieldValue fields : main.getStaticFieldValues()) {
+      if ("stuff".equals(fields.getName())) {
+        stuff = fields.getValue().asAhatInstance();
       }
     }
-    return InstanceUtils.getField(stuff, name);
+    return stuff.getField(name);
+  }
+
+  /**
+   * Returns the value of a non-primitive field in the DumpedStuff instance in
+   * the snapshot for the test-dump program.
+   */
+  public AhatInstance getDumpedAhatInstance(String name) {
+    Value value = getDumpedValue(name);
+    return value == null ? null : value.asAhatInstance();
   }
 
   /**
diff --git a/tools/ahat/test/TestHandler.java b/tools/ahat/test/TestHandler.java
new file mode 100644
index 0000000..859e39a
--- /dev/null
+++ b/tools/ahat/test/TestHandler.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Provide common utilities for basic handler tests.
+ */
+public class TestHandler {
+  private static class NullOutputStream extends OutputStream {
+    public void write(int b) throws IOException {
+    }
+  }
+
+  /**
+   * Test that the given handler doesn't crash on the given query.
+   */
+  public static void testNoCrash(AhatHandler handler, String uri) throws IOException {
+    PrintStream ps = new PrintStream(new NullOutputStream());
+    HtmlDoc doc = new HtmlDoc(ps, DocString.text("noCrash test"), DocString.uri("style.css"));
+    Query query = new Query(DocString.uri(uri));
+    handler.handle(doc, query);
+  }
+}
diff --git a/tools/ahat/test/Tests.java b/tools/ahat/test/Tests.java
index 3291470..6c29f27 100644
--- a/tools/ahat/test/Tests.java
+++ b/tools/ahat/test/Tests.java
@@ -22,11 +22,14 @@
   public static void main(String[] args) {
     if (args.length == 0) {
       args = new String[]{
-        "com.android.ahat.InstanceUtilsTest",
+        "com.android.ahat.InstanceTest",
         "com.android.ahat.NativeAllocationTest",
+        "com.android.ahat.ObjectHandlerTest",
+        "com.android.ahat.OverviewHandlerTest",
         "com.android.ahat.PerformanceTest",
+        "com.android.ahat.RootedHandlerTest",
         "com.android.ahat.QueryTest",
-        "com.android.ahat.SortTest",
+        "com.android.ahat.SiteHandlerTest",
       };
     }
     JUnitCore.main(args);