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 static java.util.concurrent.TimeUnit.MINUTES;
20 
21 /**
22  * Test a class with a bad finalizer.
23  *
24  * This test is inherently very slightly flaky. It assumes that the system will schedule the
25  * finalizer daemon and finalizer watchdog daemon soon and often enough to reach the timeout and
26  * throw the fatal exception before we time out. Since we build in a 100 second buffer, failures
27  * should be very rare.
28  */
29 public class Main {
main(String[] args)30     public static void main(String[] args) throws Exception {
31         CountDownLatch finalizerWait = new CountDownLatch(1);
32 
33         // A separate method to ensure no dex register keeps the object alive.
34         createBadFinalizer(finalizerWait);
35 
36         // Should have at least two iterations to trigger finalization, but just to make sure run
37         // some more.
38         for (int i = 0; i < 5; i++) {
39             Runtime.getRuntime().gc();
40         }
41 
42         // Now wait for the finalizer to start running. Give it a minute.
43         finalizerWait.await(1, MINUTES);
44 
45         // Now fall asleep with a timeout. The timeout is large enough that we expect the
46         // finalizer daemon to have killed the process before the deadline elapses.
47         // The timeout is also large enough to cover the extra 5 seconds we wait
48         // to dump threads, plus potentially substantial gcstress overhead.
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 + 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 
createBadFinalizer(CountDownLatch finalizerWait)70     private static void createBadFinalizer(CountDownLatch finalizerWait) {
71         BadFinalizer bf = new BadFinalizer(finalizerWait);
72 
73         System.out.println("About to null reference.");
74         bf = null;  // Not that this would make a difference, could be eliminated earlier.
75     }
76 
snooze(int ms)77     public static void snooze(int ms) {
78         try {
79             Thread.sleep(ms);
80         } catch (InterruptedException ie) {
81             System.out.println("Unexpected interrupt");
82         }
83     }
84 
85     /**
86      * Class with a bad finalizer.
87      */
88     public static class BadFinalizer {
89         private CountDownLatch finalizerWait;
90         private volatile int j = 0;  // Volatile in an effort to curb loop optimization.
91 
BadFinalizer(CountDownLatch finalizerWait)92         public BadFinalizer(CountDownLatch finalizerWait) {
93             this.finalizerWait = finalizerWait;
94         }
95 
finalize()96         protected void finalize() {
97             finalizerWait.countDown();
98 
99             System.out.println("Finalizer started and sleeping briefly...");
100 
101             long start, end;
102             start = System.nanoTime();
103             snooze(2000);
104             end = System.nanoTime();
105             System.out.println("Finalizer done snoozing.");
106 
107             System.out.println("Finalizer sleeping forever now.");
108             while (true) {
109                 snooze(10000);
110             }
111         }
112     }
113 }
114