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 17package java.lang; 18 19import android.system.Os; 20import android.system.OsConstants; 21import dalvik.system.VMRuntime; 22import java.lang.ref.FinalizerReference; 23import java.lang.ref.Reference; 24import java.lang.ref.ReferenceQueue; 25import java.util.concurrent.atomic.AtomicBoolean; 26import java.util.concurrent.atomic.AtomicInteger; 27import java.util.concurrent.TimeoutException; 28import libcore.util.EmptyArray; 29 30/** 31 * Calls Object.finalize() on objects in the finalizer reference queue. The VM 32 * will abort if any finalize() call takes more than the maximum finalize time 33 * to complete. 34 * 35 * @hide 36 */ 37public final class Daemons { 38 private static final int NANOS_PER_MILLI = 1000 * 1000; 39 private static final int NANOS_PER_SECOND = NANOS_PER_MILLI * 1000; 40 private static final long MAX_FINALIZE_NANOS = 10L * NANOS_PER_SECOND; 41 42 public static void start() { 43 ReferenceQueueDaemon.INSTANCE.start(); 44 FinalizerDaemon.INSTANCE.start(); 45 FinalizerWatchdogDaemon.INSTANCE.start(); 46 HeapTaskDaemon.INSTANCE.start(); 47 } 48 49 public static void startPostZygoteFork() { 50 ReferenceQueueDaemon.INSTANCE.startPostZygoteFork(); 51 FinalizerDaemon.INSTANCE.startPostZygoteFork(); 52 FinalizerWatchdogDaemon.INSTANCE.startPostZygoteFork(); 53 HeapTaskDaemon.INSTANCE.startPostZygoteFork(); 54 } 55 56 public static void stop() { 57 HeapTaskDaemon.INSTANCE.stop(); 58 ReferenceQueueDaemon.INSTANCE.stop(); 59 FinalizerDaemon.INSTANCE.stop(); 60 FinalizerWatchdogDaemon.INSTANCE.stop(); 61 } 62 63 /** 64 * A background task that provides runtime support to the application. 65 * Daemons can be stopped and started, but only so that the zygote can be a 66 * single-threaded process when it forks. 67 */ 68 private static abstract class Daemon implements Runnable { 69 private Thread thread; 70 private String name; 71 private boolean postZygoteFork; 72 73 protected Daemon(String name) { 74 this.name = name; 75 } 76 77 public synchronized void start() { 78 startInternal(); 79 } 80 81 public synchronized void startPostZygoteFork() { 82 postZygoteFork = true; 83 startInternal(); 84 } 85 86 public void startInternal() { 87 if (thread != null) { 88 throw new IllegalStateException("already running"); 89 } 90 thread = new Thread(ThreadGroup.systemThreadGroup, this, name); 91 thread.setDaemon(true); 92 thread.start(); 93 } 94 95 public void run() { 96 if (postZygoteFork) { 97 // We don't set the priority before the Thread.start() call above because 98 // Thread.start() will call SetNativePriority and overwrite the desired native 99 // priority. We (may) use a native priority that doesn't have a corresponding 100 // java.lang.Thread-level priority (native priorities are more coarse-grained.) 101 VMRuntime.getRuntime().setSystemDaemonThreadPriority(); 102 } 103 runInternal(); 104 } 105 106 public abstract void runInternal(); 107 108 /** 109 * Returns true while the current thread should continue to run; false 110 * when it should return. 111 */ 112 protected synchronized boolean isRunning() { 113 return thread != null; 114 } 115 116 public synchronized void interrupt() { 117 interrupt(thread); 118 } 119 120 public synchronized void interrupt(Thread thread) { 121 if (thread == null) { 122 throw new IllegalStateException("not running"); 123 } 124 thread.interrupt(); 125 } 126 127 /** 128 * Waits for the runtime thread to stop. This interrupts the thread 129 * currently running the runnable and then waits for it to exit. 130 */ 131 public void stop() { 132 Thread threadToStop; 133 synchronized (this) { 134 threadToStop = thread; 135 thread = null; 136 } 137 if (threadToStop == null) { 138 throw new IllegalStateException("not running"); 139 } 140 interrupt(threadToStop); 141 while (true) { 142 try { 143 threadToStop.join(); 144 return; 145 } catch (InterruptedException ignored) { 146 } catch (OutOfMemoryError ignored) { 147 // An OOME may be thrown if allocating the InterruptedException failed. 148 } 149 } 150 } 151 152 /** 153 * Returns the current stack trace of the thread, or an empty stack trace 154 * if the thread is not currently running. 155 */ 156 public synchronized StackTraceElement[] getStackTrace() { 157 return thread != null ? thread.getStackTrace() : EmptyArray.STACK_TRACE_ELEMENT; 158 } 159 } 160 161 /** 162 * This heap management thread moves elements from the garbage collector's 163 * pending list to the managed reference queue. 164 */ 165 private static class ReferenceQueueDaemon extends Daemon { 166 private static final ReferenceQueueDaemon INSTANCE = new ReferenceQueueDaemon(); 167 168 ReferenceQueueDaemon() { 169 super("ReferenceQueueDaemon"); 170 } 171 172 @Override public void runInternal() { 173 while (isRunning()) { 174 Reference<?> list; 175 try { 176 synchronized (ReferenceQueue.class) { 177 while (ReferenceQueue.unenqueued == null) { 178 ReferenceQueue.class.wait(); 179 } 180 list = ReferenceQueue.unenqueued; 181 ReferenceQueue.unenqueued = null; 182 } 183 } catch (InterruptedException e) { 184 continue; 185 } catch (OutOfMemoryError e) { 186 continue; 187 } 188 ReferenceQueue.enqueuePending(list); 189 } 190 } 191 } 192 193 private static class FinalizerDaemon extends Daemon { 194 private static final FinalizerDaemon INSTANCE = new FinalizerDaemon(); 195 private final ReferenceQueue<Object> queue = FinalizerReference.queue; 196 private final AtomicInteger progressCounter = new AtomicInteger(0); 197 // Object (not reference!) being finalized. Accesses may race! 198 private Object finalizingObject = null; 199 200 FinalizerDaemon() { 201 super("FinalizerDaemon"); 202 } 203 204 @Override public void runInternal() { 205 // This loop may be performance critical, since we need to keep up with mutator 206 // generation of finalizable objects. 207 // We minimize the amount of work we do per finalizable object. For example, we avoid 208 // reading the current time here, since that involves a kernel call per object. We 209 // limit fast path communication with FinalizerWatchDogDaemon to what's unavoidable: A 210 // non-volatile store to communicate the current finalizable object, e.g. for 211 // reporting, and a release store (lazySet) to a counter. 212 // We do stop the FinalizerWatchDogDaemon if we have nothing to do for a 213 // potentially extended period. This prevents the device from waking up regularly 214 // during idle times. 215 216 // Local copy of progressCounter; saves a fence per increment on ARM and MIPS. 217 int localProgressCounter = progressCounter.get(); 218 219 while (isRunning()) { 220 try { 221 // Use non-blocking poll to avoid FinalizerWatchdogDaemon communication 222 // when busy. 223 FinalizerReference<?> finalizingReference = (FinalizerReference<?>)queue.poll(); 224 if (finalizingReference != null) { 225 finalizingObject = finalizingReference.get(); 226 progressCounter.lazySet(++localProgressCounter); 227 } else { 228 finalizingObject = null; 229 progressCounter.lazySet(++localProgressCounter); 230 // Slow path; block. 231 FinalizerWatchdogDaemon.INSTANCE.goToSleep(); 232 finalizingReference = (FinalizerReference<?>)queue.remove(); 233 finalizingObject = finalizingReference.get(); 234 progressCounter.set(++localProgressCounter); 235 FinalizerWatchdogDaemon.INSTANCE.wakeUp(); 236 } 237 doFinalize(finalizingReference); 238 } catch (InterruptedException ignored) { 239 } catch (OutOfMemoryError ignored) { 240 } 241 } 242 } 243 244 @FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION") 245 private void doFinalize(FinalizerReference<?> reference) { 246 FinalizerReference.remove(reference); 247 Object object = reference.get(); 248 reference.clear(); 249 try { 250 object.finalize(); 251 } catch (Throwable ex) { 252 // The RI silently swallows these, but Android has always logged. 253 System.logE("Uncaught exception thrown by finalizer", ex); 254 } finally { 255 // Done finalizing, stop holding the object as live. 256 finalizingObject = null; 257 } 258 } 259 } 260 261 /** 262 * The watchdog exits the VM if the finalizer ever gets stuck. We consider 263 * the finalizer to be stuck if it spends more than MAX_FINALIZATION_MILLIS 264 * on one instance. 265 */ 266 private static class FinalizerWatchdogDaemon extends Daemon { 267 private static final FinalizerWatchdogDaemon INSTANCE = new FinalizerWatchdogDaemon(); 268 269 private boolean needToWork = true; // Only accessed in synchronized methods. 270 271 FinalizerWatchdogDaemon() { 272 super("FinalizerWatchdogDaemon"); 273 } 274 275 @Override public void runInternal() { 276 while (isRunning()) { 277 if (!sleepUntilNeeded()) { 278 // We have been interrupted, need to see if this daemon has been stopped. 279 continue; 280 } 281 final Object finalizing = waitForFinalization(); 282 if (finalizing != null && !VMRuntime.getRuntime().isDebuggerActive()) { 283 finalizerTimedOut(finalizing); 284 break; 285 } 286 } 287 } 288 289 /** 290 * Wait until something is ready to be finalized. 291 * Return false if we have been interrupted 292 * See also http://code.google.com/p/android/issues/detail?id=22778. 293 */ 294 private synchronized boolean sleepUntilNeeded() { 295 while (!needToWork) { 296 try { 297 wait(); 298 } catch (InterruptedException e) { 299 // Daemon.stop may have interrupted us. 300 return false; 301 } catch (OutOfMemoryError e) { 302 return false; 303 } 304 } 305 return true; 306 } 307 308 /** 309 * Notify daemon that it's OK to sleep until notified that something is ready to be 310 * finalized. 311 */ 312 private synchronized void goToSleep() { 313 needToWork = false; 314 } 315 316 /** 317 * Notify daemon that there is something ready to be finalized. 318 */ 319 private synchronized void wakeUp() { 320 needToWork = true; 321 notify(); 322 } 323 324 private synchronized boolean getNeedToWork() { 325 return needToWork; 326 } 327 328 /** 329 * Sleep for the given number of nanoseconds. 330 * @return false if we were interrupted. 331 */ 332 private boolean sleepFor(long durationNanos) { 333 long startNanos = System.nanoTime(); 334 while (true) { 335 long elapsedNanos = System.nanoTime() - startNanos; 336 long sleepNanos = durationNanos - elapsedNanos; 337 long sleepMills = sleepNanos / NANOS_PER_MILLI; 338 if (sleepMills <= 0) { 339 return true; 340 } 341 try { 342 Thread.sleep(sleepMills); 343 } catch (InterruptedException e) { 344 if (!isRunning()) { 345 return false; 346 } 347 } catch (OutOfMemoryError ignored) { 348 if (!isRunning()) { 349 return false; 350 } 351 } 352 } 353 } 354 355 356 /** 357 * Return an object that took too long to finalize or return null. 358 * Wait MAX_FINALIZE_NANOS. If the FinalizerDaemon took essentially the whole time 359 * processing a single reference, return that reference. Otherwise return null. 360 */ 361 private Object waitForFinalization() { 362 long startCount = FinalizerDaemon.INSTANCE.progressCounter.get(); 363 // Avoid remembering object being finalized, so as not to keep it alive. 364 if (!sleepFor(MAX_FINALIZE_NANOS)) { 365 // Don't report possibly spurious timeout if we are interrupted. 366 return null; 367 } 368 if (getNeedToWork() && FinalizerDaemon.INSTANCE.progressCounter.get() == startCount) { 369 // We assume that only remove() and doFinalize() may take time comparable to 370 // MAX_FINALIZE_NANOS. 371 // We observed neither the effect of the gotoSleep() nor the increment preceding a 372 // later wakeUp. Any remove() call by the FinalizerDaemon during our sleep 373 // interval must have been followed by a wakeUp call before we checked needToWork. 374 // But then we would have seen the counter increment. Thus there cannot have 375 // been such a remove() call. 376 // The FinalizerDaemon must not have progressed (from either the beginning or the 377 // last progressCounter increment) to either the next increment or gotoSleep() 378 // call. Thus we must have taken essentially the whole MAX_FINALIZE_NANOS in a 379 // single doFinalize() call. Thus it's OK to time out. finalizingObject was set 380 // just before the counter increment, which preceded the doFinalize call. Thus we 381 // are guaranteed to get the correct finalizing value below, unless doFinalize() 382 // just finished as we were timing out, in which case we may get null or a later 383 // one. In this last case, we are very likely to discard it below. 384 Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject; 385 sleepFor(NANOS_PER_SECOND / 2); 386 // Recheck to make it even less likely we report the wrong finalizing object in 387 // the case which a very slow finalization just finished as we were timing out. 388 if (getNeedToWork() 389 && FinalizerDaemon.INSTANCE.progressCounter.get() == startCount) { 390 return finalizing; 391 } 392 } 393 return null; 394 } 395 396 private static void finalizerTimedOut(Object object) { 397 // The current object has exceeded the finalization deadline; abort! 398 String message = object.getClass().getName() + ".finalize() timed out after " 399 + (MAX_FINALIZE_NANOS / NANOS_PER_SECOND) + " seconds"; 400 Exception syntheticException = new TimeoutException(message); 401 // We use the stack from where finalize() was running to show where it was stuck. 402 syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace()); 403 Thread.UncaughtExceptionHandler h = Thread.getDefaultUncaughtExceptionHandler(); 404 // Send SIGQUIT to get native stack traces. 405 try { 406 Os.kill(Os.getpid(), OsConstants.SIGQUIT); 407 // Sleep a few seconds to let the stack traces print. 408 Thread.sleep(5000); 409 } catch (Exception e) { 410 System.logE("failed to send SIGQUIT", e); 411 } catch (OutOfMemoryError ignored) { 412 // May occur while trying to allocate the exception. 413 } 414 if (h == null) { 415 // If we have no handler, log and exit. 416 System.logE(message, syntheticException); 417 System.exit(2); 418 } 419 // Otherwise call the handler to do crash reporting. 420 // We don't just throw because we're not the thread that 421 // timed out; we're the thread that detected it. 422 h.uncaughtException(Thread.currentThread(), syntheticException); 423 } 424 } 425 426 // Adds a heap trim task to the heap event processor, not called from java. Left for 427 // compatibility purposes due to reflection. 428 public static void requestHeapTrim() { 429 VMRuntime.getRuntime().requestHeapTrim(); 430 } 431 432 // Adds a concurrent GC request task ot the heap event processor, not called from java. Left 433 // for compatibility purposes due to reflection. 434 public static void requestGC() { 435 VMRuntime.getRuntime().requestConcurrentGC(); 436 } 437 438 private static class HeapTaskDaemon extends Daemon { 439 private static final HeapTaskDaemon INSTANCE = new HeapTaskDaemon(); 440 441 HeapTaskDaemon() { 442 super("HeapTaskDaemon"); 443 } 444 445 // Overrides the Daemon.interupt method which is called from Daemons.stop. 446 public synchronized void interrupt(Thread thread) { 447 VMRuntime.getRuntime().stopHeapTaskProcessor(); 448 } 449 450 @Override public void runInternal() { 451 synchronized (this) { 452 if (isRunning()) { 453 // Needs to be synchronized or else we there is a race condition where we start 454 // the thread, call stopHeapTaskProcessor before we start the heap task 455 // processor, resulting in a deadlock since startHeapTaskProcessor restarts it 456 // while the other thread is waiting in Daemons.stop(). 457 VMRuntime.getRuntime().startHeapTaskProcessor(); 458 } 459 } 460 // This runs tasks until we are stopped and there is no more pending task. 461 VMRuntime.getRuntime().runHeapTasks(); 462 } 463 } 464} 465