xref: /aosp_15_r20/art/test/2041-bad-cleaner/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 sun.misc.Cleaner;
19 import java.util.concurrent.CountDownLatch;
20 import static java.util.concurrent.TimeUnit.MINUTES;
21 
22 /**
23  * Test a class with a bad finalizer.
24  *
25  * This test is inherently flaky. It assumes that the system will schedule the finalizer daemon
26  * and finalizer watchdog daemon enough to reach the timeout and throwing the fatal exception.
27  */
28 public class Main {
main(String[] args)29     public static void main(String[] args) throws Exception {
30         CountDownLatch finalizerWait = new CountDownLatch(1);
31 
32         // A separate method to ensure no dex register keeps the object alive.
33         createBadCleanable(finalizerWait);
34 
35         // Should have at least two iterations to trigger finalization, but just to make sure run
36         // some more.
37         for (int i = 0; i < 5; i++) {
38             Runtime.getRuntime().gc();
39         }
40 
41         // Now wait for the finalizer to start running. Give it a minute.
42         finalizerWait.await(1, MINUTES);
43 
44         // Now fall asleep with a timeout. The timeout is large enough that we expect the
45         // finalizer daemon to have killed the process before the deadline elapses.
46         // The timeout is also large enough to cover the extra 5 seconds we wait
47         // to dump threads, plus potentially substantial gcstress overhead.
48         // The RQ timeout is currently effectively 5 * the finalizer timeout.
49         // Note: the timeout is here (instead of an infinite sleep) to protect the test
50         //       environment (e.g., in case this is run without a timeout wrapper).
51         final long timeout = 100 * 1000 + 5 * VMRuntime.getRuntime().getFinalizerTimeoutMs();
52         long remainingWait = timeout;
53         final long waitStart = System.currentTimeMillis();
54         while (remainingWait > 0) {
55             synchronized (args) {  // Just use an already existing object for simplicity...
56                 try {
57                     args.wait(remainingWait);
58                 } catch (Exception e) {
59                     System.out.println("UNEXPECTED EXCEPTION");
60                 }
61             }
62             remainingWait = timeout - (System.currentTimeMillis() - waitStart);
63         }
64 
65         // We should not get here.
66         System.out.println("UNREACHABLE");
67         System.exit(0);
68     }
69 
createBadCleanable(CountDownLatch finalizerWait)70     private static void createBadCleanable(CountDownLatch finalizerWait) {
71         Object badCleanable = new Object();
72         Runnable badRunnable = new Runnable() {
73             public void run () {
74                 finalizerWait.countDown();
75 
76                 System.out.println("Cleaner started and sleeping briefly...");
77 
78                 snooze(2000);
79                 System.out.println("Cleaner done snoozing.");
80 
81                 System.out.println("Cleaner sleeping forever now.");
82                 while (true) {
83                     snooze(500000);
84                 }
85             }
86         };
87         final Cleaner badCleaner = Cleaner.create(badCleanable, badRunnable);
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 
snooze(int ms)93     public static void snooze(int ms) {
94         try {
95             Thread.sleep(ms);
96         } catch (InterruptedException ie) {
97         }
98     }
99 
100 }
101