Merge "Add missing SO_FLOW_SLA changes"
diff --git a/luni/src/test/java/libcore/java/lang/ThreadTest.java b/luni/src/test/java/libcore/java/lang/ThreadTest.java
index 10ca9a7..be16938 100644
--- a/luni/src/test/java/libcore/java/lang/ThreadTest.java
+++ b/luni/src/test/java/libcore/java/lang/ThreadTest.java
@@ -17,6 +17,8 @@
 package libcore.java.lang;
 
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 import libcore.java.lang.ref.FinalizationTester;
@@ -179,6 +181,39 @@
         }
     }
 
+    // http://b/29746125
+    public void testParkUntilWithUnderflowValue() throws Exception {
+        final Thread current = Thread.currentThread();
+
+        // watchdog to unpark the tread in case it will be parked
+        AtomicBoolean afterPark = new AtomicBoolean(false);
+        AtomicBoolean wasParkedForLongTime = new AtomicBoolean(false);
+        Thread watchdog = new Thread() {
+            @Override public void run() {
+                try {
+                    sleep(5000);
+                } catch(InterruptedException expected) {}
+
+                if (!afterPark.get()) {
+                    wasParkedForLongTime.set(true);
+                    current.unpark$();
+                }
+            }
+        };
+        watchdog.start();
+
+        // b/29746125 is caused by underflow: parkUntilArg - System.currentTimeMillis() > 0.
+        // parkUntil$ should return immediately for everyargument that's <=
+        // System.currentTimeMillis().
+        current.parkUntil$(Long.MIN_VALUE);
+        if (wasParkedForLongTime.get()) {
+            fail("Current thread was parked, but was expected to return immediately");
+        }
+        afterPark.set(true);
+        watchdog.interrupt();
+        watchdog.join();
+    }
+
     // This method returns {@code null} if all tests pass, or a non-null String containing
     // failure details if an error occured.
     private static native String nativeTestNativeThreadNames();
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index cff47dc..f0e9a78 100644
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -2183,11 +2183,18 @@
          * spuriously return for any reason, and this situation
          * can safely be construed as just such a spurious return.
          */
-        long delayMillis = time - System.currentTimeMillis();
-
-        if (delayMillis <= 0) {
+        final long currentTime = System.currentTimeMillis();
+        if (time <= currentTime) {
             parkState = ParkState.UNPARKED;
         } else {
+            long delayMillis = time - currentTime;
+            // Long.MAX_VALUE / NANOS_PER_MILLI (0x8637BD05SF6) is the largest
+            // long value that won't overflow to negative value when
+            // multiplyed by NANOS_PER_MILLI (10^6).
+            long maxValue = (Long.MAX_VALUE / NANOS_PER_MILLI);
+            if (delayMillis > maxValue) {
+                delayMillis = maxValue;
+            }
             parkFor$(delayMillis * NANOS_PER_MILLI);
         }
         }