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