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