• 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.compat.annotation.UnsupportedAppUsage;
20 import android.system.Os;
21 import android.system.OsConstants;
22 
23 import java.lang.invoke.MethodHandles;
24 import java.lang.invoke.VarHandle;
25 import java.lang.ref.Cleaner;
26 import java.lang.ref.FinalizerReference;
27 import java.lang.ref.Reference;
28 import java.lang.ref.ReferenceQueue;
29 import java.util.concurrent.CountDownLatch;
30 import java.util.concurrent.TimeoutException;
31 import java.util.concurrent.atomic.AtomicInteger;
32 import libcore.util.EmptyArray;
33 import libcore.util.NativeAllocationRegistry;
34 
35 import dalvik.system.VMRuntime;
36 import dalvik.system.VMDebug;
37 
38 import jdk.internal.ref.CleanerImpl;
39 
40 /**
41  * Calls Object.finalize() on objects in the finalizer reference queue. The VM
42  * will abort if any finalize() call takes more than the maximum finalize time
43  * to complete.
44  *
45  * @hide
46  */
47 public final class Daemons {
48     private static final int NANOS_PER_MILLI = 1000 * 1000;
49 
50     // This used to be final. IT IS NOW ONLY WRITTEN. We now update it when we look at the command
51     // line argument, for the benefit of mis-behaved apps that might read it.  SLATED FOR REMOVAL.
52     // There is no reason to use this: Finalizers should not rely on the value. If a finalizer takes
53     // appreciable time, the work should be done elsewhere.  Based on disassembly of Daemons.class,
54     // the value is effectively inlined, so changing the field never did have an effect.
55     // DO NOT USE. FOR ANYTHING. THIS WILL BE REMOVED SHORTLY.
56     @UnsupportedAppUsage
57     private static long MAX_FINALIZE_NANOS = 10L * 1000 * NANOS_PER_MILLI;
58 
59     private static final Daemon[] DAEMONS = new Daemon[] {
60             HeapTaskDaemon.INSTANCE,
61             ReferenceQueueDaemon.INSTANCE,
62             FinalizerDaemon.INSTANCE,
63             FinalizerWatchdogDaemon.INSTANCE,
64     };
65     private static CountDownLatch zygoteStartLatch;
66 
67     private static boolean postZygoteFork = false;
68 
69     @UnsupportedAppUsage
start()70     public static void start() {
71         zygoteStartLatch = new CountDownLatch(DAEMONS.length);
72         for (Daemon daemon : DAEMONS) {
73             daemon.start();
74         }
75     }
76 
startPostZygoteFork()77     public static void startPostZygoteFork() {
78         postZygoteFork = true;
79         start();
80     }
81 
82     @UnsupportedAppUsage
stop()83     public static void stop() {
84         for (Daemon daemon : DAEMONS) {
85             daemon.stop();
86         }
87     }
88 
waitForDaemonStart()89     private static void waitForDaemonStart() throws Exception {
90         zygoteStartLatch.await();
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 
Daemon(String name)103         protected Daemon(String name) {
104             this.name = name;
105         }
106 
107         @UnsupportedAppUsage
start()108         public synchronized void start() {
109             startInternal();
110         }
111 
startInternal()112         public void startInternal() {
113             if (thread != null) {
114                 throw new IllegalStateException("already running");
115             }
116             thread = new Thread(ThreadGroup.systemThreadGroup, this, name);
117             thread.setDaemon(true);
118             thread.setSystemDaemon(true);
119             thread.start();
120         }
121 
run()122         public final void run() {
123             if (postZygoteFork) {
124                 // We don't set the priority before the Thread.start() call above because
125                 // Thread.start() will call SetNativePriority and overwrite the desired native
126                 // priority. We (may) use a native priority that doesn't have a corresponding
127                 // java.lang.Thread-level priority (native priorities are more coarse-grained.)
128                 VMRuntime.getRuntime().setSystemDaemonThreadPriority();
129             }
130             zygoteStartLatch.countDown();
131             try {
132                 runInternal();
133                 // This thread is about to exit, and we may have to wait for it to do so.
134                 // Terminate the underlying system thread as quickly as possible.
135                 // Mirroring setSystemDaemonThreadPriority, we only touch the native priority,
136                 // bypassing the rest of setPriority().
137                 Thread.currentThread().setPriority0(Thread.MAX_PRIORITY);
138             } catch (Throwable ex) {
139                 // Usually caught in runInternal. May not o.w. get reported, e.g. in zygote.
140                 // Risk logging redundantly, rather than losing it.
141                 System.logE("Uncaught exception in system thread " + name, ex);
142                 throw ex;
143             }
144         }
145 
146         /*
147          * Do the actual work. Returns normally when asked to stop.
148          */
runInternal()149         public abstract void runInternal();
150 
151         /**
152          * Returns true while the current thread should continue to run; false
153          * when it should return.
154          */
155         @UnsupportedAppUsage
isRunning()156         protected synchronized boolean isRunning() {
157             return thread != null;
158         }
159 
interrupt()160         public synchronized void interrupt() {
161             interrupt(thread);
162         }
163 
interrupt(Thread thread)164         public synchronized void interrupt(Thread thread) {
165             if (thread == null) {
166                 throw new IllegalStateException("not running");
167             }
168             thread.interrupt();
169         }
170 
171         /**
172          * Waits for the runtime thread to stop. This interrupts the thread
173          * currently running the runnable and then waits for it to exit.
174          */
175         @UnsupportedAppUsage
stop()176         public void stop() {
177             // This can be called on shutdown with the GC already disabled.
178             // Allocation either here or while handling the request in the
179             // daemon thread should be minimized.
180             Thread threadToStop;
181             synchronized (this) {
182                 threadToStop = thread;
183                 thread = null;
184             }
185             if (threadToStop == null) {
186                 throw new IllegalStateException("not running");
187             }
188             interrupt(threadToStop);
189             while (true) {
190                 try {
191                     threadToStop.join();
192                     return;
193                 } catch (InterruptedException ignored) {
194                 } catch (OutOfMemoryError ignored) {
195                     // An OOME may be thrown if allocating the InterruptedException failed.
196                 }
197             }
198         }
199 
200         /**
201          * Returns the current stack trace of the thread, or an empty stack trace
202          * if the thread is not currently running.
203          */
getStackTrace()204         public synchronized StackTraceElement[] getStackTrace() {
205             return thread != null ? thread.getStackTrace() : EmptyArray.STACK_TRACE_ELEMENT;
206         }
207     }
208 
209     // Allocate these strings on start-up.
210     // Don't declare them private, to minimize chances that the compiler can defer allocation.
211     /**
212      * @hide
213      */
214     public static final String FD_OOM_MESSAGE = "Ignoring unexpected OOME in FinalizerDaemon";
215     /**
216      * @hide
217      */
218     public static final String RQD_OOM_MESSAGE = "Ignoring unexpected OOME in ReferenceQueueDaemon";
219 
220     /**
221      * This heap management thread moves elements from the garbage collector's
222      * pending list to the managed reference queue.
223      */
224     private static class ReferenceQueueDaemon extends Daemon {
225         @UnsupportedAppUsage
226         private static final ReferenceQueueDaemon INSTANCE = new ReferenceQueueDaemon();
227 
228         // Monitored by FinalizerWatchdogDaemon to make sure we're still working.
229         private final AtomicInteger progressCounter = new AtomicInteger(0);
230 
ReferenceQueueDaemon()231         ReferenceQueueDaemon() {
232             super("ReferenceQueueDaemon");
233         }
234 
runInternal()235         @Override public void runInternal() {
236             FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded(FinalizerWatchdogDaemon.RQ_DAEMON);
237 
238             // Call once early to reduce later allocation, and hence chance of OOMEs.
239             FinalizerWatchdogDaemon.INSTANCE.resetTimeouts();
240 
241             long lastGcCount = VMRuntime.getFullGcCount();
242 
243             while (isRunning()) {
244                 Reference<?> list = null;
245                 boolean runPostCleanupCallbacks = false;
246                 try {
247                     synchronized (ReferenceQueue.class) {
248                         if (ReferenceQueue.unenqueued == null) {
249                             long gcCount = VMRuntime.getFullGcCount();
250                             if (gcCount > lastGcCount) {
251                                 lastGcCount = gcCount;
252                                 runPostCleanupCallbacks = true;
253                             } else {
254                                 FinalizerWatchdogDaemon.INSTANCE.monitoringNotNeeded(
255                                     FinalizerWatchdogDaemon.RQ_DAEMON);
256                                 // Increment after above call. If watchdog saw it active,
257                                 // it should see the counter update.
258                                 progressCounter.incrementAndGet();
259                                 do {
260                                    ReferenceQueue.class.wait();
261                                 } while (ReferenceQueue.unenqueued == null);
262                                 progressCounter.incrementAndGet();
263                                 FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded(
264                                     FinalizerWatchdogDaemon.RQ_DAEMON);
265                             }
266                         }
267                         if (!runPostCleanupCallbacks) {
268                             list = ReferenceQueue.unenqueued;
269                             ReferenceQueue.unenqueued = null;
270                         }
271                     }
272                     if (runPostCleanupCallbacks) {
273                         VMRuntime.onPostCleanup();
274                     }
275                     if (list != null) {
276                         ReferenceQueue.enqueuePending(list, progressCounter);
277                         FinalizerWatchdogDaemon.INSTANCE.resetTimeouts();
278                     }
279                 } catch (InterruptedException e) {
280                     // Happens when we are asked to stop.
281                 } catch (OutOfMemoryError ignored) {
282                     // Very unlikely. Cleaner.clean OOMEs are caught elsewhere, and nothing else
283                     // should allocate regularly. Could result in enqueuePending dropping
284                     // references. Does occur in tests that run out of memory.
285                     System.logW(RQD_OOM_MESSAGE);
286                 }
287             }
288         }
289 
currentlyProcessing()290         Object currentlyProcessing() {
291           return ReferenceQueue.getCurrentTarget();
292         }
293     }
294 
295     private static class FinalizerDaemon extends Daemon {
296         @UnsupportedAppUsage
297         private static final FinalizerDaemon INSTANCE = new FinalizerDaemon();
298         private final ReferenceQueue<Object> queue = FinalizerReference.queue;
299         private final AtomicInteger progressCounter = new AtomicInteger(0);
300         // Object (not reference!) being finalized. Accesses may race!
301         @UnsupportedAppUsage
302         private Object finalizingObject = null;
303 
304         // Track if we are currently logging an exception. We don't want to time out
305         // in the middle.
306         public static int NONE = 0;
307         public static int LOGGING = 1;
308         public static int TIMED_OUT = 2;
309         public volatile int exceptionLoggingState = NONE;
310 
FinalizerDaemon()311         FinalizerDaemon() {
312             super("FinalizerDaemon");
313         }
314 
runInternal()315         @Override public void runInternal() {
316             // This loop may be performance critical, since we need to keep up with mutator
317             // generation of finalizable objects.
318             // We minimize the amount of work we do per finalizable object. For example, we avoid
319             // reading the current time here, since that involves a kernel call per object.  We
320             // limit fast path communication with FinalizerWatchDogDaemon to what's unavoidable: A
321             // non-volatile store to communicate the current finalizable object, e.g. for
322             // reporting, and a release store (lazySet) to a counter.
323             // We do stop the  FinalizerWatchDogDaemon if we have nothing to do for a
324             // potentially extended period.  This prevents the device from waking up regularly
325             // during idle times.
326 
327             // Local copy of progressCounter; saves a fence per increment on ARM.
328             int localProgressCounter = progressCounter.get();
329 
330             FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded(
331                     FinalizerWatchdogDaemon.FINALIZER_DAEMON);
332             while (isRunning()) {
333                 try {
334                     // Use non-blocking poll to avoid FinalizerWatchdogDaemon communication
335                     // when busy.
336                     Object nextReference = queue.poll();
337                     if (nextReference != null) {
338                         progressCounter.lazySet(++localProgressCounter);
339                         processReference(nextReference);
340                     } else {
341                         finalizingObject = null;
342                         // Slow path; block.
343                         FinalizerWatchdogDaemon.INSTANCE.monitoringNotNeeded(
344                                 FinalizerWatchdogDaemon.FINALIZER_DAEMON);
345                         // Increment after above call. If watchdog saw it active, it should see
346                         // the counter update.
347                         progressCounter.set(++localProgressCounter);
348                         nextReference = queue.remove();
349                         progressCounter.set(++localProgressCounter);
350                         FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded(
351                                 FinalizerWatchdogDaemon.FINALIZER_DAEMON);
352                         processReference(nextReference);
353                     }
354                 } catch (InterruptedException e) {
355                     // Happens when we are asked to stop.
356                 } catch (OutOfMemoryError ignored) {
357                     // An  OOME here is unlikely to be actionable. Bravely/foolishly continue.
358                     System.logW(FD_OOM_MESSAGE);
359                 }
360             }
361         }
362 
processReference(Object ref)363         private void processReference(Object ref) {
364             if (ref instanceof FinalizerReference finalizingReference) {
365                 finalizingObject = finalizingReference.get();
366                 try {
367                     doFinalize(finalizingReference);
368                 } finally {
369                     // Make really sure we delay any PhantomReference enqueueing until we are
370                     // really done. Possibly redundant, but the rules are complex.
371                     Reference.reachabilityFence(finalizingObject);
372                 }
373             } else if (ref instanceof Cleaner.Cleanable cleanableReference) {
374                 finalizingObject = cleanableReference;
375                 doClean(cleanableReference);
376             } else {
377                 throw new AssertionError("Unknown class was placed into queue: " + ref);
378             }
379         }
380 
381         @FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION")
doFinalize(FinalizerReference<?> reference)382         private void doFinalize(FinalizerReference<?> reference) {
383             FinalizerReference.remove(reference);
384             Object object = reference.get();
385             reference.clear();
386             try {
387                 object.finalize();
388             } catch (Throwable ex) {
389                 // The RI silently swallows these, but Android has always logged.
390                 exceptionLoggingState = LOGGING;
391                 System.logE("Uncaught exception thrown by finalizer", ex);
392                 if (exceptionLoggingState == TIMED_OUT) {
393                   // We would have timed out. Attempt to crash the process here to leave a trace.
394                   throw new AssertionError("Timed out logging finalizer exception", ex);
395                 }
396             } finally {
397                 // Done finalizing, stop holding the object as live.
398                 finalizingObject = null;
399                 exceptionLoggingState = NONE;
400             }
401         }
402 
doClean(Cleaner.Cleanable cleanable)403         private void doClean(Cleaner.Cleanable cleanable) {
404             try {
405                 cleanable.clean();
406                 // We only get here for SystemCleaner, and are thus not constrained to ignore
407                 // exceptions/errors.
408             } finally {
409                 finalizingObject = null;
410             }
411         }
412     }
413 
414     /**
415      * The watchdog exits the VM if either the FinalizerDaemon, or the ReferenceQueueDaemon
416      * gets stuck. We consider the finalizer to be stuck if it spends more than
417      * MAX_FINALIZATION_MILLIS on one instance. We consider ReferenceQueueDaemon to be
418      * potentially stuck if it spends more than MAX_FINALIZATION_MILLIS processing a single
419      * Cleaner or transferring objects into a single queue, but only report if this happens
420      * a few times in a row, to compensate for the fact that multiple Cleaners may be involved.
421      */
422     private static class FinalizerWatchdogDaemon extends Daemon {
423         // Single bit values to identify daemon to be watched.
424         static final int FINALIZER_DAEMON = 1;
425         static final int RQ_DAEMON = 2;
426 
427         @UnsupportedAppUsage
428         private static final FinalizerWatchdogDaemon INSTANCE = new FinalizerWatchdogDaemon();
429         private static final VarHandle VH_ACTION;
430         static {
431             try {
432                 VH_ACTION = MethodHandles
433                         .privateLookupIn(
434                                 CleanerImpl.PhantomCleanableRef.class, MethodHandles.lookup())
435                         .findVarHandle(
436                                 CleanerImpl.PhantomCleanableRef.class, "action", Runnable.class);
437             } catch (NoSuchFieldException | IllegalAccessException e) {
438                 throw new AssertionError("PhantomCleanableRef should have action field", e);
439             }
440         }
441 
442         private int activeWatchees;  // Only synchronized accesses.
443 
444         private long finalizerTimeoutNs = 0;  // Lazily initialized.
445 
446         // We tolerate this many timeouts during an enqueuePending call.
447         // This number is > 1, since we may only report enqueuePending progress rarely.
448         private static final int TOLERATED_REFERENCE_QUEUE_TIMEOUTS = 5;
449         private static final AtomicInteger observedReferenceQueueTimeouts = new AtomicInteger(0);
450 
FinalizerWatchdogDaemon()451         FinalizerWatchdogDaemon() {
452             super("FinalizerWatchdogDaemon");
453         }
454 
resetTimeouts()455         void resetTimeouts() {
456             observedReferenceQueueTimeouts.lazySet(0);
457         }
458 
runInternal()459         @Override public void runInternal() {
460             while (isRunning()) {
461                 if (!sleepUntilNeeded()) {
462                     // We have been interrupted, need to see if this daemon has been stopped.
463                     continue;
464                 }
465                 final TimeoutException exception = waitForProgress();
466                 if (exception != null && !VMDebug.isDebuggerConnected()) {
467                     timedOut(exception);
468                     break;
469                 }
470             }
471         }
472 
473         /**
474          * Wait until something is ready to be finalized.
475          * Return false if we have been interrupted
476          * See also http://code.google.com/p/android/issues/detail?id=22778.
477          */
sleepUntilNeeded()478         private synchronized boolean sleepUntilNeeded() {
479             while (activeWatchees == 0) {
480                 try {
481                     wait();
482                 } catch (InterruptedException e) {
483                     // Daemon.stop may have interrupted us.
484                     return false;
485                 } catch (OutOfMemoryError e) {
486                     return false;
487                 }
488             }
489             return true;
490         }
491 
492         /**
493          * Notify daemon that it's OK to sleep until notified that something is ready to be
494          * finalized.
495          */
monitoringNotNeeded(int whichDaemon)496         private synchronized void monitoringNotNeeded(int whichDaemon) {
497             activeWatchees &= ~whichDaemon;
498         }
499 
500         /**
501          * Notify daemon that there is something ready to be finalized.
502          */
monitoringNeeded(int whichDaemon)503         private synchronized void monitoringNeeded(int whichDaemon) {
504             int oldWatchees = activeWatchees;
505             activeWatchees |= whichDaemon;
506 
507             if (oldWatchees == 0) {
508                 notify();
509             }
510         }
511 
isActive(int whichDaemon)512         private synchronized boolean isActive(int whichDaemon) {
513             return (activeWatchees & whichDaemon) != 0;
514         }
515 
516         /**
517          * Sleep for the given number of nanoseconds, or slightly longer.
518          * @return false if we were interrupted.
519          */
sleepForNanos(long durationNanos)520         private boolean sleepForNanos(long durationNanos) {
521             // It's important to base this on nanoTime(), not currentTimeMillis(), since
522             // the former stops counting when the processor isn't running.
523             long startNanos = System.nanoTime();
524             while (true) {
525                 long elapsedNanos = System.nanoTime() - startNanos;
526                 long sleepNanos = durationNanos - elapsedNanos;
527                 if (sleepNanos <= 0) {
528                     return true;
529                 }
530                 // Ensure the nano time is always rounded up to the next whole millisecond,
531                 // ensuring the delay is >= the requested delay.
532                 long sleepMillis = (sleepNanos + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
533                 try {
534                     Thread.sleep(sleepMillis);
535                 } catch (InterruptedException e) {
536                     if (!isRunning()) {
537                         return false;
538                     }
539                 } catch (OutOfMemoryError ignored) {
540                     if (!isRunning()) {
541                         return false;
542                     }
543                 }
544             }
545         }
546 
547         /**
548          * A toString() that cannot possibly be stopped by a hung finalizer.
549          * Mirrors Object.toString(), except that we use the system hashcode.
550          * Thus no user monitors can be acquired.
551          */
safeToString(Object obj)552         static private String safeToString(Object obj) {
553             if (NativeAllocationRegistry.isCleanerThunk(obj)) {
554                 // Known to not acquire user monitors, and has toString() method tailored for this.
555                 return obj.toString();
556             }
557             return obj.getClass().getName() + '@'
558                     + Integer.toHexString(System.identityHashCode(obj));
559         }
560 
561         /**
562          * Return null (normal case) or an exception describing what timed out.
563          * Wait VMRuntime.getFinalizerTimeoutMs.  If the FinalizerDaemon took essentially the
564          * whole time processing a single reference, or the ReferenceQueueDaemon failed to make
565          * visible progress during that time, return an exception.  Only called from a single
566          * thread.
567          */
waitForProgress()568         private TimeoutException waitForProgress() {
569             if (finalizerTimeoutNs == 0) {
570                 finalizerTimeoutNs =
571                         NANOS_PER_MILLI * VMRuntime.getRuntime().getFinalizerTimeoutMs();
572                 // Temporary app backward compatibility. Remove eventually.
573                 MAX_FINALIZE_NANOS = finalizerTimeoutNs;
574             }
575             // Read the counter before we read the "active" state the first time, and after
576             // we read it the last time, to guarantee that if the state was ever inactive,
577             // we'll see a changed counter.
578             int finalizerStartCount = FinalizerDaemon.INSTANCE.progressCounter.get();
579             boolean monitorFinalizer = isActive(FINALIZER_DAEMON);
580             int refQueueStartCount = ReferenceQueueDaemon.INSTANCE.progressCounter.get();
581             boolean monitorRefQueue = isActive(RQ_DAEMON);
582             // Avoid remembering object being finalized, so as not to keep it alive.
583             final long startMillis = System.currentTimeMillis();
584             final long startNanos = System.nanoTime();
585 
586             // Rather than just sleeping for finalizerTimeoutNs and checking whether we made
587             // progress, we sleep repeatedly. This means that if our process makes no progress,
588             // e.g. because it is frozen, the watchdog also won't, making it less likely we will
589             // spuriously time out. It does mean that in the normal case, we will go to sleep
590             // and wake up twice per timeout period, rather than once.
591             final int NUM_WAKEUPS = 5;
592             for (int i = 1; i <= NUM_WAKEUPS; ++i) {
593                 if (!sleepForNanos(finalizerTimeoutNs / NUM_WAKEUPS)) {
594                     // Don't report possibly spurious timeout if we are interrupted.
595                     return null;
596                 }
597                 if (monitorFinalizer && isActive(FINALIZER_DAEMON)
598                     && FinalizerDaemon.INSTANCE.progressCounter.get() == finalizerStartCount) {
599                     // Still working on same finalizer or Java 9 Cleaner.
600                     continue;
601                 }
602                 if (monitorRefQueue && isActive(RQ_DAEMON)
603                     && ReferenceQueueDaemon.INSTANCE.progressCounter.get() == refQueueStartCount) {
604                     // Still working on same ReferenceQueue or sun.misc.Cleaner.
605                     continue;
606                 }
607                 // Everything that could make progress, already did. Just sleep for the rest of the
608                 // timeout interval.
609                 if (i < NUM_WAKEUPS) {
610                     sleepForNanos((finalizerTimeoutNs  / NUM_WAKEUPS) * (NUM_WAKEUPS - i));
611                     return null;
612                 }
613             }
614             // Either a state change to inactive, or a task completion would have caused us to see a
615             // counter change. Thus at least one of the daemons appears stuck.
616             if (monitorFinalizer && isActive(FINALIZER_DAEMON)
617                 && FinalizerDaemon.INSTANCE.progressCounter.get() == finalizerStartCount) {
618                 if (FinalizerDaemon.INSTANCE.exceptionLoggingState == FinalizerDaemon.LOGGING) {
619                     // Try to let it finish and crash. We will time out if we get here again.
620                     FinalizerDaemon.INSTANCE.exceptionLoggingState = FinalizerDaemon.TIMED_OUT;
621                 }
622                 // The finalizingObject field was set just before the counter increment, which
623                 // preceded the doFinalize() or doClean() call.  Thus we are guaranteed to get the
624                 // correct finalizing value below, unless doFinalize() just finished as we were
625                 // timing out, in which case we may get null or a later one.
626                 Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject;
627                 System.logE("Was finalizing " + finalizingObjectAsString(finalizing)
628                     + ", now finalizing "
629                     + finalizingObjectAsString(FinalizerDaemon.INSTANCE.finalizingObject));
630                 // Print both time of day and monotonic time differences:
631                 System.logE("Total elapsed millis: "
632                     + (System.currentTimeMillis() - startMillis));
633                 System.logE("Total elapsed nanos: " + (System.nanoTime() - startNanos));
634                 return finalizerTimeoutException(finalizing);
635             }
636             if (monitorRefQueue && isActive(RQ_DAEMON)
637                 && ReferenceQueueDaemon.INSTANCE.progressCounter.get() == refQueueStartCount) {
638                 // Report RQD timeouts only if they occur repeatedly.
639                 // TODO: Consider changing that, but we have historically been more tolerant here,
640                 // since we may not increment the reference counter for every processed queue
641                 // element.
642                 Object current = ReferenceQueueDaemon.INSTANCE.currentlyProcessing();
643                 String currentTarget = current == null ? "unknown" : safeToString(current);
644                 System.logE("ReferenceQueueDaemon timed out while targeting " + currentTarget
645                         + ". Total nanos: " + (System.nanoTime() - startNanos));
646                 if (observedReferenceQueueTimeouts.incrementAndGet()
647                         > TOLERATED_REFERENCE_QUEUE_TIMEOUTS) {
648                     return refQueueTimeoutException(currentTarget);
649                 }
650             }
651             return null;
652         }
653 
finalizerTimeoutException(Object object)654         private static TimeoutException finalizerTimeoutException(Object object) {
655             if (object == null) {
656                 return new TimeoutException("Unknown finalizer timed out");
657             }
658             StringBuilder messageBuilder = new StringBuilder();
659 
660             if (object instanceof Cleaner.Cleanable) {
661                 messageBuilder.append(VH_ACTION.get(object).getClass().getName());
662             } else {
663                 messageBuilder.append(object.getClass().getName()).append(".finalize()");
664             }
665 
666             messageBuilder.append(" timed out after ")
667                     .append(VMRuntime.getRuntime().getFinalizerTimeoutMs() / 1000)
668                     .append(" seconds");
669             TimeoutException syntheticException = new TimeoutException(messageBuilder.toString());
670             // We use the stack from where finalize() was running to show where it was stuck.
671             syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
672             return syntheticException;
673         }
674 
finalizingObjectAsString(Object obj)675         private static String finalizingObjectAsString(Object obj) {
676             if (obj == null) {
677                 return "unknown";
678             }
679             if (obj instanceof Cleaner.Cleanable) {
680                 return safeToString(VH_ACTION.get(obj));
681             } else {
682                 return safeToString(obj);
683             }
684         }
685 
refQueueTimeoutException(String target)686         private static TimeoutException refQueueTimeoutException(String target) {
687             String message = "ReferenceQueueDaemon timed out while targeting " + target;
688             return new TimeoutException(message);
689         }
690 
timedOut(TimeoutException exception)691         private static void timedOut(TimeoutException exception) {
692             // Send SIGQUIT to get native stack traces.
693             try {
694                 Os.kill(Os.getpid(), OsConstants.SIGQUIT);
695                 // Sleep a few seconds to let the stack traces print.
696                 Thread.sleep(5000);
697             } catch (Exception e) {
698                 System.logE("failed to send SIGQUIT", e);
699             } catch (OutOfMemoryError ignored) {
700                 // May occur while trying to allocate the exception.
701             }
702 
703             // Ideally, we'd want to do this if this Thread had no handler to dispatch to.
704             // Unfortunately, it's extremely to messy to query whether a given Thread has *some*
705             // handler to dispatch to, either via a handler set on itself, via its ThreadGroup
706             // object or via the defaultUncaughtExceptionHandler.
707             //
708             // As an approximation, we log by hand and exit if there's no pre-exception handler nor
709             // a default uncaught exception handler.
710             //
711             // Note that this condition will only ever be hit by ART host tests and standalone
712             // dalvikvm invocations. All zygote forked process *will* have a pre-handler set
713             // in RuntimeInit and they cannot subsequently override it.
714             if (Thread.getUncaughtExceptionPreHandler() == null &&
715                     Thread.getDefaultUncaughtExceptionHandler() == null) {
716                 // If we have no handler, log and exit.
717                 System.logE(exception.getMessage(), exception);
718                 System.exit(2);
719             }
720 
721             // Otherwise call the handler to do crash reporting.
722             // We don't just throw because we're not the thread that
723             // timed out; we're the thread that detected it.
724             Thread.currentThread().dispatchUncaughtException(exception);
725         }
726     }
727 
728     // Adds a heap trim task to the heap event processor, not called from java. Left for
729     // compatibility purposes due to reflection.
730     @UnsupportedAppUsage
requestHeapTrim()731     public static void requestHeapTrim() {
732         VMRuntime.getRuntime().requestHeapTrim();
733     }
734 
735     // Adds a concurrent GC request task ot the heap event processor, not called from java. Left
736     // for compatibility purposes due to reflection.
requestGC()737     public static void requestGC() {
738         VMRuntime.getRuntime().requestConcurrentGC();
739     }
740 
741     private static class HeapTaskDaemon extends Daemon {
742         private static final HeapTaskDaemon INSTANCE = new HeapTaskDaemon();
743 
HeapTaskDaemon()744         HeapTaskDaemon() {
745             super("HeapTaskDaemon");
746         }
747 
748         // Overrides the Daemon.interupt method which is called from Daemons.stop.
interrupt(Thread thread)749         public synchronized void interrupt(Thread thread) {
750             VMRuntime.getRuntime().stopHeapTaskProcessor();
751         }
752 
runInternal()753         @Override public void runInternal() {
754             synchronized (this) {
755                 if (isRunning()) {
756                   // Needs to be synchronized or else we there is a race condition where we start
757                   // the thread, call stopHeapTaskProcessor before we start the heap task
758                   // processor, resulting in a deadlock since startHeapTaskProcessor restarts it
759                   // while the other thread is waiting in Daemons.stop().
760                   VMRuntime.getRuntime().startHeapTaskProcessor();
761                 }
762             }
763             // This runs tasks until we are stopped and there is no more pending task.
764             VMRuntime.getRuntime().runHeapTasks();
765         }
766     }
767 }
768