16a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson/*
26a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * Copyright (C) 2011 Google Inc.
36a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson *
46a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
56a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * you may not use this file except in compliance with the License.
66a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * You may obtain a copy of the License at
76a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson *
86a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * http://www.apache.org/licenses/LICENSE-2.0
96a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson *
106a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * Unless required by applicable law or agreed to in writing, software
116a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
126a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * See the License for the specific language governing permissions and
146a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson * limitations under the License.
156a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson */
166a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
176a22fa91a64739523c1344023f6dfde57e53110eJesse Wilsonpackage libcore.java.lang.ref;
186a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
1964c6c367497c7fcf88e7527022234043e4460758Jesse Wilsonimport java.util.concurrent.CountDownLatch;
206a22fa91a64739523c1344023f6dfde57e53110eJesse Wilsonimport java.util.concurrent.atomic.AtomicBoolean;
219429d06c5427a6cac499ba90f138afac006135a2Jesse Wilsonimport java.util.concurrent.atomic.AtomicInteger;
226a22fa91a64739523c1344023f6dfde57e53110eJesse Wilsonimport junit.framework.TestCase;
236a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
246a22fa91a64739523c1344023f6dfde57e53110eJesse Wilsonpublic final class FinalizeTest extends TestCase {
256a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
266a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    public void testFinalizeIsCalled() throws Exception {
276a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        AtomicBoolean finalized = new AtomicBoolean();
286a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        createFinalizableObject(finalized);
296a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
301a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson        FinalizationTester.induceFinalization();
316a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        if (!finalized.get()) {
323edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson            fail("object not yet finalized");
333edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        }
343edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson    }
353edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson
363edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson    /**
373edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson     * Test verifies that runFinalization() does not mess up objects
383edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson     * that should be finalized later on. http://b/6907299
393edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson     */
403edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson    public void testInducedFinalization() throws Exception {
413edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        AtomicBoolean finalized1 = new AtomicBoolean();
423edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        AtomicBoolean finalized2 = new AtomicBoolean();
433edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        createFinalizableObject(finalized1);
443edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        createFinalizableObject(finalized2);
453edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        FinalizationTester.induceFinalization();
463edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        if (!finalized1.get() || !finalized2.get()) {
473edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson            fail("not yet finalized: " + finalized1.get() + " " + finalized2.get());
486a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        }
496a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    }
506a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
511a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson    /** Do not inline this method; that could break non-precise GCs. See FinalizationTester. */
523edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson    private X createFinalizableObject(final AtomicBoolean finalized) {
533edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        X result = new X() {
546a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson            @Override protected void finalize() throws Throwable {
556a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson                super.finalize();
566a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson                finalized.set(true);
576a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson            }
586a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        };
593edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        FinalizationTester.induceFinalization();
603edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        // Dance around a bit to discourage dx from realizing that 'result' is no longer live.
613edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        boolean wasFinalized = finalized.get();
623edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        if (wasFinalized) {
633edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson            fail("finalizer called early"); // ...because 'result' is still live until we return.
643edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        }
653edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        // But we don't actually want to return 'result' because then we'd have to worry about
663edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        // the caller accidentally keeping it live.
673edd28a92fc86a1260347d0995e65a815d73bbbeMattias Petersson        return wasFinalized ? result : null;
686a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    }
696a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
706a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    static class X {}
716a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
72cf3d432790a78b7d81da656f9a666f3d1ce4962cMathieu Chartier    // Helper function since we do not want a vreg to keep the allocated object live.
73cf3d432790a78b7d81da656f9a666f3d1ce4962cMathieu Chartier    // For b/25851249
74cf3d432790a78b7d81da656f9a666f3d1ce4962cMathieu Chartier    private void exceptionInConstructor() {
75d4b7449574ca69c713a3f2230cb77c68ee642700Tobias Thierer        boolean thrown = false;
766a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        try {
776a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson            new ConstructionFails();
78d4b7449574ca69c713a3f2230cb77c68ee642700Tobias Thierer            // can't fail() here since AssertionFailedError extends AssertionError, which
79d4b7449574ca69c713a3f2230cb77c68ee642700Tobias Thierer            // we expect
806a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        } catch (AssertionError expected) {
81d4b7449574ca69c713a3f2230cb77c68ee642700Tobias Thierer            thrown = true;
82d4b7449574ca69c713a3f2230cb77c68ee642700Tobias Thierer        }
83d4b7449574ca69c713a3f2230cb77c68ee642700Tobias Thierer        if (!thrown) {
84d4b7449574ca69c713a3f2230cb77c68ee642700Tobias Thierer            fail();
856a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        }
86cf3d432790a78b7d81da656f9a666f3d1ce4962cMathieu Chartier    }
876a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
88cf3d432790a78b7d81da656f9a666f3d1ce4962cMathieu Chartier    // http://b/issue?id=2136462
89cf3d432790a78b7d81da656f9a666f3d1ce4962cMathieu Chartier    public void testBackFromTheDead() throws Exception {
90cf3d432790a78b7d81da656f9a666f3d1ce4962cMathieu Chartier        exceptionInConstructor();
911a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson        FinalizationTester.induceFinalization();
9229e0638aca737dd1093dac55216982b5af7d59a7Jesse Wilson        assertTrue("object whose constructor threw was not finalized", ConstructionFails.finalized);
936a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    }
946a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
956a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    static class ConstructionFails {
9629e0638aca737dd1093dac55216982b5af7d59a7Jesse Wilson        private static boolean finalized;
976a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
986a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        ConstructionFails() {
996a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson            throw new AssertionError();
1006a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        }
1016a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
1026a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        @Override protected void finalize() throws Throwable {
10329e0638aca737dd1093dac55216982b5af7d59a7Jesse Wilson            finalized = true;
1046a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        }
1056a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    }
10664c6c367497c7fcf88e7527022234043e4460758Jesse Wilson
10764c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    /**
10864c6c367497c7fcf88e7527022234043e4460758Jesse Wilson     * The finalizer watch dog exits the VM if any object takes more than 10 s
10964c6c367497c7fcf88e7527022234043e4460758Jesse Wilson     * to finalize. Check that objects near that limit are okay.
11064c6c367497c7fcf88e7527022234043e4460758Jesse Wilson     */
11164c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    public void testWatchdogDoesNotFailForObjectsThatAreNearTheDeadline() throws Exception {
1125e5169a394fd431609c3419bb4052e71dc73fed3Tobias Thierer        CountDownLatch latch = new CountDownLatch(3);
11364c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        createSlowFinalizer(   1, latch);
11464c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        createSlowFinalizer(1000, latch);
11564c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        createSlowFinalizer(8000, latch);
1161a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson        FinalizationTester.induceFinalization();
11764c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        latch.await();
11864c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    }
11964c6c367497c7fcf88e7527022234043e4460758Jesse Wilson
12064c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    public void createSlowFinalizer(final long millis, final CountDownLatch latch) {
12164c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        new Object() {
12264c6c367497c7fcf88e7527022234043e4460758Jesse Wilson            @Override protected void finalize() throws Throwable {
12364c6c367497c7fcf88e7527022234043e4460758Jesse Wilson                System.out.println("finalize sleeping " + millis + " ms");
12464c6c367497c7fcf88e7527022234043e4460758Jesse Wilson                Thread.sleep(millis);
12564c6c367497c7fcf88e7527022234043e4460758Jesse Wilson                latch.countDown();
12664c6c367497c7fcf88e7527022234043e4460758Jesse Wilson            }
12764c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        };
12864c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    }
1299429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson
1309429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    /**
1319429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson     * Make sure that System.runFinalization() returns even if the finalization
1329429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson     * queue is never completely empty. http://b/4193517
1339429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson     */
1349429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    public void testSystemRunFinalizationReturnsEvenIfQueueIsNonEmpty() throws Exception {
1359429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        AtomicInteger count = new AtomicInteger();
1369429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        AtomicBoolean keepGoing = new AtomicBoolean(true);
1379429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        createChainedFinalizer(count, keepGoing);
1381a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson        FinalizationTester.induceFinalization();
1399429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        keepGoing.set(false);
1409429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        assertTrue(count.get() > 0);
1419429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    }
1429429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson
1439429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    public void createChainedFinalizer(final AtomicInteger counter, final AtomicBoolean keepGoing) {
1449429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        new Object() {
1459429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson            @Override protected void finalize() throws Throwable {
1469429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                int count = counter.incrementAndGet();
1479429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                System.out.println(count);
1489429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                if (keepGoing.get()) {
1499429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                    createChainedFinalizer(counter, keepGoing); // recursive!
1509429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                }
1519429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                System.gc();
1521a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson                FinalizationTester.enqueueReferences();
1539429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson            }
1549429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        };
1559429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    }
1566a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson}
157