1 /*
2  * Copyright (C) 2016 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 art;
18 
19 import java.io.BufferedReader;
20 import java.io.File;
21 import java.io.FileReader;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.concurrent.CountDownLatch;
28 
29 public class Test913 {
run()30   public static void run() throws Exception {
31     doTest();
32 
33     // Use a countdown latch for synchronization, as join() will introduce more roots.
34     final CountDownLatch cdl1 = new CountDownLatch(1);
35 
36     // Run the follow-references tests on a dedicated thread so we know the specific Thread type.
37     Thread t = new Thread() {
38       @Override
39       public void run() {
40         try {
41           Test913.runFollowReferences();
42         } catch (Exception e) {
43           throw new RuntimeException(e);
44         }
45         cdl1.countDown();
46       }
47     };
48     t.start();
49     cdl1.await();
50 
51     doExtensionTests();
52   }
53 
runFollowReferences()54   public static void runFollowReferences() throws Exception {
55     new TestConfig().doFollowReferencesTest();
56 
57     Runtime.getRuntime().gc();
58     Runtime.getRuntime().gc();
59 
60     new TestConfig(null, 0, 1, -1).doFollowReferencesTest();
61 
62     Runtime.getRuntime().gc();
63     Runtime.getRuntime().gc();
64 
65     new TestConfig(null, 0, Integer.MAX_VALUE, 1).doFollowReferencesTest();
66 
67     Runtime.getRuntime().gc();
68     Runtime.getRuntime().gc();
69 
70     doStringTest();
71 
72     Runtime.getRuntime().gc();
73     Runtime.getRuntime().gc();
74 
75     doPrimitiveArrayTest();
76     doPrimitiveFieldTest();
77 
78     Runtime.getRuntime().gc();
79     Runtime.getRuntime().gc();
80 
81     // Test klass filter.
82     System.out.println("--- klass ---");
83     new TestConfig(A.class, 0).doFollowReferencesTest();
84 
85     // Test heap filter.
86     System.out.println("--- heap_filter ---");
87     System.out.println("---- tagged objects");
88     new TestConfig(null, 0x4).doFollowReferencesTest();
89     System.out.println("---- untagged objects");
90     new TestConfig(null, 0x8).doFollowReferencesTest();
91     System.out.println("---- tagged classes");
92     new TestConfig(null, 0x10).doFollowReferencesTest();
93     System.out.println("---- untagged classes");
94     new TestConfig(null, 0x20).doFollowReferencesTest();
95   }
96 
doTest()97   public static void doTest() throws Exception {
98     setupGcCallback();
99 
100     enableGcTracking(true);
101     runGc();
102     enableGcTracking(false);
103   }
104 
doStringTest()105   public static void doStringTest() throws Exception {
106     final String str = new String("HelloWorld");
107     final String str2 = new String("");
108     Object o = new Object() {
109       String s = str;
110       String s2 = str2;
111     };
112 
113     setTag(str, 1);
114     setTag(str2, 2);
115     System.out.println(Arrays.toString(followReferencesString(o)));
116     System.out.println(getTag(str));
117     System.out.println(getTag(str2));
118   }
119 
doPrimitiveArrayTest()120   public static void doPrimitiveArrayTest() throws Exception {
121     final boolean[] zArray = new boolean[] { false, true };
122     setTag(zArray, 1);
123 
124     final byte[] bArray = new byte[] { 1, 2, 3 };
125     setTag(bArray, 2);
126 
127     final char[] cArray = new char[] { 'A', 'Z' };
128     setTag(cArray, 3);
129 
130     final short[] sArray = new short[] { 1, 2, 3 };
131     setTag(sArray, 4);
132 
133     final int[] iArray = new int[] { 1, 2, 3 };
134     setTag(iArray, 5);
135 
136     final float[] fArray = new float[] { 0.0f, 1.0f };
137     setTag(fArray, 6);
138 
139     final long[] lArray = new long[] { 1, 2, 3 };
140     setTag(lArray, 7);
141 
142     final double[] dArray = new double[] { 0.0, 1.0 };
143     setTag(dArray, 8);
144 
145     Object o = new Object() {
146       Object z = zArray;
147       Object b = bArray;
148       Object c = cArray;
149       Object s = sArray;
150       Object i = iArray;
151       Object f = fArray;
152       Object l = lArray;
153       Object d = dArray;
154     };
155 
156     System.out.println(followReferencesPrimitiveArray(o));
157     System.out.print(getTag(zArray));
158     System.out.print(getTag(bArray));
159     System.out.print(getTag(cArray));
160     System.out.print(getTag(sArray));
161     System.out.print(getTag(iArray));
162     System.out.print(getTag(fArray));
163     System.out.print(getTag(lArray));
164     System.out.println(getTag(dArray));
165   }
166 
doPrimitiveFieldTest()167   public static void doPrimitiveFieldTest() throws Exception {
168     // Force GCs to clean up dirt.
169     Runtime.getRuntime().gc();
170     Runtime.getRuntime().gc();
171 
172     doTestPrimitiveFieldsClasses();
173 
174     doTestPrimitiveFieldsIntegral();
175 
176     // Force GCs to clean up dirt.
177     Runtime.getRuntime().gc();
178     Runtime.getRuntime().gc();
179 
180     doTestPrimitiveFieldsFloat();
181 
182     // Force GCs to clean up dirt.
183     Runtime.getRuntime().gc();
184     Runtime.getRuntime().gc();
185   }
186 
doTestPrimitiveFieldsClasses()187   private static void doTestPrimitiveFieldsClasses() {
188     setTag(IntObject.class, 10000);
189     System.out.println(followReferencesPrimitiveFields(IntObject.class));
190     System.out.println(getTag(IntObject.class));
191     setTag(IntObject.class, 0);
192 
193     setTag(FloatObject.class, 10000);
194     System.out.println(followReferencesPrimitiveFields(FloatObject.class));
195     System.out.println(getTag(FloatObject.class));
196     setTag(FloatObject.class, 0);
197 
198     boolean correctHeapValue = false;
199     setTag(Inf1.class, 10000);
200     String heapTrace = followReferencesPrimitiveFields(Inf1.class);
201 
202     if (!checkInitialized(Inf1.class)) {
203       correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000");
204     } else {
205       correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000001");
206     }
207 
208     if (!correctHeapValue)
209       System.out.println("Heap Trace for Inf1 is not as expected:\n" + heapTrace);
210 
211     System.out.println(getTag(Inf1.class));
212     setTag(Inf1.class, 0);
213 
214     setTag(Inf2.class, 10000);
215     heapTrace = followReferencesPrimitiveFields(Inf2.class);
216 
217     if (!checkInitialized(Inf2.class)) {
218       correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000000");
219     } else {
220       correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000001");
221     }
222 
223     if (!correctHeapValue)
224       System.out.println("Heap Trace for Inf2 is not as expected:\n" + heapTrace);
225     System.out.println(getTag(Inf2.class));
226     setTag(Inf2.class, 0);
227   }
228 
doTestPrimitiveFieldsIntegral()229   private static void doTestPrimitiveFieldsIntegral() {
230     IntObject intObject = new IntObject();
231     setTag(intObject, 10000);
232     System.out.println(followReferencesPrimitiveFields(intObject));
233     System.out.println(getTag(intObject));
234   }
235 
doTestPrimitiveFieldsFloat()236   private static void doTestPrimitiveFieldsFloat() {
237     FloatObject floatObject = new FloatObject();
238     setTag(floatObject, 10000);
239     System.out.println(followReferencesPrimitiveFields(floatObject));
240     System.out.println(getTag(floatObject));
241   }
242 
243   static ArrayList<Object> extensionTestHolder;
244 
doExtensionTests()245   private static void doExtensionTests() {
246     checkForExtensionApis();
247 
248     extensionTestHolder = new ArrayList<>();
249     System.out.println();
250 
251     try {
252       getHeapName(-1);
253       System.out.println("Expected failure for -1");
254     } catch (Exception e) {
255     }
256     System.out.println(getHeapName(0));
257     System.out.println(getHeapName(1));
258     System.out.println(getHeapName(2));
259     System.out.println(getHeapName(3));
260     try {
261       getHeapName(4);
262       System.out.println("Expected failure for -1");
263     } catch (Exception e) {
264     }
265 
266     System.out.println();
267 
268     setTag(Object.class, 100000);
269     int objectClassHeapId = getObjectHeapId(100000);
270     int objClassExpectedHeapId = hasImage() ? 1 : 3;
271     if (objectClassHeapId != objClassExpectedHeapId) {
272       throw new RuntimeException("Expected object class in heap " + objClassExpectedHeapId +
273           " but received " + objectClassHeapId);
274     }
275 
276     A a = new A();
277     extensionTestHolder.add(a);
278     setTag(a, 100001);
279     System.out.println(getObjectHeapId(100001));
280 
281     checkGetObjectHeapIdInCallback(100000, objClassExpectedHeapId);
282     checkGetObjectHeapIdInCallback(100001, 3);
283 
284     long baseTag = 30000000;
285     setTag(Object.class, baseTag + objClassExpectedHeapId);
286     setTag(Class.class, baseTag + objClassExpectedHeapId);
287     Object o = new Object();
288     extensionTestHolder.add(o);
289     setTag(o, baseTag + 3);
290 
291     iterateThroughHeapExt();
292 
293     extensionTestHolder = null;
294   }
295 
runGc()296   private static void runGc() {
297     clearStats();
298     forceGarbageCollection();
299     printStats();
300   }
301 
clearStats()302   private static void clearStats() {
303     getGcStarts();
304     getGcFinishes();
305   }
306 
printStats()307   private static void printStats() {
308     System.out.println("---");
309     int s = getGcStarts();
310     int f = getGcFinishes();
311     System.out.println((s > 0) + " " + (f > 0));
312   }
313 
hasImage()314   private static boolean hasImage() {
315     try {
316       int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
317       BufferedReader reader = new BufferedReader(new FileReader("/proc/" + pid + "/maps"));
318       String line;
319       while ((line = reader.readLine()) != null) {
320         if (line.endsWith(".art")) {
321           reader.close();
322           return true;
323         }
324       }
325       reader.close();
326       return false;
327     } catch (Exception e) {
328       throw new RuntimeException(e);
329     }
330   }
331 
332   private static class TestConfig {
333     private Class<?> klass = null;
334     private int heapFilter = 0;
335     private int stopAfter = Integer.MAX_VALUE;
336     private int followSet = -1;
337 
TestConfig()338     public TestConfig() {
339     }
TestConfig(Class<?> klass, int heapFilter)340     public TestConfig(Class<?> klass, int heapFilter) {
341       this.klass = klass;
342       this.heapFilter = heapFilter;
343     }
TestConfig(Class<?> klass, int heapFilter, int stopAfter, int followSet)344     public TestConfig(Class<?> klass, int heapFilter, int stopAfter, int followSet) {
345       this.klass = klass;
346       this.heapFilter = heapFilter;
347       this.stopAfter = stopAfter;
348       this.followSet = followSet;
349     }
350 
doFollowReferencesTest()351     public void doFollowReferencesTest() throws Exception {
352       // Force GCs to clean up dirt.
353       Runtime.getRuntime().gc();
354       Runtime.getRuntime().gc();
355 
356       setTag(Thread.currentThread(), 3000);
357 
358       {
359         ArrayList<Object> tmpStorage = new ArrayList<>();
360         doFollowReferencesTestNonRoot(tmpStorage);
361         tmpStorage = null;
362       }
363 
364       // Force GCs to clean up dirt.
365       Runtime.getRuntime().gc();
366       Runtime.getRuntime().gc();
367 
368       doFollowReferencesTestRoot();
369 
370       // Force GCs to clean up dirt.
371       Runtime.getRuntime().gc();
372       Runtime.getRuntime().gc();
373     }
374 
doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage)375     private void doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage) {
376       Verifier v = new Verifier();
377       tagClasses(v);
378       A a = createTree(v);
379       tmpStorage.add(a);
380       v.add("0@0", "1@1000");  // tmpStorage[0] --(array-element)--> a.
381 
382       doFollowReferencesTestImpl(null, stopAfter, followSet, null, v, null);
383       doFollowReferencesTestImpl(a.foo2, stopAfter, followSet, null, v, "3@1001");
384 
385       tmpStorage.clear();
386     }
387 
doFollowReferencesTestRoot()388     private void doFollowReferencesTestRoot() {
389       Verifier v = new Verifier();
390       tagClasses(v);
391       A a = createTree(v);
392 
393       doFollowReferencesTestImpl(null, stopAfter, followSet, a, v, null);
394       doFollowReferencesTestImpl(a.foo2, stopAfter, followSet, a, v, "3@1001");
395     }
396 
doFollowReferencesTestImpl(A root, int stopAfter, int followSet, Object asRoot, Verifier v, String additionalEnabled)397     private void doFollowReferencesTestImpl(A root, int stopAfter, int followSet,
398         Object asRoot, Verifier v, String additionalEnabled) {
399       String[] lines =
400           followReferences(heapFilter, klass, root, stopAfter, followSet, asRoot);
401 
402       v.process(lines, additionalEnabled, heapFilter != 0 || klass != null);
403     }
404 
tagClasses(Verifier v)405     private static void tagClasses(Verifier v) {
406       setTag(A.class, 1000);
407       registerClass(1000, A.class);
408 
409       setTag(B.class, 1001);
410       registerClass(1001, B.class);
411       v.add("1001@0", "1000@0");  // B.class --(superclass)--> A.class.
412 
413       setTag(C.class, 1002);
414       registerClass(1002, C.class);
415       v.add("1002@0", "1001@0");  // C.class --(superclass)--> B.class.
416       v.add("1002@0", "2001@0");  // C.class --(interface)--> I2.class.
417 
418       setTag(I1.class, 2000);
419       registerClass(2000, I1.class);
420 
421       setTag(I2.class, 2001);
422       registerClass(2001, I2.class);
423       v.add("2001@0", "2000@0");  // I2.class --(interface)--> I1.class.
424     }
425 
createTree(Verifier v)426     private static A createTree(Verifier v) {
427       A aInst = new A();
428       setTag(aInst, 1);
429       String aInstStr = "1@1000";
430       String aClassStr = "1000@0";
431       v.add(aInstStr, aClassStr);  // A -->(class) --> A.class.
432 
433       A a2Inst = new A();
434       setTag(a2Inst, 2);
435       aInst.foo = a2Inst;
436       String a2InstStr = "2@1000";
437       v.add(a2InstStr, aClassStr);  // A2 -->(class) --> A.class.
438       v.add(aInstStr, a2InstStr);   // A -->(field) --> A2.
439 
440       B bInst = new B();
441       setTag(bInst, 3);
442       aInst.foo2 = bInst;
443       String bInstStr = "3@1001";
444       String bClassStr = "1001@0";
445       v.add(bInstStr, bClassStr);  // B -->(class) --> B.class.
446       v.add(aInstStr, bInstStr);   // A -->(field) --> B.
447 
448       A a3Inst = new A();
449       setTag(a3Inst, 4);
450       bInst.bar = a3Inst;
451       String a3InstStr = "4@1000";
452       v.add(a3InstStr, aClassStr);  // A3 -->(class) --> A.class.
453       v.add(bInstStr, a3InstStr);   // B -->(field) --> A3.
454 
455       C cInst = new C();
456       setTag(cInst, 5);
457       bInst.bar2 = cInst;
458       String cInstStr = "5@1000";
459       String cClassStr = "1002@0";
460       v.add(cInstStr, cClassStr);  // C -->(class) --> C.class.
461       v.add(bInstStr, cInstStr);   // B -->(field) --> C.
462 
463       A a4Inst = new A();
464       setTag(a4Inst, 6);
465       cInst.baz = a4Inst;
466       String a4InstStr = "6@1000";
467       v.add(a4InstStr, aClassStr);  // A4 -->(class) --> A.class.
468       v.add(cInstStr, a4InstStr);   // C -->(field) --> A4.
469 
470       cInst.baz2 = aInst;
471       v.add(cInstStr, aInstStr);  // C -->(field) --> A.
472 
473       A[] aArray = new A[2];
474       setTag(aArray, 500);
475       aArray[1] = a2Inst;
476       cInst.array = aArray;
477       String aArrayStr = "500@0";
478       v.add(cInstStr, aArrayStr);
479       v.add(aArrayStr, a2InstStr);
480 
481       return aInst;
482     }
483   }
484 
485   public static class A {
486     public A foo;
487     public A foo2;
488 
A()489     public A() {}
A(A a, A b)490     public A(A a, A b) {
491       foo = a;
492       foo2 = b;
493     }
494   }
495 
496   public static class B extends A {
497     public A bar;
498     public A bar2;
499 
B()500     public B() {}
B(A a, A b)501     public B(A a, A b) {
502       bar = a;
503       bar2 = b;
504     }
505   }
506 
507   public static interface I1 {
508     public final static int i1Field = 1;
509   }
510 
511   public static interface I2 extends I1 {
512     public final static int i2Field = 2;
513   }
514 
515   public static class C extends B implements I2 {
516     public A baz;
517     public A baz2;
518     public A[] array;
519 
C()520     public C() {}
C(A a, A b)521     public C(A a, A b) {
522       baz = a;
523       baz2 = b;
524     }
525   }
526 
527   private static interface Inf1 {
528     public final static int A = 1;
529   }
530 
531   private static interface Inf2 extends Inf1 {
532     public final static int B = 1;
533   }
534 
535   private static class IntObject implements Inf1 {
536     byte b = (byte)1;
537     char c= 'a';
538     short s = (short)2;
539     int i = 3;
540     long l = 4;
541     Object o = new Object();
542     static int sI = 5;
543   }
544 
545   private static class FloatObject extends IntObject implements Inf2 {
546     float f = 1.23f;
547     double d = 1.23;
548     Object p = new Object();
549     static int sI = 6;
550   }
551 
552   public static class Verifier {
553     // Should roots with vreg=-1 be printed?
554     public final static boolean PRINT_ROOTS_WITH_UNKNOWN_VREG = false;
555 
556     public static class Node {
557       public String referrer;
558 
559       public HashSet<String> referrees = new HashSet<>();
560 
Node(String r)561       public Node(String r) {
562         referrer = r;
563       }
564 
isRoot()565       public boolean isRoot() {
566         return referrer.startsWith("root@");
567       }
568     }
569 
570     HashMap<String, Node> nodes = new HashMap<>();
571 
Verifier()572     public Verifier() {
573     }
574 
add(String referrer, String referree)575     public void add(String referrer, String referree) {
576       if (!nodes.containsKey(referrer)) {
577         nodes.put(referrer, new Node(referrer));
578       }
579       if (referree != null) {
580         nodes.get(referrer).referrees.add(referree);
581       }
582     }
583 
process(String[] lines, String additionalEnabledReferrer, boolean filtered)584     public void process(String[] lines, String additionalEnabledReferrer, boolean filtered) {
585       // This method isn't optimal. The loops could be merged. However, it's more readable if
586       // the different parts are separated.
587 
588       ArrayList<String> rootLines = new ArrayList<>();
589       ArrayList<String> nonRootLines = new ArrayList<>();
590 
591       // Check for consecutive chunks of referrers. Also ensure roots come first.
592       {
593         String currentHead = null;
594         boolean rootsDone = false;
595         HashSet<String> completedReferrers = new HashSet<>();
596         for (String l : lines) {
597           String referrer = getReferrer(l);
598 
599           if (isRoot(referrer)) {
600             if (rootsDone) {
601               System.out.println("ERROR: Late root " + l);
602               print(lines);
603               return;
604             }
605             rootLines.add(l);
606             continue;
607           }
608 
609           rootsDone = true;
610 
611           if (currentHead == null) {
612             currentHead = referrer;
613           } else {
614             // Ignore 0@0, as it can happen at any time (as it stands for all other objects).
615             if (!currentHead.equals(referrer) && !referrer.equals("0@0")) {
616               completedReferrers.add(currentHead);
617               currentHead = referrer;
618               if (completedReferrers.contains(referrer)) {
619                 System.out.println("Non-contiguous referrer " + l);
620                 print(lines);
621                 return;
622               }
623             }
624           }
625           nonRootLines.add(l);
626         }
627       }
628 
629       // Sort (root order is not specified) and print the roots.
630       // TODO: What about extra roots? JNI and the interpreter seem to introduce those (though it
631       //       isn't clear why a debuggable-AoT test doesn't have the same, at least for locals).
632       //       For now, swallow duplicates, and resolve once we have the metadata for the roots.
633       {
634         Collections.sort(rootLines);
635         String lastRoot = null;
636         for (String l : rootLines) {
637           if (lastRoot != null && lastRoot.equals(l)) {
638             continue;
639           }
640           lastRoot = l;
641           if (!PRINT_ROOTS_WITH_UNKNOWN_VREG && l.indexOf("vreg=-1") > 0) {
642             continue;
643           }
644           System.out.println(l);
645         }
646       }
647 
648       if (filtered) {
649         // If we aren't tracking dependencies, just sort the lines and print.
650         // TODO: As the verifier is currently using the output lines to track dependencies, we
651         //       cannot verify that output is correct when parts of it are suppressed by filters.
652         //       To correctly track this we need to take node information into account, and
653         //       actually analyze the graph.
654         Collections.sort(nonRootLines);
655         for (String l : nonRootLines) {
656           System.out.println(l);
657         }
658 
659         System.out.println("---");
660         return;
661       }
662 
663       // Iterate through the lines, keeping track of which referrers are visited, to ensure the
664       // order is acceptable.
665       HashSet<String> enabled = new HashSet<>();
666       if (additionalEnabledReferrer != null) {
667         enabled.add(additionalEnabledReferrer);
668       }
669       // Always add "0@0".
670       enabled.add("0@0");
671 
672       for (String l : lines) {
673         String referrer = getReferrer(l);
674         String referree = getReferree(l);
675         if (isRoot(referrer)) {
676           // For a root src, just enable the referree.
677           enabled.add(referree);
678         } else {
679           // Check that the referrer is enabled (may be visited).
680           if (!enabled.contains(referrer)) {
681             System.out.println("Referrer " + referrer + " not enabled: " + l);
682             print(lines);
683             return;
684           }
685           enabled.add(referree);
686         }
687       }
688 
689       // Now just sort the non-root lines and output them
690       Collections.sort(nonRootLines);
691       for (String l : nonRootLines) {
692         System.out.println(l);
693       }
694 
695       System.out.println("---");
696     }
697 
isRoot(String ref)698     public static boolean isRoot(String ref) {
699       return ref.startsWith("root@");
700     }
701 
getReferrer(String line)702     private static String getReferrer(String line) {
703       int i = line.indexOf(" --");
704       if (i <= 0) {
705         throw new IllegalArgumentException(line);
706       }
707       int j = line.indexOf(' ');
708       if (i != j) {
709         throw new IllegalArgumentException(line);
710       }
711       return line.substring(0, i);
712     }
713 
getReferree(String line)714     private static String getReferree(String line) {
715       int i = line.indexOf("--> ");
716       if (i <= 0) {
717         throw new IllegalArgumentException(line);
718       }
719       int j = line.indexOf(' ', i + 4);
720       if (j < 0) {
721         throw new IllegalArgumentException(line);
722       }
723       return line.substring(i + 4, j);
724     }
725 
print(String[] lines)726     private static void print(String[] lines) {
727       for (String l : lines) {
728         System.out.println(l);
729       }
730     }
731   }
732 
setTag(Object o, long tag)733   private static void setTag(Object o, long tag) {
734     Main.setTag(o, tag);
735   }
getTag(Object o)736   private static long getTag(Object o) {
737     return Main.getTag(o);
738   }
739 
checkInitialized(Class<?> klass)740   private static native boolean checkInitialized(Class<?> klass);
setupGcCallback()741   private static native void setupGcCallback();
enableGcTracking(boolean enable)742   private static native void enableGcTracking(boolean enable);
getGcStarts()743   private static native int getGcStarts();
getGcFinishes()744   private static native int getGcFinishes();
forceGarbageCollection()745   private static native void forceGarbageCollection();
746 
checkForExtensionApis()747   private static native void checkForExtensionApis();
getObjectHeapId(long tag)748   private static native int getObjectHeapId(long tag);
getHeapName(int heapId)749   private static native String getHeapName(int heapId);
checkGetObjectHeapIdInCallback(long tag, int heapId)750   private static native void checkGetObjectHeapIdInCallback(long tag, int heapId);
751 
followReferences(int heapFilter, Class<?> klassFilter, Object initialObject, int stopAfter, int followSet, Object jniRef)752   public static native String[] followReferences(int heapFilter, Class<?> klassFilter,
753       Object initialObject, int stopAfter, int followSet, Object jniRef);
followReferencesString(Object initialObject)754   public static native String[] followReferencesString(Object initialObject);
followReferencesPrimitiveArray(Object initialObject)755   public static native String followReferencesPrimitiveArray(Object initialObject);
followReferencesPrimitiveFields(Object initialObject)756   public static native String followReferencesPrimitiveFields(Object initialObject);
757 
iterateThroughHeapExt()758   private static native void iterateThroughHeapExt();
759 
registerClass(long tag, Object obj)760   private static native void registerClass(long tag, Object obj);
761 }
762