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 java.util.concurrent.CountDownLatch; 18 import static java.util.concurrent.TimeUnit.MINUTES; 19 20 /** 21 * Test a class with a bad finalizer. 22 * 23 * This test is inherently flaky. It assumes that the system will schedule the finalizer daemon 24 * and finalizer watchdog daemon enough to reach the timeout and throwing the fatal exception. 25 */ 26 public class Main { 27 public static void main(String[] args) throws Exception { 28 CountDownLatch finalizerWait = new CountDownLatch(1); 29 30 // A separate method to ensure no dex register keeps the object alive. 31 createBadFinalizer(finalizerWait); 32 33 // Should have at least two iterations to trigger finalization, but just to make sure run 34 // some more. 35 for (int i = 0; i < 5; i++) { 36 Runtime.getRuntime().gc(); 37 } 38 39 // Now wait for the finalizer to start running. Give it a minute. 40 finalizerWait.await(1, MINUTES); 41 42 // Now fall asleep with a timeout. The timeout is large enough that we expect the 43 // finalizer daemon to have killed the process before the deadline elapses. 44 // Note: the timeout is here (instead of an infinite sleep) to protect the test 45 // environment (e.g., in case this is run without a timeout wrapper). 46 final long timeout = 60 * 1000; // 1 minute. 47 long remainingWait = timeout; 48 final long waitStart = System.currentTimeMillis(); 49 while (remainingWait > 0) { 50 synchronized (args) { // Just use an already existing object for simplicity... 51 try { 52 args.wait(remainingWait); 53 } catch (Exception e) { 54 } 55 } 56 remainingWait = timeout - (System.currentTimeMillis() - waitStart); 57 } 58 59 // We should not get here. 60 System.out.println("UNREACHABLE"); 61 System.exit(0); 62 } 63 64 private static void createBadFinalizer(CountDownLatch finalizerWait) { 65 BadFinalizer bf = new BadFinalizer(finalizerWait); 66 67 System.out.println("About to null reference."); 68 bf = null; // Not that this would make a difference, could be eliminated earlier. 69 } 70 71 public static void snooze(int ms) { 72 try { 73 Thread.sleep(ms); 74 } catch (InterruptedException ie) { 75 } 76 } 77 78 /** 79 * Class with a bad finalizer. 80 */ 81 public static class BadFinalizer { 82 private CountDownLatch finalizerWait; 83 private volatile int j = 0; // Volatile in an effort to curb loop optimization. 84 85 public BadFinalizer(CountDownLatch finalizerWait) { 86 this.finalizerWait = finalizerWait; 87 } 88 89 protected void finalize() { 90 finalizerWait.countDown(); 91 92 System.out.println("Finalizer started and spinning..."); 93 94 /* spin for a bit */ 95 long start, end; 96 start = System.nanoTime(); 97 snooze(2000); 98 end = System.nanoTime(); 99 System.out.println("Finalizer done spinning."); 100 101 System.out.println("Finalizer sleeping forever now."); 102 while (true) { 103 snooze(10000); 104 } 105 } 106 } 107 } 108