1 /*
2  * Copyright (C) 2011 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 package java.lang.ref;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import dalvik.annotation.optimization.FastNative;
21 
22 /**
23  * @hide
24  */
25 public final class FinalizerReference<T> extends Reference<T> {
26     // This queue contains those objects eligible for finalization.
27     @UnsupportedAppUsage
28     public static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
29 
30     // Guards the list (not the queue).
31     private static final Object LIST_LOCK = new Object();
32 
33     // This list contains a FinalizerReference for every finalizable object in the heap.
34     // Objects in this list may or may not be eligible for finalization yet.
35     @UnsupportedAppUsage
36     private static FinalizerReference<?> head = null;
37 
38     // The links used to construct the list.
39     private FinalizerReference<?> prev;
40     @UnsupportedAppUsage
41     private FinalizerReference<?> next;
42 
43     // When the GC wants something finalized, it moves it from the 'referent' field to
44     // the 'zombie' field instead.
45     private T zombie;
46 
FinalizerReference(T r, ReferenceQueue<? super T> q)47     public FinalizerReference(T r, ReferenceQueue<? super T> q) {
48         super(r, q);
49     }
50 
get()51     @Override public T get() {
52         return zombie;
53     }
54 
clear()55     @Override public void clear() {
56         zombie = null;
57     }
58 
59     @UnsupportedAppUsage
add(Object referent)60     public static void add(Object referent) {
61         FinalizerReference<?> reference = new FinalizerReference<Object>(referent, queue);
62         synchronized (LIST_LOCK) {
63             reference.prev = null;
64             reference.next = head;
65             if (head != null) {
66                 head.prev = reference;
67             }
68             head = reference;
69         }
70     }
71 
72     @UnsupportedAppUsage
remove(FinalizerReference<?> reference)73     public static void remove(FinalizerReference<?> reference) {
74         synchronized (LIST_LOCK) {
75             FinalizerReference<?> next = reference.next;
76             FinalizerReference<?> prev = reference.prev;
77             reference.next = null;
78             reference.prev = null;
79             if (prev != null) {
80                 prev.next = next;
81             } else {
82                 head = next;
83             }
84             if (next != null) {
85                 next.prev = prev;
86             }
87         }
88     }
89 
90     /**
91      * Waits for all currently-enqueued references to be finalized.
92      */
finalizeAllEnqueued(long timeout)93     public static void finalizeAllEnqueued(long timeout) throws InterruptedException {
94         // Alloate a new sentinel, this creates a FinalizerReference.
95         Sentinel sentinel;
96         // Keep looping until we safely enqueue our sentinel FinalizerReference.
97         // This is done to prevent races where the GC updates the pendingNext
98         // before we get the chance.
99         do {
100             sentinel = new Sentinel();
101         } while (!enqueueSentinelReference(sentinel));
102         sentinel.awaitFinalization(timeout);
103     }
104 
enqueueSentinelReference(Sentinel sentinel)105     private static boolean enqueueSentinelReference(Sentinel sentinel) {
106         synchronized (LIST_LOCK) {
107             // When a finalizable object is allocated, a FinalizerReference is added to the list.
108             // We search the list for that FinalizerReference (it should be at or near the head),
109             // and then put it on the queue so that it can be finalized.
110             for (FinalizerReference<?> r = head; r != null; r = r.next) {
111                 // Use getReferent() instead of directly accessing the referent field not to race
112                 // with GC reference processing. Can't use get() either because it's overridden to
113                 // return the zombie.
114                 if (r.getReferent() == sentinel) {
115                     FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r;
116                     sentinelReference.clearReferent();
117                     sentinelReference.zombie = sentinel;
118                     // Make a single element list, then enqueue the reference on the daemon unenqueued
119                     // list. This is required instead of enqueuing directly on the finalizer queue
120                     // since there could be recently freed objects in the unqueued list which are not
121                     // yet on the finalizer queue. This could cause the sentinel to run before the
122                     // objects are finalized. b/17381967
123                     // Make circular list if unenqueued goes through native so that we can prevent
124                     // races where the GC updates the pendingNext before we do. If it is non null, then
125                     // we update the pending next to make a circular list while holding a lock.
126                     // b/17462553
127                     if (!sentinelReference.makeCircularListIfUnenqueued()) {
128                         return false;
129                     }
130                     ReferenceQueue.add(sentinelReference);
131                     return true;
132                 }
133             }
134         }
135         // We just created a finalizable object and still hold a reference to it.
136         // It must be on the list.
137         throw new AssertionError("newly-created live Sentinel not on list!");
138     }
139 
140     @FastNative
getReferent()141     private final native T getReferent();
142     @FastNative
makeCircularListIfUnenqueued()143     private native boolean makeCircularListIfUnenqueued();
144 
145     /**
146      * A marker object that we can immediately enqueue. When this object's
147      * finalize() method is called, we know all previously-enqueued finalizable
148      * references have been finalized.
149      */
150     private static class Sentinel {
151         boolean finalized = false;
152 
finalize()153         @Override protected synchronized void finalize() throws Throwable {
154             if (finalized) {
155                 throw new AssertionError();
156             }
157             finalized = true;
158             notifyAll();
159         }
160 
awaitFinalization(long timeout)161         synchronized void awaitFinalization(long timeout) throws InterruptedException {
162             final long startTime = System.nanoTime();
163             final long endTime = startTime + timeout;  // May wrap.
164             while (!finalized) {
165                 // 0 signifies no timeout.
166                 if (timeout != 0) {
167                     final long deltaTime = endTime - System.nanoTime();
168                     if (deltaTime <= 0) {
169                         break;
170                     } else {
171                         wait(deltaTime / 1_000_000, (int)(deltaTime % 1_000_000));
172                     }
173                 } else {
174                     wait();
175                 }
176             }
177         }
178     }
179 }
180