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;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 import android.system.Os;
21 import android.system.OsConstants;
22 
23 import java.lang.ref.FinalizerReference;
24 import java.lang.ref.Reference;
25 import java.lang.ref.ReferenceQueue;
26 import java.util.concurrent.CountDownLatch;
27 import java.util.concurrent.TimeoutException;
28 import java.util.concurrent.atomic.AtomicInteger;
29 import libcore.util.EmptyArray;
30 
31 import dalvik.system.VMRuntime;
32 import dalvik.system.VMDebug;
33 
34 /**
35  * Calls Object.finalize() on objects in the finalizer reference queue. The VM
36  * will abort if any finalize() call takes more than the maximum finalize time
37  * to complete.
38  *
39  * @hide
40  */
41 public final class Daemons {
42     private static final int NANOS_PER_MILLI = 1000 * 1000;
43 
44     // This used to be final. IT IS NOW ONLY WRITTEN. We now update it when we look at the command
45     // line argument, for the benefit of mis-behaved apps that might read it.  SLATED FOR REMOVAL.
46     // There is no reason to use this: Finalizers should not rely on the value. If a finalizer takes
47     // appreciable time, the work should be done elsewhere.  Based on disassembly of Daemons.class,
48     // the value is effectively inlined, so changing the field never did have an effect.
49     // DO NOT USE. FOR ANYTHING. THIS WILL BE REMOVED SHORTLY.
50     @UnsupportedAppUsage
51     private static long MAX_FINALIZE_NANOS = 10L * 1000 * NANOS_PER_MILLI;
52 
53     private static final Daemon[] DAEMONS = new Daemon[] {
54             HeapTaskDaemon.INSTANCE,
55             ReferenceQueueDaemon.INSTANCE,
56             FinalizerDaemon.INSTANCE,
57             FinalizerWatchdogDaemon.INSTANCE,
58     };
59     private static final CountDownLatch POST_ZYGOTE_START_LATCH = new CountDownLatch(DAEMONS.length);
60     private static final CountDownLatch PRE_ZYGOTE_START_LATCH = new CountDownLatch(DAEMONS.length);
61 
62     private static boolean postZygoteFork = false;
63 
64     @UnsupportedAppUsage
start()65     public static void start() {
66         for (Daemon daemon : DAEMONS) {
67             daemon.start();
68         }
69     }
70 
startPostZygoteFork()71     public static void startPostZygoteFork() {
72         postZygoteFork = true;
73         for (Daemon daemon : DAEMONS) {
74             daemon.startPostZygoteFork();
75         }
76     }
77 
78     @UnsupportedAppUsage
stop()79     public static void stop() {
80         for (Daemon daemon : DAEMONS) {
81             daemon.stop();
82         }
83     }
84 
waitForDaemonStart()85     private static void waitForDaemonStart() throws Exception {
86         if (postZygoteFork) {
87             POST_ZYGOTE_START_LATCH.await();
88         } else {
89             PRE_ZYGOTE_START_LATCH.await();
90         }
91     }
92 
93     /**
94      * A background task that provides runtime support to the application.
95      * Daemons can be stopped and started, but only so that the zygote can be a
96      * single-threaded process when it forks.
97      */
98     private static abstract class Daemon implements Runnable {
99         @UnsupportedAppUsage
100         private Thread thread;
101         private String name;
102         private boolean postZygoteFork;
103 
Daemon(String name)104         protected Daemon(String name) {
105             this.name = name;
106         }
107 
108         @UnsupportedAppUsage
start()109         public synchronized void start() {
110             startInternal();
111         }
112 
startPostZygoteFork()113         public synchronized void startPostZygoteFork() {
114             postZygoteFork = true;
115             startInternal();
116         }
117 
startInternal()118         public void startInternal() {
119             if (thread != null) {
120                 throw new IllegalStateException("already running");
121             }
122             thread = new Thread(ThreadGroup.systemThreadGroup, this, name);
123             thread.setDaemon(true);
124             thread.setSystemDaemon(true);
125             thread.start();
126         }
127 
run()128         public final void run() {
129             if (postZygoteFork) {
130                 // We don't set the priority before the Thread.start() call above because
131                 // Thread.start() will call SetNativePriority and overwrite the desired native
132                 // priority. We (may) use a native priority that doesn't have a corresponding
133                 // java.lang.Thread-level priority (native priorities are more coarse-grained.)
134                 VMRuntime.getRuntime().setSystemDaemonThreadPriority();
135                 POST_ZYGOTE_START_LATCH.countDown();
136             } else {
137                 PRE_ZYGOTE_START_LATCH.countDown();
138             }
139             runInternal();
140         }
141 
runInternal()142         public abstract void runInternal();
143 
144         /**
145          * Returns true while the current thread should continue to run; false
146          * when it should return.
147          */
148         @UnsupportedAppUsage
isRunning()149         protected synchronized boolean isRunning() {
150             return thread != null;
151         }
152 
interrupt()153         public synchronized void interrupt() {
154             interrupt(thread);
155         }
156 
interrupt(Thread thread)157         public synchronized void interrupt(Thread thread) {
158             if (thread == null) {
159                 throw new IllegalStateException("not running");
160             }
161             thread.interrupt();
162         }
163 
164         /**
165          * Waits for the runtime thread to stop. This interrupts the thread
166          * currently running the runnable and then waits for it to exit.
167          */
168         @UnsupportedAppUsage
stop()169         public void stop() {
170             Thread threadToStop;
171             synchronized (this) {
172                 threadToStop = thread;
173                 thread = null;
174             }
175             if (threadToStop == null) {
176                 throw new IllegalStateException("not running");
177             }
178             interrupt(threadToStop);
179             while (true) {
180                 try {
181                     threadToStop.join();
182                     return;
183                 } catch (InterruptedException ignored) {
184                 } catch (OutOfMemoryError ignored) {
185                     // An OOME may be thrown if allocating the InterruptedException failed.
186                 }
187             }
188         }
189 
190         /**
191          * Returns the current stack trace of the thread, or an empty stack trace
192          * if the thread is not currently running.
193          */
getStackTrace()194         public synchronized StackTraceElement[] getStackTrace() {
195             return thread != null ? thread.getStackTrace() : EmptyArray.STACK_TRACE_ELEMENT;
196         }
197     }
198 
199     /**
200      * This heap management thread moves elements from the garbage collector's
201      * pending list to the managed reference queue.
202      */
203     private static class ReferenceQueueDaemon extends Daemon {
204         @UnsupportedAppUsage
205         private static final ReferenceQueueDaemon INSTANCE = new ReferenceQueueDaemon();
206 
ReferenceQueueDaemon()207         ReferenceQueueDaemon() {
208             super("ReferenceQueueDaemon");
209         }
210 
runInternal()211         @Override public void runInternal() {
212             while (isRunning()) {
213                 Reference<?> list;
214                 try {
215                     synchronized (ReferenceQueue.class) {
216                         while (ReferenceQueue.unenqueued == null) {
217                             ReferenceQueue.class.wait();
218                         }
219                         list = ReferenceQueue.unenqueued;
220                         ReferenceQueue.unenqueued = null;
221                     }
222                 } catch (InterruptedException e) {
223                     continue;
224                 } catch (OutOfMemoryError e) {
225                     continue;
226                 }
227                 ReferenceQueue.enqueuePending(list);
228             }
229         }
230     }
231 
232     private static class FinalizerDaemon extends Daemon {
233         @UnsupportedAppUsage
234         private static final FinalizerDaemon INSTANCE = new FinalizerDaemon();
235         private final ReferenceQueue<Object> queue = FinalizerReference.queue;
236         private final AtomicInteger progressCounter = new AtomicInteger(0);
237         // Object (not reference!) being finalized. Accesses may race!
238         @UnsupportedAppUsage
239         private Object finalizingObject = null;
240 
FinalizerDaemon()241         FinalizerDaemon() {
242             super("FinalizerDaemon");
243         }
244 
runInternal()245         @Override public void runInternal() {
246             // This loop may be performance critical, since we need to keep up with mutator
247             // generation of finalizable objects.
248             // We minimize the amount of work we do per finalizable object. For example, we avoid
249             // reading the current time here, since that involves a kernel call per object.  We
250             // limit fast path communication with FinalizerWatchDogDaemon to what's unavoidable: A
251             // non-volatile store to communicate the current finalizable object, e.g. for
252             // reporting, and a release store (lazySet) to a counter.
253             // We do stop the  FinalizerWatchDogDaemon if we have nothing to do for a
254             // potentially extended period.  This prevents the device from waking up regularly
255             // during idle times.
256 
257             // Local copy of progressCounter; saves a fence per increment on ARM and MIPS.
258             int localProgressCounter = progressCounter.get();
259 
260             while (isRunning()) {
261                 try {
262                     // Use non-blocking poll to avoid FinalizerWatchdogDaemon communication
263                     // when busy.
264                     FinalizerReference<?> finalizingReference = (FinalizerReference<?>)queue.poll();
265                     if (finalizingReference != null) {
266                         finalizingObject = finalizingReference.get();
267                         progressCounter.lazySet(++localProgressCounter);
268                     } else {
269                         finalizingObject = null;
270                         progressCounter.lazySet(++localProgressCounter);
271                         // Slow path; block.
272                         FinalizerWatchdogDaemon.INSTANCE.goToSleep();
273                         finalizingReference = (FinalizerReference<?>)queue.remove();
274                         finalizingObject = finalizingReference.get();
275                         progressCounter.set(++localProgressCounter);
276                         FinalizerWatchdogDaemon.INSTANCE.wakeUp();
277                     }
278                     doFinalize(finalizingReference);
279                 } catch (InterruptedException ignored) {
280                 } catch (OutOfMemoryError ignored) {
281                 }
282             }
283         }
284 
285         @FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION")
doFinalize(FinalizerReference<?> reference)286         private void doFinalize(FinalizerReference<?> reference) {
287             FinalizerReference.remove(reference);
288             Object object = reference.get();
289             reference.clear();
290             try {
291                 object.finalize();
292             } catch (Throwable ex) {
293                 // The RI silently swallows these, but Android has always logged.
294                 System.logE("Uncaught exception thrown by finalizer", ex);
295             } finally {
296                 // Done finalizing, stop holding the object as live.
297                 finalizingObject = null;
298             }
299         }
300     }
301 
302     /**
303      * The watchdog exits the VM if the finalizer ever gets stuck. We consider
304      * the finalizer to be stuck if it spends more than MAX_FINALIZATION_MILLIS
305      * on one instance.
306      */
307     private static class FinalizerWatchdogDaemon extends Daemon {
308         @UnsupportedAppUsage
309         private static final FinalizerWatchdogDaemon INSTANCE = new FinalizerWatchdogDaemon();
310 
311         private boolean needToWork = true;  // Only accessed in synchronized methods.
312 
313         private long finalizerTimeoutNs = 0;  // Lazily initialized.
314 
FinalizerWatchdogDaemon()315         FinalizerWatchdogDaemon() {
316             super("FinalizerWatchdogDaemon");
317         }
318 
runInternal()319         @Override public void runInternal() {
320             while (isRunning()) {
321                 if (!sleepUntilNeeded()) {
322                     // We have been interrupted, need to see if this daemon has been stopped.
323                     continue;
324                 }
325                 final Object finalizing = waitForFinalization();
326                 if (finalizing != null && !VMDebug.isDebuggerConnected()) {
327                     finalizerTimedOut(finalizing);
328                     break;
329                 }
330             }
331         }
332 
333         /**
334          * Wait until something is ready to be finalized.
335          * Return false if we have been interrupted
336          * See also http://code.google.com/p/android/issues/detail?id=22778.
337          */
sleepUntilNeeded()338         private synchronized boolean sleepUntilNeeded() {
339             while (!needToWork) {
340                 try {
341                     wait();
342                 } catch (InterruptedException e) {
343                     // Daemon.stop may have interrupted us.
344                     return false;
345                 } catch (OutOfMemoryError e) {
346                     return false;
347                 }
348             }
349             return true;
350         }
351 
352         /**
353          * Notify daemon that it's OK to sleep until notified that something is ready to be
354          * finalized.
355          */
goToSleep()356         private synchronized void goToSleep() {
357             needToWork = false;
358         }
359 
360         /**
361          * Notify daemon that there is something ready to be finalized.
362          */
wakeUp()363         private synchronized void wakeUp() {
364             needToWork = true;
365             notify();
366         }
367 
getNeedToWork()368         private synchronized boolean getNeedToWork() {
369             return needToWork;
370         }
371 
372         /**
373          * Sleep for the given number of nanoseconds, or slightly longer.
374          * @return false if we were interrupted.
375          */
sleepForNanos(long durationNanos)376         private boolean sleepForNanos(long durationNanos) {
377             // It's important to base this on nanoTime(), not currentTimeMillis(), since
378             // the former stops counting when the processor isn't running.
379             long startNanos = System.nanoTime();
380             while (true) {
381                 long elapsedNanos = System.nanoTime() - startNanos;
382                 long sleepNanos = durationNanos - elapsedNanos;
383                 if (sleepNanos <= 0) {
384                     return true;
385                 }
386                 // Ensure the nano time is always rounded up to the next whole millisecond,
387                 // ensuring the delay is >= the requested delay.
388                 long sleepMillis = (sleepNanos + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
389                 try {
390                     Thread.sleep(sleepMillis);
391                 } catch (InterruptedException e) {
392                     if (!isRunning()) {
393                         return false;
394                     }
395                 } catch (OutOfMemoryError ignored) {
396                     if (!isRunning()) {
397                         return false;
398                     }
399                 }
400             }
401         }
402 
403 
404         /**
405          * Return an object that took too long to finalize or return null.
406          * Wait VMRuntime.getFinalizerTimeoutMs.  If the FinalizerDaemon took essentially the
407          * whole time processing a single reference, return that reference.  Otherwise return
408          * null.  Only called from a single thread.
409          */
waitForFinalization()410         private Object waitForFinalization() {
411             if (finalizerTimeoutNs == 0) {
412                 finalizerTimeoutNs =
413                         NANOS_PER_MILLI * VMRuntime.getRuntime().getFinalizerTimeoutMs();
414                 // Temporary app backward compatibility. Remove eventually.
415                 MAX_FINALIZE_NANOS = finalizerTimeoutNs;
416             }
417             long startCount = FinalizerDaemon.INSTANCE.progressCounter.get();
418             // Avoid remembering object being finalized, so as not to keep it alive.
419             if (!sleepForNanos(finalizerTimeoutNs)) {
420                 // Don't report possibly spurious timeout if we are interrupted.
421                 return null;
422             }
423             if (getNeedToWork() && FinalizerDaemon.INSTANCE.progressCounter.get() == startCount) {
424                 // We assume that only remove() and doFinalize() may take time comparable to
425                 // the finalizer timeout.
426                 // We observed neither the effect of the gotoSleep() nor the increment preceding a
427                 // later wakeUp. Any remove() call by the FinalizerDaemon during our sleep
428                 // interval must have been followed by a wakeUp call before we checked needToWork.
429                 // But then we would have seen the counter increment.  Thus there cannot have
430                 // been such a remove() call.
431                 // The FinalizerDaemon must not have progressed (from either the beginning or the
432                 // last progressCounter increment) to either the next increment or gotoSleep()
433                 // call.  Thus we must have taken essentially the whole finalizerTimeoutMs in a
434                 // single doFinalize() call.  Thus it's OK to time out.  finalizingObject was set
435                 // just before the counter increment, which preceded the doFinalize call.  Thus we
436                 // are guaranteed to get the correct finalizing value below, unless doFinalize()
437                 // just finished as we were timing out, in which case we may get null or a later
438                 // one.  In this last case, we are very likely to discard it below.
439                 Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject;
440                 sleepForNanos(500 * NANOS_PER_MILLI);
441                 // Recheck to make it even less likely we report the wrong finalizing object in
442                 // the case which a very slow finalization just finished as we were timing out.
443                 if (getNeedToWork()
444                         && FinalizerDaemon.INSTANCE.progressCounter.get() == startCount) {
445                     return finalizing;
446                 }
447             }
448             return null;
449         }
450 
finalizerTimedOut(Object object)451         private static void finalizerTimedOut(Object object) {
452             // The current object has exceeded the finalization deadline; abort!
453             String message = object.getClass().getName() + ".finalize() timed out after "
454                     + VMRuntime.getRuntime().getFinalizerTimeoutMs() / 1000 + " seconds";
455             Exception syntheticException = new TimeoutException(message);
456             // We use the stack from where finalize() was running to show where it was stuck.
457             syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
458 
459             // Send SIGQUIT to get native stack traces.
460             try {
461                 Os.kill(Os.getpid(), OsConstants.SIGQUIT);
462                 // Sleep a few seconds to let the stack traces print.
463                 Thread.sleep(5000);
464             } catch (Exception e) {
465                 System.logE("failed to send SIGQUIT", e);
466             } catch (OutOfMemoryError ignored) {
467                 // May occur while trying to allocate the exception.
468             }
469 
470             // Ideally, we'd want to do this if this Thread had no handler to dispatch to.
471             // Unfortunately, it's extremely to messy to query whether a given Thread has *some*
472             // handler to dispatch to, either via a handler set on itself, via its ThreadGroup
473             // object or via the defaultUncaughtExceptionHandler.
474             //
475             // As an approximation, we log by hand an exit if there's no pre-exception handler nor
476             // a default uncaught exception handler.
477             //
478             // Note that this condition will only ever be hit by ART host tests and standalone
479             // dalvikvm invocations. All zygote forked process *will* have a pre-handler set
480             // in RuntimeInit and they cannot subsequently override it.
481             if (Thread.getUncaughtExceptionPreHandler() == null &&
482                     Thread.getDefaultUncaughtExceptionHandler() == null) {
483                 // If we have no handler, log and exit.
484                 System.logE(message, syntheticException);
485                 System.exit(2);
486             }
487 
488             // Otherwise call the handler to do crash reporting.
489             // We don't just throw because we're not the thread that
490             // timed out; we're the thread that detected it.
491             Thread.currentThread().dispatchUncaughtException(syntheticException);
492         }
493     }
494 
495     // Adds a heap trim task to the heap event processor, not called from java. Left for
496     // compatibility purposes due to reflection.
497     @UnsupportedAppUsage
requestHeapTrim()498     public static void requestHeapTrim() {
499         VMRuntime.getRuntime().requestHeapTrim();
500     }
501 
502     // Adds a concurrent GC request task ot the heap event processor, not called from java. Left
503     // for compatibility purposes due to reflection.
requestGC()504     public static void requestGC() {
505         VMRuntime.getRuntime().requestConcurrentGC();
506     }
507 
508     private static class HeapTaskDaemon extends Daemon {
509         private static final HeapTaskDaemon INSTANCE = new HeapTaskDaemon();
510 
HeapTaskDaemon()511         HeapTaskDaemon() {
512             super("HeapTaskDaemon");
513         }
514 
515         // Overrides the Daemon.interupt method which is called from Daemons.stop.
interrupt(Thread thread)516         public synchronized void interrupt(Thread thread) {
517             VMRuntime.getRuntime().stopHeapTaskProcessor();
518         }
519 
runInternal()520         @Override public void runInternal() {
521             synchronized (this) {
522                 if (isRunning()) {
523                   // Needs to be synchronized or else we there is a race condition where we start
524                   // the thread, call stopHeapTaskProcessor before we start the heap task
525                   // processor, resulting in a deadlock since startHeapTaskProcessor restarts it
526                   // while the other thread is waiting in Daemons.stop().
527                   VMRuntime.getRuntime().startHeapTaskProcessor();
528                 }
529             }
530             // This runs tasks until we are stopped and there is no more pending task.
531             VMRuntime.getRuntime().runHeapTasks();
532         }
533     }
534 }
535