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 // On host the mappings end with .art and on device they end with .art] 321 if (line.endsWith(".art]") || line.endsWith(".art")) { 322 reader.close(); 323 return true; 324 } 325 } 326 reader.close(); 327 return false; 328 } catch (Exception e) { 329 throw new RuntimeException(e); 330 } 331 } 332 333 private static class TestConfig { 334 private Class<?> klass = null; 335 private int heapFilter = 0; 336 private int stopAfter = Integer.MAX_VALUE; 337 private int followSet = -1; 338 TestConfig()339 public TestConfig() { 340 } TestConfig(Class<?> klass, int heapFilter)341 public TestConfig(Class<?> klass, int heapFilter) { 342 this.klass = klass; 343 this.heapFilter = heapFilter; 344 } TestConfig(Class<?> klass, int heapFilter, int stopAfter, int followSet)345 public TestConfig(Class<?> klass, int heapFilter, int stopAfter, int followSet) { 346 this.klass = klass; 347 this.heapFilter = heapFilter; 348 this.stopAfter = stopAfter; 349 this.followSet = followSet; 350 } 351 doFollowReferencesTest()352 public void doFollowReferencesTest() throws Exception { 353 // Force GCs to clean up dirt. 354 Runtime.getRuntime().gc(); 355 Runtime.getRuntime().gc(); 356 357 setTag(Thread.currentThread(), 3000); 358 359 { 360 ArrayList<Object> tmpStorage = new ArrayList<>(); 361 doFollowReferencesTestNonRoot(tmpStorage); 362 tmpStorage = null; 363 } 364 365 // Force GCs to clean up dirt. 366 Runtime.getRuntime().gc(); 367 Runtime.getRuntime().gc(); 368 369 doFollowReferencesTestRoot(); 370 371 // Force GCs to clean up dirt. 372 Runtime.getRuntime().gc(); 373 Runtime.getRuntime().gc(); 374 } 375 doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage)376 private void doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage) { 377 Verifier v = new Verifier(); 378 tagClasses(v); 379 A a = createTree(v); 380 tmpStorage.add(a); 381 v.add("0@0", "1@1000"); // tmpStorage[0] --(array-element)--> a. 382 383 doFollowReferencesTestImpl(null, stopAfter, followSet, null, v, null); 384 doFollowReferencesTestImpl(a.foo2, stopAfter, followSet, null, v, "3@1001"); 385 386 tmpStorage.clear(); 387 } 388 doFollowReferencesTestRoot()389 private void doFollowReferencesTestRoot() { 390 Verifier v = new Verifier(); 391 tagClasses(v); 392 A a = createTree(v); 393 394 doFollowReferencesTestImpl(null, stopAfter, followSet, a, v, null); 395 doFollowReferencesTestImpl(a.foo2, stopAfter, followSet, a, v, "3@1001"); 396 } 397 doFollowReferencesTestImpl(A root, int stopAfter, int followSet, Object asRoot, Verifier v, String additionalEnabled)398 private void doFollowReferencesTestImpl(A root, int stopAfter, int followSet, 399 Object asRoot, Verifier v, String additionalEnabled) { 400 String[] lines = 401 followReferences(heapFilter, klass, root, stopAfter, followSet, asRoot); 402 403 v.process(lines, additionalEnabled, heapFilter != 0 || klass != null); 404 } 405 tagClasses(Verifier v)406 private static void tagClasses(Verifier v) { 407 setTag(A.class, 1000); 408 registerClass(1000, A.class); 409 410 setTag(B.class, 1001); 411 registerClass(1001, B.class); 412 v.add("1001@0", "1000@0"); // B.class --(superclass)--> A.class. 413 414 setTag(C.class, 1002); 415 registerClass(1002, C.class); 416 v.add("1002@0", "1001@0"); // C.class --(superclass)--> B.class. 417 v.add("1002@0", "2001@0"); // C.class --(interface)--> I2.class. 418 419 setTag(I1.class, 2000); 420 registerClass(2000, I1.class); 421 422 setTag(I2.class, 2001); 423 registerClass(2001, I2.class); 424 v.add("2001@0", "2000@0"); // I2.class --(interface)--> I1.class. 425 } 426 createTree(Verifier v)427 private static A createTree(Verifier v) { 428 A aInst = new A(); 429 setTag(aInst, 1); 430 String aInstStr = "1@1000"; 431 String aClassStr = "1000@0"; 432 v.add(aInstStr, aClassStr); // A -->(class) --> A.class. 433 434 A a2Inst = new A(); 435 setTag(a2Inst, 2); 436 aInst.foo = a2Inst; 437 String a2InstStr = "2@1000"; 438 v.add(a2InstStr, aClassStr); // A2 -->(class) --> A.class. 439 v.add(aInstStr, a2InstStr); // A -->(field) --> A2. 440 441 B bInst = new B(); 442 setTag(bInst, 3); 443 aInst.foo2 = bInst; 444 String bInstStr = "3@1001"; 445 String bClassStr = "1001@0"; 446 v.add(bInstStr, bClassStr); // B -->(class) --> B.class. 447 v.add(aInstStr, bInstStr); // A -->(field) --> B. 448 449 A a3Inst = new A(); 450 setTag(a3Inst, 4); 451 bInst.bar = a3Inst; 452 String a3InstStr = "4@1000"; 453 v.add(a3InstStr, aClassStr); // A3 -->(class) --> A.class. 454 v.add(bInstStr, a3InstStr); // B -->(field) --> A3. 455 456 C cInst = new C(); 457 setTag(cInst, 5); 458 bInst.bar2 = cInst; 459 String cInstStr = "5@1000"; 460 String cClassStr = "1002@0"; 461 v.add(cInstStr, cClassStr); // C -->(class) --> C.class. 462 v.add(bInstStr, cInstStr); // B -->(field) --> C. 463 464 A a4Inst = new A(); 465 setTag(a4Inst, 6); 466 cInst.baz = a4Inst; 467 String a4InstStr = "6@1000"; 468 v.add(a4InstStr, aClassStr); // A4 -->(class) --> A.class. 469 v.add(cInstStr, a4InstStr); // C -->(field) --> A4. 470 471 cInst.baz2 = aInst; 472 v.add(cInstStr, aInstStr); // C -->(field) --> A. 473 474 A[] aArray = new A[2]; 475 setTag(aArray, 500); 476 aArray[1] = a2Inst; 477 cInst.array = aArray; 478 String aArrayStr = "500@0"; 479 v.add(cInstStr, aArrayStr); 480 v.add(aArrayStr, a2InstStr); 481 482 return aInst; 483 } 484 } 485 486 public static class A { 487 public A foo; 488 public A foo2; 489 A()490 public A() {} A(A a, A b)491 public A(A a, A b) { 492 foo = a; 493 foo2 = b; 494 } 495 } 496 497 public static class B extends A { 498 public A bar; 499 public A bar2; 500 B()501 public B() {} B(A a, A b)502 public B(A a, A b) { 503 bar = a; 504 bar2 = b; 505 } 506 } 507 508 public static interface I1 { 509 public final static int i1Field = 1; 510 } 511 512 public static interface I2 extends I1 { 513 public final static int i2Field = 2; 514 } 515 516 public static class C extends B implements I2 { 517 public A baz; 518 public A baz2; 519 public A[] array; 520 C()521 public C() {} C(A a, A b)522 public C(A a, A b) { 523 baz = a; 524 baz2 = b; 525 } 526 } 527 528 private static interface Inf1 { 529 public final static int A = 1; 530 } 531 532 private static interface Inf2 extends Inf1 { 533 public final static int B = 1; 534 } 535 536 private static class IntObject implements Inf1 { 537 byte b = (byte)1; 538 char c= 'a'; 539 short s = (short)2; 540 int i = 3; 541 long l = 4; 542 Object o = new Object(); 543 static int sI = 5; 544 } 545 546 private static class FloatObject extends IntObject implements Inf2 { 547 float f = 1.23f; 548 double d = 1.23; 549 Object p = new Object(); 550 static int sI = 6; 551 } 552 553 public static class Verifier { 554 // Should roots with vreg=-1 be printed? 555 public final static boolean PRINT_ROOTS_WITH_UNKNOWN_VREG = false; 556 557 public static class Node { 558 public String referrer; 559 560 public HashSet<String> referrees = new HashSet<>(); 561 Node(String r)562 public Node(String r) { 563 referrer = r; 564 } 565 isRoot()566 public boolean isRoot() { 567 return referrer.startsWith("root@"); 568 } 569 } 570 571 HashMap<String, Node> nodes = new HashMap<>(); 572 Verifier()573 public Verifier() { 574 } 575 add(String referrer, String referree)576 public void add(String referrer, String referree) { 577 if (!nodes.containsKey(referrer)) { 578 nodes.put(referrer, new Node(referrer)); 579 } 580 if (referree != null) { 581 nodes.get(referrer).referrees.add(referree); 582 } 583 } 584 process(String[] lines, String additionalEnabledReferrer, boolean filtered)585 public void process(String[] lines, String additionalEnabledReferrer, boolean filtered) { 586 // This method isn't optimal. The loops could be merged. However, it's more readable if 587 // the different parts are separated. 588 589 ArrayList<String> rootLines = new ArrayList<>(); 590 ArrayList<String> nonRootLines = new ArrayList<>(); 591 592 // Check for consecutive chunks of referrers. Also ensure roots come first. 593 { 594 String currentHead = null; 595 boolean rootsDone = false; 596 HashSet<String> completedReferrers = new HashSet<>(); 597 for (String l : lines) { 598 String referrer = getReferrer(l); 599 600 if (isRoot(referrer)) { 601 if (rootsDone) { 602 System.out.println("ERROR: Late root " + l); 603 print(lines); 604 return; 605 } 606 rootLines.add(l); 607 continue; 608 } 609 610 rootsDone = true; 611 612 if (currentHead == null) { 613 currentHead = referrer; 614 } else { 615 // Ignore 0@0, as it can happen at any time (as it stands for all other objects). 616 if (!currentHead.equals(referrer) && !referrer.equals("0@0")) { 617 completedReferrers.add(currentHead); 618 currentHead = referrer; 619 if (completedReferrers.contains(referrer)) { 620 System.out.println("Non-contiguous referrer " + l); 621 print(lines); 622 return; 623 } 624 } 625 } 626 nonRootLines.add(l); 627 } 628 } 629 630 // Sort (root order is not specified) and print the roots. 631 // TODO: What about extra roots? JNI and the interpreter seem to introduce those (though it 632 // isn't clear why a debuggable-AoT test doesn't have the same, at least for locals). 633 // For now, swallow duplicates, and resolve once we have the metadata for the roots. 634 { 635 Collections.sort(rootLines); 636 String lastRoot = null; 637 for (String l : rootLines) { 638 if (lastRoot != null && lastRoot.equals(l)) { 639 continue; 640 } 641 lastRoot = l; 642 if (!PRINT_ROOTS_WITH_UNKNOWN_VREG && l.indexOf("vreg=-1") > 0) { 643 continue; 644 } 645 System.out.println(l); 646 } 647 } 648 649 if (filtered) { 650 // If we aren't tracking dependencies, just sort the lines and print. 651 // TODO: As the verifier is currently using the output lines to track dependencies, we 652 // cannot verify that output is correct when parts of it are suppressed by filters. 653 // To correctly track this we need to take node information into account, and 654 // actually analyze the graph. 655 Collections.sort(nonRootLines); 656 for (String l : nonRootLines) { 657 System.out.println(l); 658 } 659 660 System.out.println("---"); 661 return; 662 } 663 664 // Iterate through the lines, keeping track of which referrers are visited, to ensure the 665 // order is acceptable. 666 HashSet<String> enabled = new HashSet<>(); 667 if (additionalEnabledReferrer != null) { 668 enabled.add(additionalEnabledReferrer); 669 } 670 // Always add "0@0". 671 enabled.add("0@0"); 672 673 for (String l : lines) { 674 String referrer = getReferrer(l); 675 String referree = getReferree(l); 676 if (isRoot(referrer)) { 677 // For a root src, just enable the referree. 678 enabled.add(referree); 679 } else { 680 // Check that the referrer is enabled (may be visited). 681 if (!enabled.contains(referrer)) { 682 System.out.println("Referrer " + referrer + " not enabled: " + l); 683 print(lines); 684 return; 685 } 686 enabled.add(referree); 687 } 688 } 689 690 // Now just sort the non-root lines and output them 691 Collections.sort(nonRootLines); 692 for (String l : nonRootLines) { 693 System.out.println(l); 694 } 695 696 System.out.println("---"); 697 } 698 isRoot(String ref)699 public static boolean isRoot(String ref) { 700 return ref.startsWith("root@"); 701 } 702 getReferrer(String line)703 private static String getReferrer(String line) { 704 int i = line.indexOf(" --"); 705 if (i <= 0) { 706 throw new IllegalArgumentException(line); 707 } 708 int j = line.indexOf(' '); 709 if (i != j) { 710 throw new IllegalArgumentException(line); 711 } 712 return line.substring(0, i); 713 } 714 getReferree(String line)715 private static String getReferree(String line) { 716 int i = line.indexOf("--> "); 717 if (i <= 0) { 718 throw new IllegalArgumentException(line); 719 } 720 int j = line.indexOf(' ', i + 4); 721 if (j < 0) { 722 throw new IllegalArgumentException(line); 723 } 724 return line.substring(i + 4, j); 725 } 726 print(String[] lines)727 private static void print(String[] lines) { 728 for (String l : lines) { 729 System.out.println(l); 730 } 731 } 732 } 733 setTag(Object o, long tag)734 private static void setTag(Object o, long tag) { 735 Main.setTag(o, tag); 736 } getTag(Object o)737 private static long getTag(Object o) { 738 return Main.getTag(o); 739 } 740 checkInitialized(Class<?> klass)741 private static native boolean checkInitialized(Class<?> klass); setupGcCallback()742 private static native void setupGcCallback(); enableGcTracking(boolean enable)743 private static native void enableGcTracking(boolean enable); getGcStarts()744 private static native int getGcStarts(); getGcFinishes()745 private static native int getGcFinishes(); forceGarbageCollection()746 private static native void forceGarbageCollection(); 747 checkForExtensionApis()748 private static native void checkForExtensionApis(); getObjectHeapId(long tag)749 private static native int getObjectHeapId(long tag); getHeapName(int heapId)750 private static native String getHeapName(int heapId); checkGetObjectHeapIdInCallback(long tag, int heapId)751 private static native void checkGetObjectHeapIdInCallback(long tag, int heapId); 752 followReferences(int heapFilter, Class<?> klassFilter, Object initialObject, int stopAfter, int followSet, Object jniRef)753 public static native String[] followReferences(int heapFilter, Class<?> klassFilter, 754 Object initialObject, int stopAfter, int followSet, Object jniRef); followReferencesString(Object initialObject)755 public static native String[] followReferencesString(Object initialObject); followReferencesPrimitiveArray(Object initialObject)756 public static native String followReferencesPrimitiveArray(Object initialObject); followReferencesPrimitiveFields(Object initialObject)757 public static native String followReferencesPrimitiveFields(Object initialObject); 758 iterateThroughHeapExt()759 private static native void iterateThroughHeapExt(); 760 registerClass(long tag, Object obj)761 private static native void registerClass(long tag, Object obj); 762 } 763