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 try { 140 runInternal(); 141 } catch (Throwable ex) { 142 // Should never happen, but may not o.w. get reported, e.g. in zygote. 143 // Risk logging redundantly, rather than losing it. 144 System.logE("Uncaught exception in system thread " + name, ex); 145 throw ex; 146 } 147 } 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 Thread threadToStop; 178 synchronized (this) { 179 threadToStop = thread; 180 thread = null; 181 } 182 if (threadToStop == null) { 183 throw new IllegalStateException("not running"); 184 } 185 interrupt(threadToStop); 186 while (true) { 187 try { 188 threadToStop.join(); 189 return; 190 } catch (InterruptedException ignored) { 191 } catch (OutOfMemoryError ignored) { 192 // An OOME may be thrown if allocating the InterruptedException failed. 193 } 194 } 195 } 196 197 /** 198 * Returns the current stack trace of the thread, or an empty stack trace 199 * if the thread is not currently running. 200 */ getStackTrace()201 public synchronized StackTraceElement[] getStackTrace() { 202 return thread != null ? thread.getStackTrace() : EmptyArray.STACK_TRACE_ELEMENT; 203 } 204 } 205 206 /** 207 * This heap management thread moves elements from the garbage collector's 208 * pending list to the managed reference queue. 209 */ 210 private static class ReferenceQueueDaemon extends Daemon { 211 @UnsupportedAppUsage 212 private static final ReferenceQueueDaemon INSTANCE = new ReferenceQueueDaemon(); 213 214 // Monitored by FinalizerWatchdogDaemon to make sure we're still working. 215 private final AtomicInteger progressCounter = new AtomicInteger(0); 216 ReferenceQueueDaemon()217 ReferenceQueueDaemon() { 218 super("ReferenceQueueDaemon"); 219 } 220 runInternal()221 @Override public void runInternal() { 222 FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded(FinalizerWatchdogDaemon.RQ_DAEMON); 223 while (isRunning()) { 224 Reference<?> list; 225 try { 226 synchronized (ReferenceQueue.class) { 227 if (ReferenceQueue.unenqueued == null) { 228 progressCounter.incrementAndGet(); 229 FinalizerWatchdogDaemon.INSTANCE.monitoringNotNeeded( 230 FinalizerWatchdogDaemon.RQ_DAEMON); 231 do { 232 ReferenceQueue.class.wait(); 233 } while (ReferenceQueue.unenqueued == null); 234 progressCounter.incrementAndGet(); 235 FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded( 236 FinalizerWatchdogDaemon.RQ_DAEMON); 237 } 238 list = ReferenceQueue.unenqueued; 239 ReferenceQueue.unenqueued = null; 240 } 241 } catch (InterruptedException e) { 242 continue; 243 } catch (OutOfMemoryError e) { 244 continue; 245 } 246 ReferenceQueue.enqueuePending(list, progressCounter); 247 FinalizerWatchdogDaemon.INSTANCE.resetTimeouts(); 248 } 249 } 250 currentlyProcessing()251 ReferenceQueue currentlyProcessing() { 252 return ReferenceQueue.getCurrentQueue(); 253 } 254 } 255 256 private static class FinalizerDaemon extends Daemon { 257 @UnsupportedAppUsage 258 private static final FinalizerDaemon INSTANCE = new FinalizerDaemon(); 259 private final ReferenceQueue<Object> queue = FinalizerReference.queue; 260 private final AtomicInteger progressCounter = new AtomicInteger(0); 261 // Object (not reference!) being finalized. Accesses may race! 262 @UnsupportedAppUsage 263 private Object finalizingObject = null; 264 FinalizerDaemon()265 FinalizerDaemon() { 266 super("FinalizerDaemon"); 267 } 268 runInternal()269 @Override public void runInternal() { 270 // This loop may be performance critical, since we need to keep up with mutator 271 // generation of finalizable objects. 272 // We minimize the amount of work we do per finalizable object. For example, we avoid 273 // reading the current time here, since that involves a kernel call per object. We 274 // limit fast path communication with FinalizerWatchDogDaemon to what's unavoidable: A 275 // non-volatile store to communicate the current finalizable object, e.g. for 276 // reporting, and a release store (lazySet) to a counter. 277 // We do stop the FinalizerWatchDogDaemon if we have nothing to do for a 278 // potentially extended period. This prevents the device from waking up regularly 279 // during idle times. 280 281 // Local copy of progressCounter; saves a fence per increment on ARM and MIPS. 282 int localProgressCounter = progressCounter.get(); 283 284 FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded( 285 FinalizerWatchdogDaemon.FINALIZER_DAEMON); 286 while (isRunning()) { 287 try { 288 // Use non-blocking poll to avoid FinalizerWatchdogDaemon communication 289 // when busy. 290 FinalizerReference<?> finalizingReference = (FinalizerReference<?>)queue.poll(); 291 if (finalizingReference != null) { 292 finalizingObject = finalizingReference.get(); 293 progressCounter.lazySet(++localProgressCounter); 294 } else { 295 finalizingObject = null; 296 progressCounter.lazySet(++localProgressCounter); 297 // Slow path; block. 298 FinalizerWatchdogDaemon.INSTANCE.monitoringNotNeeded( 299 FinalizerWatchdogDaemon.FINALIZER_DAEMON); 300 finalizingReference = (FinalizerReference<?>)queue.remove(); 301 finalizingObject = finalizingReference.get(); 302 progressCounter.set(++localProgressCounter); 303 FinalizerWatchdogDaemon.INSTANCE.monitoringNeeded( 304 FinalizerWatchdogDaemon.FINALIZER_DAEMON); 305 } 306 doFinalize(finalizingReference); 307 } catch (InterruptedException ignored) { 308 } catch (OutOfMemoryError ignored) { 309 } 310 } 311 } 312 313 @FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION") doFinalize(FinalizerReference<?> reference)314 private void doFinalize(FinalizerReference<?> reference) { 315 FinalizerReference.remove(reference); 316 Object object = reference.get(); 317 reference.clear(); 318 try { 319 object.finalize(); 320 } catch (Throwable ex) { 321 // The RI silently swallows these, but Android has always logged. 322 System.logE("Uncaught exception thrown by finalizer", ex); 323 } finally { 324 // Done finalizing, stop holding the object as live. 325 finalizingObject = null; 326 } 327 } 328 } 329 330 /** 331 * The watchdog exits the VM if either the FinalizerDaemon, or the ReferenceQueueDaemon 332 * gets stuck. We consider the finalizer to be stuck if it spends more than 333 * MAX_FINALIZATION_MILLIS on one instance. We consider ReferenceQueueDaemon to be 334 * potentially stuck if it spends more than MAX_FINALIZATION_MILLIS processing a single 335 * Cleaner or transferring objects into a single queue, but only report if this happens 336 * a few times in a row, to compensate for the fact that multiple Cleaners may be involved. 337 */ 338 private static class FinalizerWatchdogDaemon extends Daemon { 339 // Single bit values to identify daemon to be watched. 340 static final int FINALIZER_DAEMON = 1; 341 static final int RQ_DAEMON = 2; 342 343 @UnsupportedAppUsage 344 private static final FinalizerWatchdogDaemon INSTANCE = new FinalizerWatchdogDaemon(); 345 346 private int activeWatchees; // Only synchronized accesses. 347 348 private long finalizerTimeoutNs = 0; // Lazily initialized. 349 350 // We tolerate this many timeouts during an enqueuePending call. 351 // This number is > 1, since we may only report enqueuePending progress rarely. 352 private static final int TOLERATED_REFERENCE_QUEUE_TIMEOUTS = 5; 353 private static final AtomicInteger observedReferenceQueueTimeouts = new AtomicInteger(0); 354 FinalizerWatchdogDaemon()355 FinalizerWatchdogDaemon() { 356 super("FinalizerWatchdogDaemon"); 357 } 358 resetTimeouts()359 void resetTimeouts() { 360 observedReferenceQueueTimeouts.lazySet(0); 361 } 362 runInternal()363 @Override public void runInternal() { 364 while (isRunning()) { 365 if (!sleepUntilNeeded()) { 366 // We have been interrupted, need to see if this daemon has been stopped. 367 continue; 368 } 369 final TimeoutException exception = waitForProgress(); 370 if (exception != null && !VMDebug.isDebuggerConnected()) { 371 timedOut(exception); 372 break; 373 } 374 } 375 } 376 377 /** 378 * Wait until something is ready to be finalized. 379 * Return false if we have been interrupted 380 * See also http://code.google.com/p/android/issues/detail?id=22778. 381 */ sleepUntilNeeded()382 private synchronized boolean sleepUntilNeeded() { 383 while (activeWatchees == 0) { 384 try { 385 wait(); 386 } catch (InterruptedException e) { 387 // Daemon.stop may have interrupted us. 388 return false; 389 } catch (OutOfMemoryError e) { 390 return false; 391 } 392 } 393 return true; 394 } 395 396 /** 397 * Notify daemon that it's OK to sleep until notified that something is ready to be 398 * finalized. 399 */ monitoringNotNeeded(int whichDaemon)400 private synchronized void monitoringNotNeeded(int whichDaemon) { 401 activeWatchees &= ~whichDaemon; 402 } 403 404 /** 405 * Notify daemon that there is something ready to be finalized. 406 */ monitoringNeeded(int whichDaemon)407 private synchronized void monitoringNeeded(int whichDaemon) { 408 int oldWatchees = activeWatchees; 409 activeWatchees |= whichDaemon; 410 411 if (oldWatchees == 0) { 412 notify(); 413 } 414 } 415 isActive(int whichDaemon)416 private synchronized boolean isActive(int whichDaemon) { 417 return (activeWatchees & whichDaemon) != 0; 418 } 419 420 /** 421 * Sleep for the given number of nanoseconds, or slightly longer. 422 * @return false if we were interrupted. 423 */ sleepForNanos(long durationNanos)424 private boolean sleepForNanos(long durationNanos) { 425 // It's important to base this on nanoTime(), not currentTimeMillis(), since 426 // the former stops counting when the processor isn't running. 427 long startNanos = System.nanoTime(); 428 while (true) { 429 long elapsedNanos = System.nanoTime() - startNanos; 430 long sleepNanos = durationNanos - elapsedNanos; 431 if (sleepNanos <= 0) { 432 return true; 433 } 434 // Ensure the nano time is always rounded up to the next whole millisecond, 435 // ensuring the delay is >= the requested delay. 436 long sleepMillis = (sleepNanos + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI; 437 try { 438 Thread.sleep(sleepMillis); 439 } catch (InterruptedException e) { 440 if (!isRunning()) { 441 return false; 442 } 443 } catch (OutOfMemoryError ignored) { 444 if (!isRunning()) { 445 return false; 446 } 447 } 448 } 449 } 450 451 452 /** 453 * Return null (normal case) or an exception describing what timed out. 454 * Wait VMRuntime.getFinalizerTimeoutMs. If the FinalizerDaemon took essentially the 455 * whole time processing a single reference, or the ReferenceQueueDaemon failed to make 456 * visible progress during that time, return an exception. Only called from a single 457 * thread. 458 */ waitForProgress()459 private TimeoutException waitForProgress() { 460 if (finalizerTimeoutNs == 0) { 461 finalizerTimeoutNs = 462 NANOS_PER_MILLI * VMRuntime.getRuntime().getFinalizerTimeoutMs(); 463 // Temporary app backward compatibility. Remove eventually. 464 MAX_FINALIZE_NANOS = finalizerTimeoutNs; 465 } 466 boolean monitorFinalizer = false; 467 int finalizerStartCount = 0; 468 if (isActive(FINALIZER_DAEMON)) { 469 monitorFinalizer = true; 470 finalizerStartCount = FinalizerDaemon.INSTANCE.progressCounter.get(); 471 } 472 boolean monitorRefQueue = false; 473 int refQueueStartCount = 0; 474 if (isActive(RQ_DAEMON)) { 475 monitorRefQueue = true; 476 refQueueStartCount = ReferenceQueueDaemon.INSTANCE.progressCounter.get(); 477 } 478 479 // Avoid remembering object being finalized, so as not to keep it alive. 480 if (!sleepForNanos(finalizerTimeoutNs)) { 481 // Don't report possibly spurious timeout if we are interrupted. 482 return null; 483 } 484 if (FinalizerDaemon.INSTANCE.progressCounter.get() == finalizerStartCount 485 && monitorFinalizer && isActive(FINALIZER_DAEMON)) { 486 // We assume that only remove() and doFinalize() may take time comparable to the 487 // finalizer timeout. 488 // We observed neither the effect of the monitoringNotNeeded() nor the increment 489 // preceding a later wakeUp. Any remove() call by the FinalizerDaemon during our 490 // sleep interval must have been followed by a monitoringNeeded() call before we 491 // checked activeCallees. But then we would have seen the counter increment. 492 // Thus there cannot have been such a remove() call. 493 // The FinalizerDaemon must not have progressed (from either the beginning or the 494 // last progressCounter increment) to either the next increment or 495 // monitoringNotNeeded() call. 496 // Thus we must have taken essentially the whole finalizerTimeoutMs in a single 497 // doFinalize() call. Thus it's OK to time out. finalizingObject was set just 498 // before the counter increment, which preceded the doFinalize() call. Thus we 499 // are guaranteed to get the correct finalizing value below, unless doFinalize() 500 // just finished as we were timing out, in which case we may get null or a later 501 // one. In this last case, we are very likely to discard it below. 502 Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject; 503 sleepForNanos(500 * NANOS_PER_MILLI); 504 // Recheck to make it even less likely we report the wrong finalizing object in 505 // the case which a very slow finalization just finished as we were timing out. 506 if (isActive(FINALIZER_DAEMON) 507 && FinalizerDaemon.INSTANCE.progressCounter.get() == finalizerStartCount) { 508 return finalizerTimeoutException(finalizing); 509 } 510 } 511 if (ReferenceQueueDaemon.INSTANCE.progressCounter.get() == refQueueStartCount 512 && monitorRefQueue && isActive(RQ_DAEMON)) { 513 if (observedReferenceQueueTimeouts.incrementAndGet() 514 > TOLERATED_REFERENCE_QUEUE_TIMEOUTS) { 515 return refQueueTimeoutException( 516 ReferenceQueueDaemon.INSTANCE.currentlyProcessing()); 517 } 518 } 519 return null; 520 } 521 finalizerTimeoutException(Object object)522 private static TimeoutException finalizerTimeoutException(Object object) { 523 String message = object.getClass().getName() + ".finalize() timed out after " 524 + VMRuntime.getRuntime().getFinalizerTimeoutMs() / 1000 + " seconds"; 525 TimeoutException syntheticException = new TimeoutException(message); 526 // We use the stack from where finalize() was running to show where it was stuck. 527 syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace()); 528 return syntheticException; 529 } 530 refQueueTimeoutException(ReferenceQueue rq)531 private static TimeoutException refQueueTimeoutException(ReferenceQueue rq) { 532 String message = "ReferenceQueueDaemon timed out while targeting " + rq; 533 return new TimeoutException(message); 534 } 535 timedOut(TimeoutException exception)536 private static void timedOut(TimeoutException exception) { 537 // Send SIGQUIT to get native stack traces. 538 try { 539 Os.kill(Os.getpid(), OsConstants.SIGQUIT); 540 // Sleep a few seconds to let the stack traces print. 541 Thread.sleep(5000); 542 } catch (Exception e) { 543 System.logE("failed to send SIGQUIT", e); 544 } catch (OutOfMemoryError ignored) { 545 // May occur while trying to allocate the exception. 546 } 547 548 // Ideally, we'd want to do this if this Thread had no handler to dispatch to. 549 // Unfortunately, it's extremely to messy to query whether a given Thread has *some* 550 // handler to dispatch to, either via a handler set on itself, via its ThreadGroup 551 // object or via the defaultUncaughtExceptionHandler. 552 // 553 // As an approximation, we log by hand and exit if there's no pre-exception handler nor 554 // a default uncaught exception handler. 555 // 556 // Note that this condition will only ever be hit by ART host tests and standalone 557 // dalvikvm invocations. All zygote forked process *will* have a pre-handler set 558 // in RuntimeInit and they cannot subsequently override it. 559 if (Thread.getUncaughtExceptionPreHandler() == null && 560 Thread.getDefaultUncaughtExceptionHandler() == null) { 561 // If we have no handler, log and exit. 562 System.logE(exception.getMessage(), exception); 563 System.exit(2); 564 } 565 566 // Otherwise call the handler to do crash reporting. 567 // We don't just throw because we're not the thread that 568 // timed out; we're the thread that detected it. 569 Thread.currentThread().dispatchUncaughtException(exception); 570 } 571 } 572 573 // Adds a heap trim task to the heap event processor, not called from java. Left for 574 // compatibility purposes due to reflection. 575 @UnsupportedAppUsage requestHeapTrim()576 public static void requestHeapTrim() { 577 VMRuntime.getRuntime().requestHeapTrim(); 578 } 579 580 // Adds a concurrent GC request task ot the heap event processor, not called from java. Left 581 // for compatibility purposes due to reflection. requestGC()582 public static void requestGC() { 583 VMRuntime.getRuntime().requestConcurrentGC(); 584 } 585 586 private static class HeapTaskDaemon extends Daemon { 587 private static final HeapTaskDaemon INSTANCE = new HeapTaskDaemon(); 588 HeapTaskDaemon()589 HeapTaskDaemon() { 590 super("HeapTaskDaemon"); 591 } 592 593 // Overrides the Daemon.interupt method which is called from Daemons.stop. interrupt(Thread thread)594 public synchronized void interrupt(Thread thread) { 595 VMRuntime.getRuntime().stopHeapTaskProcessor(); 596 } 597 runInternal()598 @Override public void runInternal() { 599 synchronized (this) { 600 if (isRunning()) { 601 // Needs to be synchronized or else we there is a race condition where we start 602 // the thread, call stopHeapTaskProcessor before we start the heap task 603 // processor, resulting in a deadlock since startHeapTaskProcessor restarts it 604 // while the other thread is waiting in Daemons.stop(). 605 VMRuntime.getRuntime().startHeapTaskProcessor(); 606 } 607 } 608 // This runs tasks until we are stopped and there is no more pending task. 609 VMRuntime.getRuntime().runHeapTasks(); 610 } 611 } 612 } 613