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
7229e0638aca737dd1093dac55216982b5af7d59a7Jesse Wilson    // http://b/issue?id=2136462
736a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    public void testBackFromTheDead() throws Exception {
746a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        try {
756a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson            new ConstructionFails();
766a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        } catch (AssertionError expected) {
776a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        }
786a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
791a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson        FinalizationTester.induceFinalization();
8029e0638aca737dd1093dac55216982b5af7d59a7Jesse Wilson        assertTrue("object whose constructor threw was not finalized", ConstructionFails.finalized);
816a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    }
826a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
836a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    static class ConstructionFails {
8429e0638aca737dd1093dac55216982b5af7d59a7Jesse Wilson        private static boolean finalized;
856a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
866a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        ConstructionFails() {
876a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson            throw new AssertionError();
886a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        }
896a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson
906a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        @Override protected void finalize() throws Throwable {
9129e0638aca737dd1093dac55216982b5af7d59a7Jesse Wilson            finalized = true;
926a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson        }
936a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson    }
9464c6c367497c7fcf88e7527022234043e4460758Jesse Wilson
9564c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    /**
9664c6c367497c7fcf88e7527022234043e4460758Jesse Wilson     * The finalizer watch dog exits the VM if any object takes more than 10 s
9764c6c367497c7fcf88e7527022234043e4460758Jesse Wilson     * to finalize. Check that objects near that limit are okay.
9864c6c367497c7fcf88e7527022234043e4460758Jesse Wilson     */
9964c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    public void testWatchdogDoesNotFailForObjectsThatAreNearTheDeadline() throws Exception {
10064c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        CountDownLatch latch = new CountDownLatch(5);
10164c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        createSlowFinalizer(   1, latch);
10264c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        createSlowFinalizer(1000, latch);
10364c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        createSlowFinalizer(2000, latch);
10464c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        createSlowFinalizer(4000, latch);
10564c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        createSlowFinalizer(8000, latch);
1061a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson        FinalizationTester.induceFinalization();
10764c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        latch.await();
10864c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    }
10964c6c367497c7fcf88e7527022234043e4460758Jesse Wilson
11064c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    public void createSlowFinalizer(final long millis, final CountDownLatch latch) {
11164c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        new Object() {
11264c6c367497c7fcf88e7527022234043e4460758Jesse Wilson            @Override protected void finalize() throws Throwable {
11364c6c367497c7fcf88e7527022234043e4460758Jesse Wilson                System.out.println("finalize sleeping " + millis + " ms");
11464c6c367497c7fcf88e7527022234043e4460758Jesse Wilson                Thread.sleep(millis);
11564c6c367497c7fcf88e7527022234043e4460758Jesse Wilson                latch.countDown();
11664c6c367497c7fcf88e7527022234043e4460758Jesse Wilson            }
11764c6c367497c7fcf88e7527022234043e4460758Jesse Wilson        };
11864c6c367497c7fcf88e7527022234043e4460758Jesse Wilson    }
1199429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson
1209429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    /**
1219429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson     * Make sure that System.runFinalization() returns even if the finalization
1229429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson     * queue is never completely empty. http://b/4193517
1239429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson     */
1249429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    public void testSystemRunFinalizationReturnsEvenIfQueueIsNonEmpty() throws Exception {
1259429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        AtomicInteger count = new AtomicInteger();
1269429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        AtomicBoolean keepGoing = new AtomicBoolean(true);
1279429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        createChainedFinalizer(count, keepGoing);
1281a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson        FinalizationTester.induceFinalization();
1299429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        keepGoing.set(false);
1309429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        assertTrue(count.get() > 0);
1319429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    }
1329429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson
1339429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    public void createChainedFinalizer(final AtomicInteger counter, final AtomicBoolean keepGoing) {
1349429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        new Object() {
1359429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson            @Override protected void finalize() throws Throwable {
1369429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                int count = counter.incrementAndGet();
1379429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                System.out.println(count);
1389429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                if (keepGoing.get()) {
1399429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                    createChainedFinalizer(counter, keepGoing); // recursive!
1409429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                }
1419429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson                System.gc();
1421a9cff8f68deffd618c5cba1f22f0fb0e396e067Jesse Wilson                FinalizationTester.enqueueReferences();
1439429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson            }
1449429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson        };
1459429d06c5427a6cac499ba90f138afac006135a2Jesse Wilson    }
1466a22fa91a64739523c1344023f6dfde57e53110eJesse Wilson}
147