Merge "Use nanoTime() in finalizer watchdog"
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index 568614f..6e05cea 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -310,7 +310,7 @@
 
         private boolean needToWork = true;  // Only accessed in synchronized methods.
 
-        private long finalizerTimeoutMs = 0;  // Lazily initialized.
+        private long finalizerTimeoutNs = 0;  // Lazily initialized.
 
         FinalizerWatchdogDaemon() {
             super("FinalizerWatchdogDaemon");
@@ -370,17 +370,22 @@
         }
 
         /**
-         * Sleep for the given number of milliseconds.
+         * Sleep for the given number of nanoseconds, or slightly longer.
          * @return false if we were interrupted.
          */
-        private boolean sleepForMillis(long durationMillis) {
-            long startMillis = System.currentTimeMillis();
+        private boolean sleepForNanos(long durationNanos) {
+            // It's important to base this on nanoTime(), not currentTimeMillis(), since
+            // the former stops counting when the processor isn't running.
+            long startNanos = System.nanoTime();
             while (true) {
-                long elapsedMillis = System.currentTimeMillis() - startMillis;
-                long sleepMillis = durationMillis - elapsedMillis;
-                if (sleepMillis <= 0) {
+                long elapsedNanos = System.nanoTime() - startNanos;
+                long sleepNanos = durationNanos - elapsedNanos;
+                if (sleepNanos <= 0) {
                     return true;
                 }
+                // Ensure the nano time is always rounded up to the next whole millisecond,
+                // ensuring the delay is >= the requested delay.
+                long sleepMillis = (sleepNanos + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
                 try {
                     Thread.sleep(sleepMillis);
                 } catch (InterruptedException e) {
@@ -403,14 +408,15 @@
          * null.  Only called from a single thread.
          */
         private Object waitForFinalization() {
-            if (finalizerTimeoutMs == 0) {
-                finalizerTimeoutMs = VMRuntime.getRuntime().getFinalizerTimeoutMs();
+            if (finalizerTimeoutNs == 0) {
+                finalizerTimeoutNs =
+                        NANOS_PER_MILLI * VMRuntime.getRuntime().getFinalizerTimeoutMs();
                 // Temporary app backward compatibility. Remove eventually.
-                MAX_FINALIZE_NANOS = NANOS_PER_MILLI * finalizerTimeoutMs;
+                MAX_FINALIZE_NANOS = finalizerTimeoutNs;
             }
             long startCount = FinalizerDaemon.INSTANCE.progressCounter.get();
             // Avoid remembering object being finalized, so as not to keep it alive.
-            if (!sleepForMillis(finalizerTimeoutMs)) {
+            if (!sleepForNanos(finalizerTimeoutNs)) {
                 // Don't report possibly spurious timeout if we are interrupted.
                 return null;
             }
@@ -431,7 +437,7 @@
                 // just finished as we were timing out, in which case we may get null or a later
                 // one.  In this last case, we are very likely to discard it below.
                 Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject;
-                sleepForMillis(500);
+                sleepForNanos(500 * NANOS_PER_MILLI);
                 // Recheck to make it even less likely we report the wrong finalizing object in
                 // the case which a very slow finalization just finished as we were timing out.
                 if (getNeedToWork()