blob: 7d0eca2f0819ae5b62c0b8bf8f2d82f020e8a693 [file] [log] [blame]
Rahul Ravikumar05336002019-10-14 15:04:32 -07001/*
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
17package java.lang;
18
19import android.system.Os;
20import android.system.OsConstants;
21import dalvik.annotation.compat.UnsupportedAppUsage;
22import dalvik.system.VMRuntime;
23import java.lang.ref.FinalizerReference;
24import java.lang.ref.Reference;
25import java.lang.ref.ReferenceQueue;
26import java.util.concurrent.atomic.AtomicBoolean;
27import java.util.concurrent.atomic.AtomicInteger;
28import java.util.concurrent.CountDownLatch;
29import java.util.concurrent.TimeoutException;
30import 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 */
39public 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
63 public static void start() {
64 for (Daemon daemon : DAEMONS) {
65 daemon.start();
66 }
67 }
68
69 public static void startPostZygoteFork() {
70 postZygoteFork = true;
71 for (Daemon daemon : DAEMONS) {
72 daemon.startPostZygoteFork();
73 }
74 }
75
76 @UnsupportedAppUsage
77 public static void stop() {
78 for (Daemon daemon : DAEMONS) {
79 daemon.stop();
80 }
81 }
82
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
102 protected Daemon(String name) {
103 this.name = name;
104 }
105
106 @UnsupportedAppUsage
107 public synchronized void start() {
108 startInternal();
109 }
110
111 public synchronized void startPostZygoteFork() {
112 postZygoteFork = true;
113 startInternal();
114 }
115
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
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
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
147 protected synchronized boolean isRunning() {
148 return thread != null;
149 }
150
151 public synchronized void interrupt() {
152 interrupt(thread);
153 }
154
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
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 */
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
205 ReferenceQueueDaemon() {
206 super("ReferenceQueueDaemon");
207 }
208
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
239 FinalizerDaemon() {
240 super("FinalizerDaemon");
241 }
242
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")
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
313 FinalizerWatchdogDaemon() {
314 super("FinalizerWatchdogDaemon");
315 }
316
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 */
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 */
354 private synchronized void goToSleep() {
355 needToWork = false;
356 }
357
358 /**
359 * Notify daemon that there is something ready to be finalized.
360 */
361 private synchronized void wakeUp() {
362 needToWork = true;
363 notify();
364 }
365
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 */
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 */
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
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
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.
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
503 HeapTaskDaemon() {
504 super("HeapTaskDaemon");
505 }
506
507 // Overrides the Daemon.interupt method which is called from Daemons.stop.
508 public synchronized void interrupt(Thread thread) {
509 VMRuntime.getRuntime().stopHeapTaskProcessor();
510 }
511
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}