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.AhatHeap;
21 import com.android.ahat.heapdump.AhatInstance;
22 import com.android.ahat.heapdump.AhatSnapshot;
23 import com.android.ahat.heapdump.PathElement;
24 import com.android.ahat.heapdump.Reachability;
25 import com.android.ahat.heapdump.Size;
26 import com.android.ahat.heapdump.Value;
27 import java.io.IOException;
28 import java.util.List;
29 import org.junit.Test;
30 
31 import static org.junit.Assert.assertEquals;
32 import static org.junit.Assert.assertFalse;
33 import static org.junit.Assert.assertNotNull;
34 import static org.junit.Assert.assertNull;
35 import static org.junit.Assert.assertTrue;
36 
37 public class InstanceTest {
38   @Test
asStringBasic()39   public void asStringBasic() throws IOException {
40     TestDump dump = TestDump.getTestDump();
41     AhatInstance str = dump.getDumpedAhatInstance("basicString");
42     assertEquals("hello, world", str.asString());
43   }
44 
45   @Test
asStringNonAscii()46   public void asStringNonAscii() throws IOException {
47     TestDump dump = TestDump.getTestDump();
48     AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
49     assertEquals("Sigma (Ʃ) is not ASCII", str.asString());
50   }
51 
52   @Test
asStringEmbeddedZero()53   public void asStringEmbeddedZero() throws IOException {
54     TestDump dump = TestDump.getTestDump();
55     AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
56     assertEquals("embedded\0...", str.asString());
57   }
58 
59   @Test
asStringCharArray()60   public void asStringCharArray() throws IOException {
61     TestDump dump = TestDump.getTestDump();
62     AhatInstance str = dump.getDumpedAhatInstance("charArray");
63     assertEquals("char thing", str.asString());
64   }
65 
66   @Test
asStringTruncated()67   public void asStringTruncated() throws IOException {
68     TestDump dump = TestDump.getTestDump();
69     AhatInstance str = dump.getDumpedAhatInstance("basicString");
70     assertEquals("hello", str.asString(5));
71   }
72 
73   @Test
asStringTruncatedNonAscii()74   public void asStringTruncatedNonAscii() throws IOException {
75     TestDump dump = TestDump.getTestDump();
76     AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
77     assertEquals("Sigma (Ʃ)", str.asString(9));
78   }
79 
80   @Test
asStringTruncatedEmbeddedZero()81   public void asStringTruncatedEmbeddedZero() throws IOException {
82     TestDump dump = TestDump.getTestDump();
83     AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
84     assertEquals("embed", str.asString(5));
85   }
86 
87   @Test
asStringCharArrayTruncated()88   public void asStringCharArrayTruncated() throws IOException {
89     TestDump dump = TestDump.getTestDump();
90     AhatInstance str = dump.getDumpedAhatInstance("charArray");
91     assertEquals("char ", str.asString(5));
92   }
93 
94   @Test
asStringExactMax()95   public void asStringExactMax() throws IOException {
96     TestDump dump = TestDump.getTestDump();
97     AhatInstance str = dump.getDumpedAhatInstance("basicString");
98     assertEquals("hello, world", str.asString(12));
99   }
100 
101   @Test
asStringExactMaxNonAscii()102   public void asStringExactMaxNonAscii() throws IOException {
103     TestDump dump = TestDump.getTestDump();
104     AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
105     assertEquals("Sigma (Ʃ) is not ASCII", str.asString(22));
106   }
107 
108   @Test
asStringExactMaxEmbeddedZero()109   public void asStringExactMaxEmbeddedZero() throws IOException {
110     TestDump dump = TestDump.getTestDump();
111     AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
112     assertEquals("embedded\0...", str.asString(12));
113   }
114 
115   @Test
asStringCharArrayExactMax()116   public void asStringCharArrayExactMax() throws IOException {
117     TestDump dump = TestDump.getTestDump();
118     AhatInstance str = dump.getDumpedAhatInstance("charArray");
119     assertEquals("char thing", str.asString(10));
120   }
121 
122   @Test
asStringNotTruncated()123   public void asStringNotTruncated() throws IOException {
124     TestDump dump = TestDump.getTestDump();
125     AhatInstance str = dump.getDumpedAhatInstance("basicString");
126     assertEquals("hello, world", str.asString(50));
127   }
128 
129   @Test
asStringNotTruncatedNonAscii()130   public void asStringNotTruncatedNonAscii() throws IOException {
131     TestDump dump = TestDump.getTestDump();
132     AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
133     assertEquals("Sigma (Ʃ) is not ASCII", str.asString(50));
134   }
135 
136   @Test
asStringNotTruncatedEmbeddedZero()137   public void asStringNotTruncatedEmbeddedZero() throws IOException {
138     TestDump dump = TestDump.getTestDump();
139     AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
140     assertEquals("embedded\0...", str.asString(50));
141   }
142 
143   @Test
asStringCharArrayNotTruncated()144   public void asStringCharArrayNotTruncated() throws IOException {
145     TestDump dump = TestDump.getTestDump();
146     AhatInstance str = dump.getDumpedAhatInstance("charArray");
147     assertEquals("char thing", str.asString(50));
148   }
149 
150   @Test
asStringNegativeMax()151   public void asStringNegativeMax() throws IOException {
152     TestDump dump = TestDump.getTestDump();
153     AhatInstance str = dump.getDumpedAhatInstance("basicString");
154     assertEquals("hello, world", str.asString(-3));
155   }
156 
157   @Test
asStringNegativeMaxNonAscii()158   public void asStringNegativeMaxNonAscii() throws IOException {
159     TestDump dump = TestDump.getTestDump();
160     AhatInstance str = dump.getDumpedAhatInstance("nonAscii");
161     assertEquals("Sigma (Ʃ) is not ASCII", str.asString(-3));
162   }
163 
164   @Test
asStringNegativeMaxEmbeddedZero()165   public void asStringNegativeMaxEmbeddedZero() throws IOException {
166     TestDump dump = TestDump.getTestDump();
167     AhatInstance str = dump.getDumpedAhatInstance("embeddedZero");
168     assertEquals("embedded\0...", str.asString(-3));
169   }
170 
171   @Test
asStringCharArrayNegativeMax()172   public void asStringCharArrayNegativeMax() throws IOException {
173     TestDump dump = TestDump.getTestDump();
174     AhatInstance str = dump.getDumpedAhatInstance("charArray");
175     assertEquals("char thing", str.asString(-3));
176   }
177 
178   @Test
asStringNull()179   public void asStringNull() throws IOException {
180     TestDump dump = TestDump.getTestDump();
181     AhatInstance obj = dump.getDumpedAhatInstance("nullString");
182     assertNull(obj);
183   }
184 
185   @Test
asStringNotString()186   public void asStringNotString() throws IOException {
187     TestDump dump = TestDump.getTestDump();
188     AhatInstance obj = dump.getDumpedAhatInstance("anObject");
189     assertNotNull(obj);
190     assertNull(obj.asString());
191   }
192 
193   @Test
basicReference()194   public void basicReference() throws IOException {
195     TestDump dump = TestDump.getTestDump();
196 
197     AhatInstance pref = dump.getDumpedAhatInstance("aPhantomReference");
198     AhatInstance wref = dump.getDumpedAhatInstance("aWeakReference");
199     AhatInstance nref = dump.getDumpedAhatInstance("aNullReferentReference");
200     AhatInstance referent = dump.getDumpedAhatInstance("anObject");
201     assertNotNull(pref);
202     assertNotNull(wref);
203     assertNotNull(nref);
204     assertNotNull(referent);
205     assertEquals(referent, pref.getReferent());
206     assertEquals(referent, wref.getReferent());
207     assertNull(nref.getReferent());
208     assertNull(referent.getReferent());
209   }
210 
211   @Test
unreachableReferent()212   public void unreachableReferent() throws IOException {
213     // The test dump program should never be under enough GC pressure for the
214     // soft reference to be cleared. Ensure that ahat will show the soft
215     // reference as having a non-null referent.
216     TestDump dump = TestDump.getTestDump();
217     AhatInstance ref = dump.getDumpedAhatInstance("aSoftReference");
218     AhatInstance referent = ref.getReferent();
219     assertNotNull(referent);
220     assertEquals(Reachability.SOFT, referent.getReachability());
221     assertTrue(referent.isWeaklyReachable());
222   }
223 
224   @Test
reachability()225   public void reachability() throws IOException {
226     TestDump dump = TestDump.getTestDump();
227     AhatInstance strong1 = dump.getDumpedAhatInstance("reachabilityReferenceChain");
228     AhatInstance soft1 = strong1.getField("referent").asAhatInstance();
229     AhatInstance strong2 = soft1.getField("referent").asAhatInstance();
230     AhatInstance weak1 = strong2.getField("referent").asAhatInstance();
231     AhatInstance soft2 = weak1.getField("referent").asAhatInstance();
232     AhatInstance phantom1 = soft2.getField("referent").asAhatInstance();
233     AhatInstance obj = phantom1.getField("referent").asAhatInstance();
234 
235     assertEquals(Reachability.STRONG, strong1.getReachability());
236     assertEquals(Reachability.STRONG, soft1.getReachability());
237     assertEquals(Reachability.SOFT, strong2.getReachability());
238     assertEquals(Reachability.SOFT, weak1.getReachability());
239     assertEquals(Reachability.WEAK, soft2.getReachability());
240     assertEquals(Reachability.WEAK, phantom1.getReachability());
241     assertEquals(Reachability.PHANTOM, obj.getReachability());
242   }
243 
244   @Test
gcRootPath()245   public void gcRootPath() throws IOException {
246     TestDump dump = TestDump.getTestDump();
247 
248     AhatClassObj main = dump.findClass("Main");
249     AhatInstance gcPathArray = dump.getDumpedAhatInstance("gcPathArray");
250     Value value = gcPathArray.asArrayInstance().getValue(2);
251     AhatInstance base = value.asAhatInstance();
252     AhatInstance left = base.getRefField("left");
253     AhatInstance right = base.getRefField("right");
254     AhatInstance target = left.getRefField("right");
255 
256     List<PathElement> path = target.getPathFromGcRoot();
257     assertEquals(6, path.size());
258 
259     assertEquals(main, path.get(0).instance);
260     assertEquals(".stuff", path.get(0).field);
261     assertTrue(path.get(0).isDominator);
262 
263     assertEquals(".gcPathArray", path.get(1).field);
264     assertTrue(path.get(1).isDominator);
265 
266     assertEquals(gcPathArray, path.get(2).instance);
267     assertEquals("[2]", path.get(2).field);
268     assertTrue(path.get(2).isDominator);
269 
270     assertEquals(base, path.get(3).instance);
271     assertTrue(path.get(3).isDominator);
272 
273     // There are two possible paths. Either it can go through the 'left' node,
274     // or the 'right' node.
275     if (path.get(3).field.equals(".left")) {
276       assertEquals(".left", path.get(3).field);
277 
278       assertEquals(left, path.get(4).instance);
279       assertEquals(".right", path.get(4).field);
280       assertFalse(path.get(4).isDominator);
281 
282     } else {
283       assertEquals(".right", path.get(3).field);
284 
285       assertEquals(right, path.get(4).instance);
286       assertEquals(".left", path.get(4).field);
287       assertFalse(path.get(4).isDominator);
288     }
289 
290     assertEquals(target, path.get(5).instance);
291     assertEquals("", path.get(5).field);
292     assertTrue(path.get(5).isDominator);
293   }
294 
295   @Test
gcRootPathNotWeak()296   public void gcRootPathNotWeak() throws IOException {
297     TestDump dump = TestDump.getTestDump();
298 
299     // The test dump is set up to have the following graph:
300     //  -S-> strong1 -S-> strong2 -S-> strong3 -S-> object
301     //  -S-> weak1 -W-> weak2 ------------------S->-/
302     // The gc root path should go through the longer chain of strong
303     // references, not the shorter chain with weak references (even though the
304     // last element in the shorter chain is a strong reference).
305 
306     AhatInstance strong1 = dump.getDumpedAhatInstance("aLongStrongPathToSamplePathObject");
307     AhatInstance strong2 = strong1.getField("referent").asAhatInstance();
308     AhatInstance strong3 = strong2.getField("referent").asAhatInstance();
309     AhatInstance object = strong3.getField("referent").asAhatInstance();
310 
311     List<PathElement> path = object.getPathFromGcRoot();
312     assertEquals(strong3, path.get(path.size() - 2).instance);
313   }
314 
315   @Test
retainedSize()316   public void retainedSize() throws IOException {
317     TestDump dump = TestDump.getTestDump();
318 
319     // anObject should not be an immediate dominator of any other object. This
320     // means its retained size should be equal to its size for the heap it was
321     // allocated on, and should be 0 for all other heaps.
322     AhatInstance anObject = dump.getDumpedAhatInstance("anObject");
323     AhatSnapshot snapshot = dump.getAhatSnapshot();
324     Size size = anObject.getSize();
325     assertEquals(size, anObject.getTotalRetainedSize());
326     assertEquals(size, anObject.getRetainedSize(anObject.getHeap()));
327     for (AhatHeap heap : snapshot.getHeaps()) {
328       if (!heap.equals(anObject.getHeap())) {
329         assertEquals(String.format("For heap '%s'", heap.getName()),
330             Size.ZERO, anObject.getRetainedSize(heap));
331       }
332     }
333   }
334 
335   @Test
retainedSizeByRetained()336   public void retainedSizeByRetained() throws IOException {
337     // The test dump program should never be under enough GC pressure for the
338     // soft reference to be cleared. The referent should be included in
339     // retained size if --retained is soft, but not if --retained is strong.
340     TestDump dumpStrong = TestDump.getTestDump("test-dump.hprof",
341                                                "test-dump-base.hprof",
342                                                "test-dump.map",
343                                                Reachability.STRONG);
344     AhatInstance refStrong = dumpStrong.getDumpedAhatInstance("aSoftReference");
345     long sizeStrong = refStrong.getTotalRetainedSize().getSize();
346 
347     TestDump dumpSoft = TestDump.getTestDump("test-dump.hprof",
348                                              "test-dump-base.hprof",
349                                              "test-dump.map",
350                                              Reachability.SOFT);
351     AhatInstance refSoft = dumpSoft.getDumpedAhatInstance("aSoftReference");
352     long sizeSoft = refSoft.getTotalRetainedSize().getSize();
353 
354     assertTrue(sizeStrong < sizeSoft);
355   }
356 
357   @Test
358   public void objectNotABitmap() throws IOException {
359     TestDump dump = TestDump.getTestDump();
360     AhatInstance obj = dump.getDumpedAhatInstance("anObject");
361     assertNull(obj.asBitmap());
362   }
363 
364   @Test
365   public void arrayNotABitmap() throws IOException {
366     TestDump dump = TestDump.getTestDump();
367     AhatInstance obj = dump.getDumpedAhatInstance("gcPathArray");
368     assertNull(obj.asBitmap());
369   }
370 
371   @Test
372   public void classObjNotABitmap() throws IOException {
373     TestDump dump = TestDump.getTestDump();
374     AhatInstance obj = dump.findClass("Main");
375     assertNull(obj.asBitmap());
376   }
377 
378   @Test
379   public void classInstanceToString() throws IOException {
380     TestDump dump = TestDump.getTestDump();
381     AhatInstance obj = dump.getDumpedAhatInstance("aPhantomReference");
382     long id = obj.getId();
383     assertEquals(String.format("java.lang.ref.PhantomReference@%08x", id), obj.toString());
384   }
385 
386   @Test
387   public void classObjToString() throws IOException {
388     TestDump dump = TestDump.getTestDump();
389     AhatInstance obj = dump.findClass("Main");
390     assertEquals("class Main", obj.toString());
391   }
392 
393   @Test
394   public void arrayInstanceToString() throws IOException {
395     TestDump dump = TestDump.getTestDump();
396     AhatInstance obj = dump.getDumpedAhatInstance("gcPathArray");
397     long id = obj.getId();
398 
399     // There's a bug in perfib's proguard deobfuscation for arrays.
400     // To work around that bug for the time being, only test the suffix of
401     // the toString result. Ideally we test for string equality against
402     // "Main$ObjectTree[4]@%08x", id.
403     assertTrue(obj.toString().endsWith(String.format("[4]@%08x", id)));
404   }
405 
406   @Test
407   public void primArrayInstanceToString() throws IOException {
408     TestDump dump = TestDump.getTestDump();
409     AhatInstance obj = dump.getDumpedAhatInstance("bigArray");
410     long id = obj.getId();
411     assertEquals(String.format("byte[1000000]@%08x", id), obj.toString());
412   }
413 
414   @Test
415   public void isRoot() throws IOException {
416     // We expect the Main class to be a root.
417     TestDump dump = TestDump.getTestDump();
418     AhatInstance main = dump.findClass("Main");
419     assertTrue(main.isRoot());
420     assertNull(main.getImmediateDominator());
421   }
422 
423   @Test
424   public void isNotRoot() throws IOException {
425     TestDump dump = TestDump.getTestDump();
426     AhatInstance obj = dump.getDumpedAhatInstance("anObject");
427     assertFalse(obj.isRoot());
428     assertNull(obj.getRootTypes());
429   }
430 
431   @Test
432   public void weakRefToGcRoot() throws IOException {
433     TestDump dump = TestDump.getTestDump();
434     AhatInstance ref = dump.getDumpedAhatInstance("aWeakRefToGcRoot");
435 
436     // The weak reference points to Main.class, which we expect will be marked
437     // as a GC root. In theory Main.class doesn't have to be a GC root, in
438     // which case this test case will need to be revised.
439     AhatInstance root = ref.getField("referent").asAhatInstance();
440     assertTrue(root.isRoot());
441 
442     // We had a bug in the past where weak references to GC roots caused the
443     // roots to be incorrectly be considered weakly reachable.
444     assertEquals(Reachability.STRONG, root.getReachability());
445     assertTrue(root.isStronglyReachable());
446     assertFalse(root.isWeaklyReachable());
447   }
448 
449   @Test
450   public void softReferenceChain() throws IOException {
451     // If the only reference to a chain of strongly referenced objects is a
452     // soft reference, then all of the objects should be considered softly
453     // reachable.
454     TestDump dump = TestDump.getTestDump();
455     AhatInstance ref = dump.getDumpedAhatInstance("aSoftChain");
456     AhatInstance soft1 = ref.getField("referent").asAhatInstance();
457     AhatInstance soft2 = soft1.getField("referent").asAhatInstance();
458     AhatInstance soft3 = soft2.getField("referent").asAhatInstance();
459     assertTrue(ref.isStronglyReachable());
460     assertEquals(Reachability.SOFT, soft1.getReachability());
461     assertEquals(Reachability.SOFT, soft2.getReachability());
462     assertEquals(Reachability.SOFT, soft3.getReachability());
463 
464     // Test the deprecated isWeaklyReachable API, which interprets weak as any
465     // kind of phantom/finalizer/weak/soft reference.
466     assertTrue(soft1.isWeaklyReachable());
467     assertTrue(soft2.isWeaklyReachable());
468     assertTrue(soft3.isWeaklyReachable());
469   }
470 
471   @Test
472   public void reverseReferences() throws IOException {
473     TestDump dump = TestDump.getTestDump();
474     AhatInstance obj = dump.getDumpedAhatInstance("anObject");
475     AhatInstance ref = dump.getDumpedAhatInstance("aReference");
476     AhatInstance weak = dump.getDumpedAhatInstance("aWeakReference");
477     assertTrue(obj.getReverseReferences().contains(ref));
478     assertTrue(obj.getReverseReferences().contains(weak));
479     assertTrue(obj.getHardReverseReferences().contains(ref));
480     assertFalse(obj.getHardReverseReferences().contains(weak));
481     assertFalse(obj.getSoftReverseReferences().contains(ref));
482     assertTrue(obj.getSoftReverseReferences().contains(weak));
483   }
484 
485   @Test
486   public void asStringEmbedded() throws IOException {
487     // On Android L, image strings were backed by a single big char array.
488     // Verify we show just the relative part of the string, not the entire
489     // char array.
490     TestDump dump = TestDump.getTestDump("L.hprof", null, null, Reachability.STRONG);
491     AhatSnapshot snapshot = dump.getAhatSnapshot();
492 
493     // java.lang.String@0x6fe17050 is an image string "char" backed by a
494     // shared char array.
495     AhatInstance str = snapshot.findInstance(0x6fe17050);
496     assertEquals("char", str.asString());
497   }
498 
499   @Test
500   public void nonDefaultHeapRoot() throws IOException {
501     TestDump dump = TestDump.getTestDump("O.hprof", null, null, Reachability.STRONG);
502     AhatSnapshot snapshot = dump.getAhatSnapshot();
503 
504     // java.util.HashMap@6004fdb8 is marked as a VM INTERNAL root.
505     // Previously we had a bug where roots not on the default heap were not
506     // properly treated as roots (b/65356532).
507     AhatInstance map = snapshot.findInstance(0x6004fdb8);
508     assertEquals("java.util.HashMap", map.getClassName());
509     assertTrue(map.isRoot());
510   }
511 
512   @Test
513   public void threadRoot() throws IOException {
514     TestDump dump = TestDump.getTestDump("O.hprof", null, null, Reachability.STRONG);
515     AhatSnapshot snapshot = dump.getAhatSnapshot();
516 
517     // java.lang.Thread@12c03470 is marked as a thread root.
518     // Previously we had a bug where thread roots were not properly treated as
519     // roots (b/65356532).
520     AhatInstance thread = snapshot.findInstance(0x12c03470);
521     assertEquals("java.lang.Thread", thread.getClassName());
522     assertTrue(thread.isRoot());
523   }
524 
525   @Test
526   public void classOfClass() throws IOException {
527     TestDump dump = TestDump.getTestDump();
528     AhatInstance obj = dump.getDumpedAhatInstance("anObject");
529     AhatClassObj cls = obj.getClassObj();
530     AhatClassObj clscls = cls.getClassObj();
531     assertNotNull(clscls);
532     assertEquals("java.lang.Class", clscls.getName());
533   }
534 
535   @Test
536   public void nullValueString() throws IOException {
537     TestDump dump = TestDump.getTestDump("RI.hprof", null, null, Reachability.STRONG);
538     AhatSnapshot snapshot = dump.getAhatSnapshot();
539 
540     // java.lang.String@500001a8 has a null 'value' field, which should not
541     // cause ahat to crash.
542     AhatInstance str = snapshot.findInstance(0x500001a8);
543     assertEquals("java.lang.String", str.getClassName());
544     assertNull(str.asString());
545   }
546 
547   @Test
548   public void classOverhead() throws IOException {
549     TestDump dump = TestDump.getTestDump("O.hprof", null, null, Reachability.STRONG);
550     AhatSnapshot snapshot = dump.getAhatSnapshot();
551 
552     // class libore.io.IoTracker has byte[124]@12c028d1 as its class overhead.
553     AhatInstance overhead = snapshot.findInstance(0x12c028d1);
554     AhatClassObj cls = overhead.getAssociatedClassForOverhead();
555     assertEquals(0x12c028d0, cls.getId());
556     assertEquals("libcore.io.IoTracker", cls.getName());
557 
558     // Other kinds of objects should not have associated classes for overhead.
559     assertNull(cls.getAssociatedClassForOverhead());
560   }
561 
562   @Test
563   public void binderProxy() throws IOException {
564     TestDump dump = TestDump.getTestDump();
565 
566     AhatInstance correctObj = dump.getDumpedAhatInstance("correctBinderProxy");
567     assertEquals("DumpedStuff$IDumpedManager", correctObj.getBinderProxyInterfaceName());
568 
569     AhatInstance imposedObj = dump.getDumpedAhatInstance("imposedBinderProxy");
570     assertNull(imposedObj.getBinderProxyInterfaceName());
571 
572     AhatInstance carriedObj = dump.getDumpedAhatInstance("carriedBinderProxy");
573     assertNull(carriedObj.getBinderProxyInterfaceName());
574   }
575 
576   @Test
577   public void binderToken() throws IOException {
578     TestDump dump = TestDump.getTestDump();
579 
580     // Tokens without a descriptor return an empty string
581     AhatInstance binderToken = dump.getDumpedAhatInstance("binderToken");
582     assertEquals("", binderToken.getBinderTokenDescriptor());
583 
584     // Named binder tokens return their descriptor
585     AhatInstance namedBinderToken = dump.getDumpedAhatInstance("namedBinderToken");
586     assertEquals("awesomeToken", namedBinderToken.getBinderTokenDescriptor());
587 
588     // Binder stubs aren't considered binder tokens
589     AhatInstance binderService = dump.getDumpedAhatInstance("binderService");
590     assertEquals(null, binderService.getBinderTokenDescriptor());
591   }
592 
593   @Test
594   public void binderStub() throws IOException {
595     TestDump dump = TestDump.getTestDump();
596 
597     // Regular binder service returns the interface name and no token descriptor
598     AhatInstance binderService = dump.getDumpedAhatInstance("binderService");
599     assertEquals("DumpedStuff$IDumpedManager", binderService.getBinderStubInterfaceName());
600 
601     // Binder tokens aren't considered binder services
602     AhatInstance binderToken = dump.getDumpedAhatInstance("binderToken");
603     assertEquals(null, binderToken.getBinderStubInterfaceName());
604 
605     // Named binder tokens aren't considered binder services
606     AhatInstance namedBinderToken = dump.getDumpedAhatInstance("namedBinderToken");
607     assertEquals(null, namedBinderToken.getBinderStubInterfaceName());
608 
609     // Fake service returns null
610     AhatInstance fakeService = dump.getDumpedAhatInstance("fakeBinderService");
611     assertNull(fakeService.getBinderStubInterfaceName());
612 
613     // Random non-binder object returns null
614     AhatInstance nonBinderObject = dump.getDumpedAhatInstance("anObject");
615     assertNull(nonBinderObject.getBinderStubInterfaceName());
616   }
617 }
618