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