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