xref: /aosp_15_r20/art/test/2048-bad-native-registry/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1 /*
2  * Copyright (C) 2007 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 import dalvik.system.VMRuntime;
18 import java.util.concurrent.CountDownLatch;
19 import libcore.util.NativeAllocationRegistry;
20 import java.util.concurrent.TimeoutException;
21 import static java.util.concurrent.TimeUnit.MINUTES;
22 
23 /**
24  * Test a class with a bad finalizer.
25  *
26  * This test is inherently flaky. It assumes that the system will schedule the finalizer daemon
27  * and finalizer watchdog daemon enough to reach the timeout and throwing the fatal exception.
28  * This uses somewhat simpler logic than 2041-bad-cleaner, since the handshake implemented there
29  * is harder to replicate here. We bump up the timeout below a bit to compensate.
30  */
31 public class Main {
main(String[] args)32     public static void main(String[] args) throws Exception {
33         System.loadLibrary(args[0]);
34         ClassLoader cl = Main.class.getClassLoader();
35         NativeAllocationRegistry registry =
36             NativeAllocationRegistry.createNonmalloced(cl, getBadFreeFunction(), 666);
37         // Replace the global uncaught exception handler, so the exception shows up on stdout.
38         Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
39             public void uncaughtException(Thread thread, Throwable e) {
40                 if (e instanceof TimeoutException) {
41                     System.out.println("TimeoutException on "
42                         + thread.getName() + ":" + e.getMessage());
43                 } else {
44                     System.out.println("Unexpected exception " + e);
45                 }
46                 System.exit(2);
47             }
48         });
49         // A separate method to ensure no dex register keeps the object alive.
50         createBadCleanable(registry);
51 
52         // Should have at least two iterations to trigger finalization, but just to make sure run
53         // some more.
54         for (int i = 0; i < 5; i++) {
55             Runtime.getRuntime().gc();
56         }
57 
58         // Now fall asleep with a timeout. The timeout is large enough that we expect the
59         // finalizer daemon to have killed the process before the deadline elapses.
60         // The timeout is also large enough to cover the extra 5 seconds we wait
61         // to dump threads, plus potentially substantial gcstress overhead.
62         // The RQ timeout is currently effectively 5 * the finalizer timeout.
63         // Note: the timeout is here (instead of an infinite sleep) to protect the test
64         //       environment (e.g., in case this is run without a timeout wrapper).
65         final long timeout = 150 * 1000 + 5 * VMRuntime.getRuntime().getFinalizerTimeoutMs();
66         long remainingWait = timeout;
67         final long waitStart = System.currentTimeMillis();
68         while (remainingWait > 0) {
69             synchronized (args) {  // Just use an already existing object for simplicity...
70                 try {
71                     args.wait(remainingWait);
72                 } catch (Exception e) {
73                     System.out.println("UNEXPECTED EXCEPTION");
74                 }
75             }
76             remainingWait = timeout - (System.currentTimeMillis() - waitStart);
77         }
78 
79         // We should not get here.
80         System.out.println("UNREACHABLE");
81         System.exit(0);
82     }
83 
createBadCleanable(NativeAllocationRegistry registry)84     private static void createBadCleanable(NativeAllocationRegistry registry) {
85         Object badCleanable = new Object();
86         long nativeObj = getNativeObj();
87         registry.registerNativeAllocation(badCleanable, nativeObj);
88 
89         System.out.println("About to null reference.");
90         badCleanable = null;  // Not that this would make a difference, could be eliminated earlier.
91     }
92 
getNativeObj()93     private static native long getNativeObj();
getBadFreeFunction()94     private static native long getBadFreeFunction();
95 
96 }
97