Merge "Remove conflicting package infromation for java.security packages"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 97e94f8..5955f27 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -101,10 +101,7 @@
 LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs)
 LOCAL_NO_STANDARD_LIBRARIES := true
 LOCAL_JAVACFLAGS := $(local_javac_flags)
-# TODO(oth): Remove --min-sdk-version=26 when the O SDK version is determined.
-# For now it represents the minimum sdk version required for invoke-polymorphic.
-# This is only needed when ANDROID_COMPILE_WITH_JACK=false (b/36118520).
-LOCAL_DX_FLAGS := --core-library --min-sdk-version=26
+LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-oj
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..72d7fb4
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+nfuller@google.com
+pszczepaniak@google.com
+android-libcore-team+review@google.com
diff --git a/expectations/virtualdeviceknownfailures.txt b/expectations/virtualdeviceknownfailures.txt
index 54d0d64..300bfde 100644
--- a/expectations/virtualdeviceknownfailures.txt
+++ b/expectations/virtualdeviceknownfailures.txt
@@ -12,5 +12,15 @@
   description: "Virtual devices do not implement the SELinux policy (forbid hard link) asserted by this test",
   name: "libcore.java.nio.file.Files2Test#test_createLink",
   bug: 35670953
+},
+{
+  description: "multicast not supported in virtual device testing infra",
+  names: ["org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_InetAddress_IPv4",
+          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4_nullInterface",
+          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_InetAddress_IPv4",
+          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_sendLjava_net_DatagramPacketB_IPv4",
+          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv4"
+          ],
+  bug: 35922755
 }
 ]
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index adad301..20a4a47 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -521,6 +521,9 @@
     public static final int TCP_NODELAY = placeholder();
     public static final int TCP_USER_TIMEOUT = placeholder();
     /** @hide */ public static final int TIOCOUTQ = placeholder();
+    /** @hide */ public static final int UDP_ENCAP = placeholder();
+    /** @hide */ public static final int UDP_ENCAP_ESPINUDP_NON_IKE = placeholder();
+    /** @hide */ public static final int UDP_ENCAP_ESPINUDP = placeholder();
     /** @hide */ public static final int UNIX_PATH_MAX = placeholder();
     public static final int WCONTINUED = placeholder();
     public static final int WEXITED = placeholder();
diff --git a/luni/src/main/java/libcore/icu/TimeZoneNames.java b/luni/src/main/java/libcore/icu/TimeZoneNames.java
index 917d9ce..68e6e30 100644
--- a/luni/src/main/java/libcore/icu/TimeZoneNames.java
+++ b/luni/src/main/java/libcore/icu/TimeZoneNames.java
@@ -43,15 +43,6 @@
     public static final int NAME_COUNT = 5;
 
     private static final ZoneStringsCache cachedZoneStrings = new ZoneStringsCache();
-    static {
-        // Ensure that we pull in the zone strings for the root locale, en_US, and the
-        // user's default locale. (All devices must support the root locale and en_US,
-        // and they're used for various system things like HTTP headers.) Pre-populating
-        // the cache is especially useful on Android because we'll share this via the Zygote.
-        cachedZoneStrings.get(Locale.ROOT);
-        cachedZoneStrings.get(Locale.US);
-        cachedZoneStrings.get(Locale.getDefault());
-    }
 
     public static class ZoneStringsCache extends BasicLruCache<Locale, String[][]> {
         public ZoneStringsCache() {
@@ -71,6 +62,7 @@
             fillZoneStrings(locale.toLanguageTag(), result);
             long nativeEnd = System.nanoTime();
 
+            addOffsetStrings(result);
             internStrings(result);
             // Ending up in this method too often is an easy way to make your app slow, so we ensure
             // it's easy to tell from the log (a) what we were doing, (b) how long it took, and
@@ -83,8 +75,33 @@
             return result;
         }
 
+        /**
+         * Generate offset strings for cases where we don't have a name. Note that this is a
+         * potentially slow operation, as we need to load the timezone data for all affected
+         * time zones.
+         */
+        private void addOffsetStrings(String[][] result) {
+            for (int i = 0; i < result.length; ++i) {
+                TimeZone tz = null;
+                for (int j = 1; j < NAME_COUNT; ++j) {
+                    if (result[i][j] != null) {
+                        continue;
+                    }
+                    if (tz == null) {
+                        tz = TimeZone.getTimeZone(result[i][0]);
+                    }
+                    int offsetMillis = tz.getRawOffset();
+                    if (j == LONG_NAME_DST || j == SHORT_NAME_DST) {
+                        offsetMillis += tz.getDSTSavings();
+                    }
+                    result[i][j] = TimeZone.createGmtOffsetString(
+                            /* includeGmt */ true, /*includeMinuteSeparator */true, offsetMillis);
+                }
+            }
+        }
+
         // De-duplicate the strings (http://b/2672057).
-        private synchronized void internStrings(String[][] result) {
+        private void internStrings(String[][] result) {
             HashMap<String, String> internTable = new HashMap<String, String>();
             for (int i = 0; i < result.length; ++i) {
                 for (int j = 1; j < NAME_COUNT; ++j) {
diff --git a/luni/src/main/java/libcore/net/MimeUtils.java b/luni/src/main/java/libcore/net/MimeUtils.java
index b746273..693b6da 100644
--- a/luni/src/main/java/libcore/net/MimeUtils.java
+++ b/luni/src/main/java/libcore/net/MimeUtils.java
@@ -51,8 +51,7 @@
         add("application/mathematica", "nb");
         add("application/msaccess", "mdb");
         add("application/oda", "oda");
-        add("application/ogg", "ogg");
-        add("application/ogg", "oga");
+        add("application/ogg", "ogx");
         add("application/pdf", "pdf");
         add("application/pgp-keys", "key");
         add("application/pgp-signature", "pgp");
@@ -240,6 +239,9 @@
         add("audio/mpeg", "mp2");
         add("audio/mpeg", "m4a");
         add("audio/mpegurl", "m3u");
+        add("audio/ogg", "oga");
+        add("audio/ogg", "ogg");
+        add("audio/ogg", "spx");
         add("audio/prs.sid", "sid");
         add("audio/x-aiff", "aif");
         add("audio/x-aiff", "aiff");
@@ -372,6 +374,7 @@
         add("video/mpeg", "mpe");
         add("video/mp4", "mp4");
         add("video/mpeg", "VOB");
+        add("video/ogg", "ogv");
         add("video/quicktime", "qt");
         add("video/quicktime", "mov");
         add("video/vnd.mpegurl", "mxu");
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index 3ae4af6..a517475 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -47,6 +47,9 @@
 #include <linux/if_addr.h>
 #include <linux/rtnetlink.h>
 
+// Include linux socket constants for setting sockopts
+#include <linux/udp.h>
+
 #include <net/if.h> // After <sys/socket.h> to work around a Mac header file bug.
 
 #if defined(__BIONIC__)
@@ -577,6 +580,9 @@
     initConstant(env, c, "TCP_USER_TIMEOUT", TCP_USER_TIMEOUT);
 #endif
     initConstant(env, c, "TIOCOUTQ", TIOCOUTQ);
+    initConstant(env, c, "UDP_ENCAP", UDP_ENCAP);
+    initConstant(env, c, "UDP_ENCAP_ESPINUDP_NON_IKE", UDP_ENCAP_ESPINUDP_NON_IKE);
+    initConstant(env, c, "UDP_ENCAP_ESPINUDP", UDP_ENCAP_ESPINUDP);
     // UNIX_PATH_MAX is mentioned in some versions of unix(7), but not actually declared.
     initConstant(env, c, "UNIX_PATH_MAX", sizeof(sockaddr_un::sun_path));
     initConstant(env, c, "WCONTINUED", WCONTINUED);
diff --git a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
index b85f69a..c199bca 100644
--- a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
@@ -264,11 +264,6 @@
                 assertEquals(0, Libcore.os.lseek(fis.getFD(), 0, OsConstants.SEEK_CUR));
                 assertEquals(lastByte, fis.skip(lastByte));
             }
-
-            FileInputStream fis = new FileInputStream(largeFile);
-            long lastByte = 3 * 1024 * 1024 * 1024L - 1;
-            assertEquals(0, Libcore.os.lseek(fis.getFD(), 0, OsConstants.SEEK_CUR));
-            assertEquals(lastByte, fis.skip(lastByte));
         } finally {
             // Proactively cleanup - it's a pretty large file.
             assertTrue(largeFile.delete());
diff --git a/luni/src/test/java/libcore/java/lang/LambdaImplementationTest.java b/luni/src/test/java/libcore/java/lang/LambdaImplementationTest.java
index d32fa20..0161c6a 100644
--- a/luni/src/test/java/libcore/java/lang/LambdaImplementationTest.java
+++ b/luni/src/test/java/libcore/java/lang/LambdaImplementationTest.java
@@ -27,6 +27,7 @@
 import java.io.Serializable;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -35,18 +36,22 @@
 
 public class LambdaImplementationTest extends TestCase {
 
-    private static final String MSG = "Hello World";
+    private static final String STATIC_METHOD_RESPONSE = "StaticMethodResponse";
 
     public void testNonCapturingLambda() throws Exception {
-        Callable<String> r1 = () -> MSG;
+        Callable<String> r1 = () -> "Hello World";
         assertGeneralLambdaClassCharacteristics(r1);
         assertLambdaImplementsInterfaces(r1, Callable.class);
         assertLambdaMethodCharacteristics(r1, Callable.class);
         assertNonSerializableLambdaCharacteristics(r1);
-        assertCallableBehavior(r1, MSG);
+        assertCallableBehavior(r1, "Hello World");
 
-        Callable<String> r2 = () -> MSG;
-        assertMultipleInstanceCharacteristics(r1, r2);
+        List<Callable<String>> callables = new ArrayList<>();
+        for (int i = 0; i < 2; i++) {
+            callables.add(() -> "Hello World");
+        }
+        assertMultipleDefinitionCharacteristics(r1, callables.get(0));
+        assertMultipleInstanceCharacteristics(callables.get(0), callables.get(1));
     }
 
     interface Condition<T> {
@@ -83,65 +88,96 @@
         assertLambdaMethodCharacteristics(r1, Callable.class);
         assertNonSerializableLambdaCharacteristics(r1);
 
-        assertCallableBehavior(r1, MSG);
+        assertCallableBehavior(r1, STATIC_METHOD_RESPONSE);
 
-        Callable<String> r2 = LambdaImplementationTest::staticMethod;
-        assertMultipleInstanceCharacteristics(r1, r2);
+        List<Callable<String>> callables = new ArrayList<>();
+        for (int i = 0; i < 2; i++) {
+            callables.add(LambdaImplementationTest::staticMethod);
+        }
+        assertMultipleDefinitionCharacteristics(r1, callables.get(0));
+        assertMultipleInstanceCharacteristics(callables.get(0), callables.get(1));
     }
 
     public void testObjectMethodReferenceLambda() throws Exception {
-        StringBuilder o = new StringBuilder(MSG);
+        String msg = "Hello";
+        StringBuilder o = new StringBuilder(msg);
         Callable<String> r1 = o::toString;
         assertGeneralLambdaClassCharacteristics(r1);
         assertLambdaImplementsInterfaces(r1, Callable.class);
         assertLambdaMethodCharacteristics(r1, Callable.class);
         assertNonSerializableLambdaCharacteristics(r1);
 
-        assertCallableBehavior(r1, MSG);
+        assertCallableBehavior(r1, msg);
 
-        Callable<String> r2 = o::toString;
-        assertMultipleInstanceCharacteristics(r1, r2);
+        List<Callable<String>> callables = new ArrayList<>();
+        for (int i = 0; i < 2; i++) {
+            callables.add(o::toString);
+        }
+        assertMultipleDefinitionCharacteristics(r1, callables.get(0));
+        assertMultipleInstanceCharacteristics(callables.get(0), callables.get(1));
     }
 
     public void testArgumentCapturingLambda() throws Exception {
-        String msg = MSG;
+        checkArgumentCapturingLambda("Argument");
+    }
+
+    private void checkArgumentCapturingLambda(String msg) throws Exception {
         Callable<String> r1 = () -> msg;
         assertGeneralLambdaClassCharacteristics(r1);
         assertLambdaImplementsInterfaces(r1, Callable.class);
         assertLambdaMethodCharacteristics(r1, Callable.class);
         assertNonSerializableLambdaCharacteristics(r1);
 
-        assertCallableBehavior(r1, MSG);
+        assertCallableBehavior(r1, msg);
 
-        Callable<String> r2 = () -> msg;
-        assertMultipleInstanceCharacteristics(r1, r2);
+        List<Callable<String>> callables = new ArrayList<>();
+        for (int i = 0; i < 2; i++) {
+            callables.add(() -> msg);
+        }
+        assertMultipleDefinitionCharacteristics(r1, callables.get(0));
+        assertMultipleInstanceCharacteristics(callables.get(0), callables.get(1));
     }
 
     public void testSerializableLambda_withoutState() throws Exception {
-        Callable<String> r1 = (Callable<String> & Serializable) () -> MSG;
+        Callable<String> r1 = (Callable<String> & Serializable) () -> "No State";
         assertGeneralLambdaClassCharacteristics(r1);
         assertLambdaImplementsInterfaces(r1, Callable.class, Serializable.class);
         assertLambdaMethodCharacteristics(r1, Callable.class);
         assertSerializableLambdaCharacteristics(r1);
 
-        assertCallableBehavior(r1, MSG);
+        assertCallableBehavior(r1, "No State");
 
-        Callable<String> r2 = (Callable<String> & Serializable) () -> MSG;
-        assertMultipleInstanceCharacteristics(r1, r2);
+        List<Callable<String>> callables = new ArrayList<>();
+        for (int i = 0; i < 2; i++) {
+            Callable<String> callable = (Callable<String> & Serializable) () -> "No State";
+            assertLambdaImplementsInterfaces(callable, Callable.class, Serializable.class);
+            callables.add(callable);
+        }
+        assertMultipleDefinitionCharacteristics(r1, callables.get(0));
+        assertMultipleInstanceCharacteristics(callables.get(0), callables.get(1));
     }
 
     public void testSerializableLambda_withState() throws Exception {
-        final int state = 123;
-        Callable<String> r1 = (Callable<String> & Serializable) () -> MSG + state;
+        final long state = System.currentTimeMillis();
+        Callable<String> r1 = (Callable<String> & Serializable) () -> "State:" + state;
         assertGeneralLambdaClassCharacteristics(r1);
         assertLambdaImplementsInterfaces(r1, Callable.class, Serializable.class);
         assertLambdaMethodCharacteristics(r1, Callable.class);
         assertSerializableLambdaCharacteristics(r1);
 
-        assertCallableBehavior(r1, MSG + state);
+        assertCallableBehavior(r1, "State:" + state);
 
         Callable<String> deserializedR1 = roundtripSerialization(r1);
         assertEquals(r1.call(), deserializedR1.call());
+
+        List<Callable<String>> callables = new ArrayList<>();
+        for (int i = 0; i < 2; i++) {
+            Callable<String> callable = (Callable<String> & Serializable) () -> "State:" + state;
+            assertLambdaImplementsInterfaces(callable, Callable.class, Serializable.class);
+            callables.add(callable);
+        }
+        assertMultipleDefinitionCharacteristics(r1, callables.get(0));
+        assertMultipleInstanceCharacteristics(callables.get(0), callables.get(1));
     }
 
     public void testBadSerializableLambda() throws Exception {
@@ -159,14 +195,25 @@
     }
 
     public void testMultipleInterfaceLambda() throws Exception {
-        Callable<String> r1 = (Callable<String> & MarkerInterface) () -> MSG;
+        Callable<String> r1 = (Callable<String> & MarkerInterface) () -> "MultipleInterfaces";
         assertTrue(r1 instanceof MarkerInterface);
         assertGeneralLambdaClassCharacteristics(r1);
         assertLambdaMethodCharacteristics(r1, Callable.class);
         assertLambdaImplementsInterfaces(r1, Callable.class, MarkerInterface.class);
         assertNonSerializableLambdaCharacteristics(r1);
 
-        assertCallableBehavior(r1, MSG);
+        assertCallableBehavior(r1, "MultipleInterfaces");
+
+        List<Callable<String>> callables = new ArrayList<>();
+        for (int i = 0; i < 2; i++) {
+            Callable<String> callable =
+                    (Callable<String> & MarkerInterface) () -> "MultipleInterfaces";
+            assertLambdaImplementsInterfaces(callable, Callable.class, MarkerInterface.class);
+            callables.add(callable);
+        }
+        assertLambdaImplementsInterfaces(r1, Callable.class, MarkerInterface.class);
+        assertMultipleDefinitionCharacteristics(r1, callables.get(0));
+        assertMultipleInstanceCharacteristics(callables.get(0), callables.get(1));
     }
 
     private static void assertSerializableLambdaCharacteristics(Object r1) throws Exception {
@@ -248,8 +295,15 @@
         }
     }
 
-    private static void assertMultipleInstanceCharacteristics(Object r1, Object r2)
-            throws Exception {
+    /**
+     * Asserts that necessary conditions hold when there are two lambdas with separate but identical
+     * definitions.
+     */
+    private static void assertMultipleDefinitionCharacteristics(
+            Callable<String> r1, Callable<String> r2) throws Exception {
+
+        // Sanity check that the lambdas do the same thing.
+        assertEquals(r1.call(), r2.call());
 
         // Unclear if any of this is *guaranteed* to be true.
 
@@ -258,10 +312,23 @@
         assertNotSame(r1, r2);
         assertTrue(!r1.equals(r2));
 
-        // Confirm the classes differ.
-        Class<?> lambda1Class = r1.getClass();
-        Class<?> lambda2Class = r2.getClass();
-        assertNotSame(lambda1Class, lambda2Class);
+        // Two lambdas from different definitions can share the same class or may not.
+        // See JLS 15.27.4.
+    }
+
+    /**
+     * Asserts that necessary conditions hold when there are two lambdas created from the same
+     * definition.
+     */
+    private static void assertMultipleInstanceCharacteristics(
+            Callable<String> r1, Callable<String> r2) throws Exception {
+
+        // Sanity check that the lambdas do the same thing.
+        assertEquals(r1.call(), r2.call());
+
+        // There doesn't appear to be anything else that is safe to assert here. Two lambdas
+        // created from the same definition can be the same, as can their class, but they can also
+        // be different. See JLS 15.27.4.
     }
 
     private static void assertGeneralLambdaClassCharacteristics(Object r1) throws Exception {
@@ -333,7 +400,7 @@
     }
 
     private static String staticMethod() {
-        return MSG;
+        return STATIC_METHOD_RESPONSE;
     }
 
     private interface MarkerInterface {
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
index 9bf02ef..5866ae4 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
@@ -1924,4 +1924,417 @@
             MethodType.methodType(void.class, MethodHandle.class, String.class));
         invokeMultiThreaded(MethodHandles.insertArguments(mh, 0, adapter, "a: c+d ,b:c ,c:d ,d:e"));
     }
+
+    private static void checkBooleanCast_delegate(boolean expected, boolean z,  boolean b,
+                                                  boolean c, boolean s, boolean i, boolean j,
+                                                  boolean f, boolean d, boolean l) {
+        assertEquals(expected, z);
+        assertEquals(expected, b);
+        assertEquals(expected, c);
+        assertEquals(expected, s);
+        assertEquals(expected, i);
+        assertEquals(expected, j);
+        assertEquals(expected, f);
+        assertEquals(expected, d);
+        assertEquals(expected, l);
+    }
+
+    private static void checkByteCast_delegate(byte expected, byte z, byte b, byte c, byte s,
+                                               byte i, byte j, byte f, byte d, byte l) {
+        int mask = 0xff;
+        assertEquals(expected & 1, z);
+        assertEquals(expected, b);
+        assertEquals(expected, c & mask);
+        assertEquals(expected, s & mask);
+        assertEquals(expected, i & mask);
+        assertEquals(expected, j & mask);
+        assertEquals(expected, f & mask);
+        assertEquals(expected, d & mask);
+        assertEquals(expected, l);
+    }
+
+    private static void checkCharCast_delegate(char expected, char z, char b, char c, char s,
+                                               char i, char j, char f, char d, char l) {
+        int mask = 0xffff;
+        assertEquals(expected & 1, z);
+        assertEquals(expected & 0xff, b);
+        assertEquals(expected, c);
+        assertEquals(expected, s & mask);
+        assertEquals(expected, i & mask);
+        assertEquals(expected, j & mask);
+        assertEquals(expected, f & mask);
+        assertEquals(expected, d & mask);
+        assertEquals(expected, l);
+    }
+
+    private static void checkShortCast_delegate(short expected, short z, short b, short c, short s,
+                                                short i, short j, short f, short d, short l) {
+        int mask = 0xffff;
+        assertEquals(expected & 1, z);
+        assertEquals(expected & 0xff, b);
+        assertEquals(expected, c & mask);
+        assertEquals(expected, s);
+        assertEquals(expected, i & mask);
+        assertEquals(expected, j & mask);
+        assertEquals(expected, f & mask);
+        assertEquals(expected, d & mask);
+        assertEquals(expected, l);
+    }
+
+    private static void checkIntCast_delegate(int expected, int z, int b, int c, int s, int i,
+                                              int j, int f, int d, int l) {
+        int mask = 0xffffffff;
+        assertEquals(expected & 1, z);
+        assertEquals(expected & 0xff, b);
+        assertEquals(expected & 0xffff, c);
+        assertEquals(expected & 0xffff, s);
+        assertEquals(expected, i & mask);
+        assertEquals(expected, j & mask);
+        assertEquals(expected, f & mask);
+        assertEquals(expected, d & mask);
+        assertEquals(expected, l);
+    }
+
+    private static void checkLongCast_delegate(long expected, long z, long b, long c, long s,
+                                               long i, long j, long f, long d, long l) {
+        long mask = 0xffffffffl;
+        assertEquals(expected & 1, z);
+        assertEquals(expected & 0xff, b);
+        assertEquals(expected & 0xffff, c);
+        assertEquals(expected & 0xffff, s);
+        assertEquals(expected & mask, i & mask);
+        assertEquals(expected, j);
+        assertEquals(expected & mask, f & mask);
+        assertEquals(expected, d);
+        assertEquals(expected, l);
+    }
+
+    private static void checkFloatCast_delegate(float expected, float z, float b, float c, float s,
+                                                float i, float j, float f, float d, float l) {
+        assertEquals((byte) expected & 1, (int) z);
+        assertEquals((byte) expected, (int) b & 0xff);
+        assertEquals((char) expected & 0xffff, (int) c& 0xffff);
+        assertEquals((short) expected & 0xffff, (int) s & 0xffff);
+        assertEquals((int) expected, (int) i);
+        assertEquals((long) expected, (long) j);
+        assertEquals(expected, f);
+        assertEquals(expected, d);
+        assertEquals(expected, l);
+    }
+
+    private static void checkDoubleCast_delegate(double expected, double z, double b, double c,
+                                                 double s, double i, double j, double f, double d,
+                                                 double l) {
+        assertEquals((byte) expected & 1, (int) z);
+        assertEquals((byte) expected & 0xff, (int) b & 0xff);
+        assertEquals((int) expected & 0xffff, (int) c & 0xffff);
+        assertEquals((int) expected & 0xffff, (int) s & 0xffff);
+        assertEquals((int) expected, (int) i);
+        assertEquals((long) expected, (long) j);
+        assertEquals((float) expected, (float) f);
+        assertEquals(expected, d);
+        assertEquals(expected, l);
+    }
+
+    private static void checkBoxingCasts_delegate(boolean expected, Boolean z, Byte b, Character c,
+                                                  Short s, Integer i, Long j, Float f, Double d) {
+        int v = expected ? 1 : 0;
+        assertEquals(Boolean.valueOf(expected ? true : false), z);
+        assertEquals(Byte.valueOf((byte) v), b);
+        assertEquals(Character.valueOf((char) v), c);
+        assertEquals(Short.valueOf((short) v), s);
+        assertEquals(Integer.valueOf(v), i);
+        assertEquals(Long.valueOf(v), j);
+        assertEquals(Float.valueOf(v), f);
+        assertEquals(Double.valueOf(v), d);
+    }
+
+    public static void testExplicitCastArguments() throws Throwable {
+        MethodHandle target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkBooleanCast_delegate",
+            MethodType.methodType(void.class, boolean.class, boolean.class, boolean.class,
+                                  boolean.class, boolean.class, boolean.class, boolean.class,
+                                  boolean.class, boolean.class, boolean.class));
+        MethodHandle mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, boolean.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, Boolean.class));
+        mh.invokeExact(false, false, (byte) 0, (char) 0, (short) 0, 0, 0l, 0.0f, 0.0,
+                       Boolean.valueOf(false));
+        mh.invokeExact(false, false, (byte) 2, (char) 2, (short) 2, 2, 2l, 2.2f, 2.2,
+                       Boolean.valueOf(false));
+        mh.invokeExact(true, true, (byte) 1, (char) 1, (short) 1, 1, 1l, 1.0f, 1.0,
+                       Boolean.valueOf(true));
+        mh.invokeExact(true, true, (byte) 51, (char) 51, (short) 51, 51, 51l, 51.0f, 51.0,
+                       Boolean.valueOf(true));
+        MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, boolean.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, String.class));
+        try {
+            mh.invoke(true, true, (byte) 51, (char) 51, (short) 51, 51, 51l, 51.0f, 51.0,
+                      "ClassCastException here!");
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkByteCast_delegate",
+            MethodType.methodType(void.class, byte.class, byte.class, byte.class,
+                                  byte.class, byte.class, byte.class, byte.class,
+                                  byte.class, byte.class, byte.class));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, byte.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, Byte.class));
+        mh.invokeExact((byte) 0x5a, false, (byte) 0x5a, (char) 0x5a5a, (short) 0x5a5a, (int) 0x5a5a,
+                       (long) 0x5a5a, (float) 0x5a5a, (double) 0x5a5a, Byte.valueOf((byte) 0x5a));
+        try {
+            mh.invoke((byte) 0x5a, false, (byte) 0x5a, (char) 0x5a5a, (short) 0x5a5a, (int) 0x5a5a,
+                      (long) 0x5a5a, (float) 0x5a5a, (double) 0x5a5a,
+                      Short.valueOf((short) 0x5a5a));
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkCharCast_delegate",
+            MethodType.methodType(void.class, char.class, char.class, char.class,
+                                  char.class, char.class, char.class, char.class,
+                                  char.class, char.class, char.class));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, char.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, Character.class));
+        mh.invokeExact((char) 0x5555, true, (byte) 0x5555, (char) 0x5555, (short) 0x5555,
+                       (int) 0x5555, (long) 0x5555, (float) 0x5555, (double) 0x5555,
+                       Character.valueOf((char) 0x5555));
+        try {
+            mh.invoke((char) 0x5555, false, (byte) 0x5555, (char) 0x5555, (short) 0x5555,
+                      (int) 0x5555, (long) 0x5555, (float) 0x5555, (double) 0x5555,
+                      Integer.valueOf((int) 0x5555));
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkShortCast_delegate",
+            MethodType.methodType(void.class, short.class, short.class, short.class,
+                                  short.class, short.class, short.class, short.class,
+                                  short.class, short.class, short.class));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, short.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, Short.class));
+        mh.invokeExact((short) 0x3773, true, (byte) 0x3773, (char) 0x3773, (short) 0x3773,
+                       (int) 0x3773, (long) 0x3773, (float) 0x3773, (double) 0x3773,
+                       Short.valueOf((short) 0x3773));
+        try {
+            mh.invoke((short) 0x3773, true, (byte) 0x3773, (char) 0x3773, (short) 0x3773,
+                      (int) 0x3773, (long) 0x3773, (float) 0x3773, (double) 0x3773,
+                      Long.valueOf((long) 0x3773));
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkIntCast_delegate",
+            MethodType.methodType(void.class, int.class, int.class, int.class,
+                                  int.class, int.class, int.class, int.class,
+                                  int.class, int.class, int.class));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, int.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, Integer.class));
+        mh.invokeExact((int) 0x3773470, false, (byte) 0x3773470, (char) 0x3773470,
+                       (short) 0x3773470, (int) 0x3773470, (long) 0x3773470, (float) 0x3773470,
+                       (double) 0x3773470, Integer.valueOf(0x3773470));
+        try {
+            mh.invoke((int) 0x3773470, false, (byte) 0x3773470, (char) 0x3773470,
+                      (short) 0x3773470, (int) 0x3773470, (long) 0x3773470, (float) 0x3773470,
+                      (double) 0x3773470, Long.valueOf((long) 0x3773470));
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkLongCast_delegate",
+            MethodType.methodType(void.class, long.class, long.class, long.class,
+                                  long.class, long.class, long.class, long.class,
+                                  long.class, long.class, long.class));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, long.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, Long.class));
+        long longValue = 0x770000000l;
+        mh.invokeExact((long) longValue, false, (byte) longValue, (char) longValue,
+                       (short) longValue, (int) longValue, (long) longValue, (float) longValue,
+                       (double) longValue, Long.valueOf(longValue));
+        try {
+            mh.invoke((long) longValue, false, (byte) longValue, (char) longValue,
+                      (short) longValue, (int) longValue, (long) longValue, (float) longValue,
+                      (double) longValue, Integer.valueOf(3));
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkFloatCast_delegate",
+            MethodType.methodType(void.class, float.class, float.class, float.class,
+                                  float.class, float.class, float.class, float.class,
+                                  float.class, float.class, float.class));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, float.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, Float.class));
+        float floatValue = 33333.141f;
+        mh.invokeExact(floatValue, true, (byte) floatValue, (char) floatValue, (short) floatValue,
+                       (int) floatValue, (long) floatValue, floatValue, (double) floatValue,
+                       Float.valueOf(floatValue));
+        try {
+            mh.invoke(floatValue, true, (byte) floatValue, (char) floatValue,
+                      (short) floatValue, (int) floatValue, (long) floatValue, floatValue,
+                      (double) floatValue, Integer.valueOf((int) floatValue));
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkDoubleCast_delegate",
+            MethodType.methodType(void.class, double.class, double.class, double.class,
+                                  double.class, double.class, double.class, double.class,
+                                  double.class, double.class, double.class));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, double.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class, Double.class));
+        double doubleValue = 33333333333.141;
+        mh.invokeExact(doubleValue, true, (byte) doubleValue, (char) doubleValue,
+                       (short) doubleValue, (int) doubleValue, (long) doubleValue,
+                       (float) doubleValue, doubleValue, Double.valueOf(doubleValue));
+        try {
+            mh.invoke(doubleValue, true, (byte) doubleValue, (char) doubleValue,
+                      (short) doubleValue, (int) doubleValue, (long) doubleValue,
+                      (float) doubleValue, (double) doubleValue,
+                      Integer.valueOf((int) doubleValue));
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkBoxingCasts_delegate",
+            MethodType.methodType(void.class, boolean.class, Boolean.class, Byte.class,
+                                  Character.class, Short.class, Integer.class, Long.class,
+                                  Float.class, Double.class));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, boolean.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class));
+        mh.invokeExact(false, false, (byte) 0, (char) 0, (short) 0, 0, 0l, 0.0f, 0.0);
+        mh.invokeExact(true, true, (byte) 1, (char) 1, (short) 1, 1, 1l, 1.0f, 1.0);
+        mh.invoke(Boolean.valueOf(false), Boolean.valueOf(false), Byte.valueOf((byte) 0),
+                  Character.valueOf((char) 0), Short.valueOf((short) 0), Integer.valueOf(0),
+                  Long.valueOf(0l), Float.valueOf(0.0f), Double.valueOf(0.0));
+        mh.invoke(Boolean.valueOf(true), Boolean.valueOf(true), Byte.valueOf((byte) 1),
+                  Character.valueOf((char) 1), Short.valueOf((short) 1), Integer.valueOf(1),
+                  Long.valueOf(1l), Float.valueOf(1.0f), Double.valueOf(1.0));
+        mh = MethodHandles.explicitCastArguments(
+            target, MethodType.methodType(void.class, double.class, boolean.class, byte.class,
+                                          char.class, short.class, int.class, long.class,
+                                          float.class, double.class));
+        mh.invokeExact(0.0, false, (byte) 0, (char) 0, (short) 0, 0, 0l, 0.0f, 0.0);
+    }
+
+    static void returnVoid() {}
+
+    static boolean returnBoolean(boolean b) { return b; }
+
+    static Boolean returnBooleanObject(boolean b) { return b; }
+
+    public static void testExplicitCastReturnValues() throws Throwable {
+        MethodHandle target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "returnVoid", MethodType.methodType(void.class));
+        assertEquals(false,
+                     MethodHandles
+                     .explicitCastArguments(target, MethodType.methodType(boolean.class))
+                     .invoke());
+        assertEquals(null,
+                     MethodHandles
+                     .explicitCastArguments(target, MethodType.methodType(Boolean.class))
+                     .invoke());
+        assertEquals(0l,
+                     MethodHandles
+                     .explicitCastArguments(target, MethodType.methodType(long.class))
+                     .invoke());
+        assertEquals(null,
+                     MethodHandles
+                     .explicitCastArguments(target, MethodType.methodType(Long.class))
+                     .invoke());
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "returnBoolean",
+            MethodType.methodType(boolean.class, boolean.class));
+        assertEquals(false,
+                     MethodHandles
+                     .explicitCastArguments(target,
+                                            MethodType.methodType(boolean.class, boolean.class))
+                     .invoke(false));
+        assertEquals(true,
+                     MethodHandles
+                     .explicitCastArguments(target,
+                                            MethodType.methodType(boolean.class, boolean.class))
+                     .invoke(true));
+        assertEquals(Boolean.valueOf(false),
+                     MethodHandles
+                     .explicitCastArguments(target,
+                                            MethodType.methodType(Boolean.class, boolean.class))
+                     .invoke(false));
+        assertEquals(Boolean.valueOf(true),
+                     MethodHandles
+                     .explicitCastArguments(target,
+                                            MethodType.methodType(Boolean.class, boolean.class))
+                     .invoke(true));
+        assertEquals((byte) 0,
+                     MethodHandles
+                     .explicitCastArguments(target,
+                                            MethodType.methodType(byte.class, boolean.class))
+                     .invoke(false));
+        assertEquals((byte) 1,
+                     MethodHandles
+                     .explicitCastArguments(target,
+                                            MethodType.methodType(byte.class, boolean.class))
+                     .invoke(true));
+        try {
+            assertEquals(Byte.valueOf((byte) 0),
+                         MethodHandles
+                         .explicitCastArguments(target,
+                                                MethodType.methodType(Byte.class, boolean.class))
+                         .invoke(false));
+            fail();
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            assertEquals(Byte.valueOf((byte) 1),
+                         MethodHandles
+                         .explicitCastArguments(target,
+                                                MethodType.methodType(Byte.class, boolean.class))
+                         .invoke(true));
+        } catch (ClassCastException e) {
+        }
+
+        target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "returnBooleanObject",
+            MethodType.methodType(Boolean.class, boolean.class));
+        assertEquals(false,
+                     (boolean) MethodHandles
+                     .explicitCastArguments(target,
+                                            MethodType.methodType(boolean.class, boolean.class))
+                     .invokeExact(false));
+        assertEquals(true,
+                     (boolean) MethodHandles
+                     .explicitCastArguments(target,
+                                            MethodType.methodType(boolean.class, boolean.class))
+                     .invokeExact(true));
+    }
 }
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java
index aa14bd3..cb49aef 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java
@@ -114,6 +114,8 @@
 
         void singleAnnotation(@Repeated(1) String p0) {}
 
+        static void staticSingleAnnotation(@Repeated(1) String p0) {}
+
         static Method getMethodWithoutAnnotations() throws Exception {
             return AnnotatedMethodClass.class.getDeclaredMethod("noAnnotation", String.class);
         }
@@ -135,6 +137,20 @@
         static Method getMethodSingleAnnotation() throws Exception {
             return AnnotatedMethodClass.class.getDeclaredMethod("singleAnnotation", String.class);
         }
+
+        static Method getMethodStaticSingleAnnotation() throws Exception {
+            return AnnotatedMethodClass.class.getDeclaredMethod("staticSingleAnnotation",
+                    String.class);
+        }
+    }
+
+    private static abstract class AnnotatedMethodAbstractClass {
+        abstract void abstractSingleAnnotation(@Repeated(1) String p0);
+
+        static Method getMethodAbstractSingleAnnotation() throws Exception {
+            return AnnotatedMethodAbstractClass.class.getDeclaredMethod(
+                    "abstractSingleAnnotation", String.class);
+        }
     }
 
     // Tests for isAnnotationPresent and getDeclaredAnnotation.
@@ -155,6 +171,12 @@
         checkParameter0DeclaredAnnotation(
                 AnnotatedMethodClass.getMethodSingleAnnotation(),
                 repeated, "@Repeated(1)");
+        checkParameter0DeclaredAnnotation(
+                AnnotatedMethodClass.getMethodStaticSingleAnnotation(),
+                repeated, "@Repeated(1)");
+        checkParameter0DeclaredAnnotation(
+                AnnotatedMethodAbstractClass.getMethodAbstractSingleAnnotation(),
+                repeated, "@Repeated(1)");
 
         Class<? extends Annotation> container = Container.class;
         checkParameter0DeclaredAnnotation(
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java
index a07f2b3..38d9899 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java
@@ -108,6 +108,8 @@
 
         void singleAnnotation(@Repeated(1) String p0) {}
 
+        static void staticSingleAnnotation(@Repeated(1) String p0) {}
+
         static Method getMethodWithoutAnnotations() throws Exception {
             return AnnotatedMethodClass.class.getDeclaredMethod("noAnnotation", String.class);
         }
@@ -129,8 +131,23 @@
         static Method getMethodSingleAnnotation() throws Exception {
             return AnnotatedMethodClass.class.getDeclaredMethod("singleAnnotation", String.class);
         }
+
+        static Method getMethodStaticSingleAnnotation() throws Exception {
+            return AnnotatedMethodClass.class.getDeclaredMethod("staticSingleAnnotation",
+                    String.class);
+        }
     }
 
+    private static abstract class AnnotatedMethodAbstractClass {
+        abstract void abstractSingleAnnotation(@Repeated(1) String p0);
+
+        static Method getMethodAbstractSingleAnnotation() throws Exception {
+            return AnnotatedMethodAbstractClass.class.getDeclaredMethod(
+                    "abstractSingleAnnotation", String.class);
+        }
+    }
+
+
     public void testMethodGetParameterAnnotations_repeated() throws Exception {
         assertParameter0Annotations(
                 AnnotatedMethodClass.getMethodWithoutAnnotations(), EXPECT_EMPTY);
@@ -146,6 +163,13 @@
         assertParameter0Annotations(
                 AnnotatedMethodClass.getMethodSingleAnnotation(),
                 "@Repeated(1)");
+        assertParameter0Annotations(
+                AnnotatedMethodClass.getMethodStaticSingleAnnotation(),
+                "@Repeated(1)");
+        assertParameter0Annotations(
+                AnnotatedMethodAbstractClass.getMethodAbstractSingleAnnotation(),
+                "@Repeated(1)");
+
     }
 
     private static class AnnotatedConstructorClass {
diff --git a/luni/src/test/java/libcore/java/net/SocketTest.java b/luni/src/test/java/libcore/java/net/SocketTest.java
index 50d8ce6..0bfd241 100644
--- a/luni/src/test/java/libcore/java/net/SocketTest.java
+++ b/luni/src/test/java/libcore/java/net/SocketTest.java
@@ -262,8 +262,11 @@
                 s.setTrafficClass(i);
 
                 // b/30909505
-                // Linux does not set ECN bits for STREAM sockets, so these bits should be zero.
-                assertEquals(i & ~INET_ECN_MASK, s.getTrafficClass());
+                // Linux does not set ECN bits for IP_TOS, but sets for IPV6_TCLASS. We should
+                // accept either output.
+                int actual = s.getTrafficClass();
+                assertTrue(i == actual || // IPV6_TCLASS
+                        (actual == (i & ~INET_ECN_MASK))); // IP_TOS: ECN bits should be 0
             }
         }
     }
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 375eb36..9f7267c 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -384,6 +384,18 @@
         }
     }
 
+    // http://b/33197219
+    public void testDisplayNameForNonCanonicalTimezones() {
+        TimeZone canonical = TimeZone.getTimeZone("Europe/London");
+        TimeZone nonCanonical = TimeZone.getTimeZone("GB");
+
+        // verify that GB is actually an alias for Europe/London
+        assertTrue(canonical.hasSameRules(nonCanonical));
+
+        assertEquals(canonical.getDisplayName(true, TimeZone.LONG, Locale.ENGLISH),
+                nonCanonical.getDisplayName(true, TimeZone.LONG, Locale.ENGLISH));
+    }
+
     // http://b/30937209
     public void testSetDefaultDeadlock() throws InterruptedException, BrokenBarrierException {
         // Since this tests a deadlock, the test has two fundamental problems:
diff --git a/luni/src/test/java/libcore/net/MimeUtilsTest.java b/luni/src/test/java/libcore/net/MimeUtilsTest.java
index ac0c017..af8f479 100644
--- a/luni/src/test/java/libcore/net/MimeUtilsTest.java
+++ b/luni/src/test/java/libcore/net/MimeUtilsTest.java
@@ -76,4 +76,13 @@
     assertEquals("video/3gpp2", MimeUtils.guessMimeTypeFromExtension("3gpp2"));
     assertEquals("video/3gpp2", MimeUtils.guessMimeTypeFromExtension("3g2"));
   }
+
+  public void test_37167977() {
+    // https://tools.ietf.org/html/rfc5334#section-10.1
+    assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("ogg"));
+    assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("oga"));
+    assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("spx"));
+    assertEquals("video/ogg", MimeUtils.guessMimeTypeFromExtension("ogv"));
+  }
+
 }
diff --git a/ojluni/src/main/java/java/io/Console.java b/ojluni/src/main/java/java/io/Console.java
index 2b4e4e6..b25759c 100644
--- a/ojluni/src/main/java/java/io/Console.java
+++ b/ojluni/src/main/java/java/io/Console.java
@@ -514,11 +514,10 @@
         }
     }
 
-    // Android-changed: Remove SharedSecrets setup and also the shutdown
-    // hook that's a no-op (but causes trouble when it's turned on).
+    // Android-removed: SharedSecrets setup and also the shutdown hook.
+    // The hook is a no-op (but causes trouble when it's turned on).
 
-    private static Console cons;
-
+    // Android-changed: Use @hide rather than sun.misc.SharedSecrets to expose console().
     /** @hide */
     public static Console console() {
         if (istty()) {
@@ -528,15 +527,16 @@
         }
         return null;
     }
-
+    private static Console cons;
     private native static boolean istty();
-
     private Console() {
+    // BEGIN Android-changed: Support custom in/out streams for testing.
       this(new FileInputStream(FileDescriptor.in), new FileOutputStream(FileDescriptor.out));
     }
 
     // Constructor for tests
     private Console(InputStream inStream, OutputStream outStream) {
+    // END Android-changed: Support custom in/out streams for testing.
         readLock = new Object();
         writeLock = new Object();
         String csname = encoding();
diff --git a/ojluni/src/main/java/java/io/DeleteOnExitHook.java b/ojluni/src/main/java/java/io/DeleteOnExitHook.java
index 447f038..e988f9b 100644
--- a/ojluni/src/main/java/java/io/DeleteOnExitHook.java
+++ b/ojluni/src/main/java/java/io/DeleteOnExitHook.java
@@ -36,11 +36,13 @@
 class DeleteOnExitHook {
     private static LinkedHashSet<String> files = new LinkedHashSet<>();
     static {
+        // BEGIN Android-changed: Use Runtime.addShutdownHook() rather than SharedSecrets.
         Runtime.getRuntime().addShutdownHook(new Thread() {
             public void run() {
                 runHooks();
             }
         });
+        // END Android-changed: Use Runtime.addShutdownHook() rather than SharedSecrets.
     }
 
     private DeleteOnExitHook() {}
diff --git a/ojluni/src/main/java/java/io/InterruptedIOException.java b/ojluni/src/main/java/java/io/InterruptedIOException.java
index e4ed419..25569dd 100644
--- a/ojluni/src/main/java/java/io/InterruptedIOException.java
+++ b/ojluni/src/main/java/java/io/InterruptedIOException.java
@@ -74,7 +74,7 @@
     public int bytesTransferred = 0;
 
     /** @hide */
-    // Android-added.
+    // Android-added: Additional constructor for internal use.
     public InterruptedIOException(Throwable cause) {
         super(cause);
     }
@@ -84,7 +84,7 @@
      *
      * @hide internal use only
      */
-    // Android-added.
+    // Android-added: Additional constructor for internal use.
     public InterruptedIOException(String detailMessage, Throwable cause) {
         super(detailMessage, cause);
     }
diff --git a/ojluni/src/main/java/java/io/Serializable.java b/ojluni/src/main/java/java/io/Serializable.java
index 96ea33c..496aef7 100644
--- a/ojluni/src/main/java/java/io/Serializable.java
+++ b/ojluni/src/main/java/java/io/Serializable.java
@@ -25,6 +25,7 @@
 
 package java.io;
 
+// Android-added: Notes about serialVersionUID, using serialization judiciously, JSON.
 /**
  * Serializability of a class is enabled by the class implementing the
  * java.io.Serializable interface. Classes that do not implement this
diff --git a/ojluni/src/main/java/java/io/SerializablePermission.java b/ojluni/src/main/java/java/io/SerializablePermission.java
index e11f3ee..93bb4aa 100644
--- a/ojluni/src/main/java/java/io/SerializablePermission.java
+++ b/ojluni/src/main/java/java/io/SerializablePermission.java
@@ -27,8 +27,9 @@
 
 import java.security.*;
 
+// Android-changed: Replaced with empty implementation and documented as legacy security code.
 /**
- * Legacy security code; do not use.
+ * This legacy security is not supported on Android. Do not use.
  */
 public final class SerializablePermission extends BasicPermission {
 
diff --git a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
index c67a0a4..cc24e96 100644
--- a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -153,7 +153,7 @@
             newCapacity = minCapacity;
         }
         return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
-           ? hugeCapacity(minCapacity)
+            ? hugeCapacity(minCapacity)
             : newCapacity;
     }
 
diff --git a/ojluni/src/main/java/java/lang/ArrayIndexOutOfBoundsException.java b/ojluni/src/main/java/java/lang/ArrayIndexOutOfBoundsException.java
index 756c684..9c85456 100644
--- a/ojluni/src/main/java/java/lang/ArrayIndexOutOfBoundsException.java
+++ b/ojluni/src/main/java/java/lang/ArrayIndexOutOfBoundsException.java
@@ -66,16 +66,16 @@
         super(s);
     }
 
+    // Android-added: Additional constructor for internal use.
     /**
-     * Used internally for consistent high-quality error reporting.
      * @hide
      */
     public ArrayIndexOutOfBoundsException(int sourceLength, int index) {
         super("length=" + sourceLength + "; index=" + index);
     }
 
+    // Android-added: Additional constructor for internal use.
     /**
-     * Used internally for consistent high-quality error reporting.
      * @hide
      */
     public ArrayIndexOutOfBoundsException(int sourceLength, int offset,
diff --git a/ojluni/src/main/java/java/lang/Byte.java b/ojluni/src/main/java/java/lang/Byte.java
index ba2f588..d0031d0 100644
--- a/ojluni/src/main/java/java/lang/Byte.java
+++ b/ojluni/src/main/java/java/lang/Byte.java
@@ -518,7 +518,7 @@
     /** use serialVersionUID from JDK 1.1. for interoperability */
     private static final long serialVersionUID = -7183698231559129828L;
 
-    // BEGIN Android-changed
+    // BEGIN Android-added: toHexString() for internal use.
     /**
      * @hide
      */
@@ -542,5 +542,5 @@
         'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
         'U', 'V', 'W', 'X', 'Y', 'Z'
     };
-    // END Android-changed
+    // END Android-added: toHexString() for internal use.
 }
diff --git a/ojluni/src/main/java/java/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index 6e8f74f..ef08be0 100644
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -989,7 +989,7 @@
         }
         p.put("os.version", info.release);
 
-        // Undocumented Android-only properties.
+        // Android-added: Undocumented properties that exist only on Android.
         p.put("android.icu.library.version", ICU.getIcuVersion());
         p.put("android.icu.unicode.version", ICU.getUnicodeVersion());
         p.put("android.icu.cldr.version", ICU.getCldrVersion());
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index a6301b5..0419ede 100644
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -1081,7 +1081,9 @@
         ThreadGroup g;
         checkAccess();
         if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
-            throw new IllegalArgumentException();
+            // Android-changed: Improve exception message when the new priority
+            // is out of bounds.
+            throw new IllegalArgumentException("Priority out of range: " + newPriority);
         }
         if((g = getThreadGroup()) != null) {
             if (newPriority > g.getMaxPriority()) {
diff --git a/ojluni/src/main/java/java/lang/invoke/CallSite.java b/ojluni/src/main/java/java/lang/invoke/CallSite.java
index b2226bf..85b4bb9 100644
--- a/ojluni/src/main/java/java/lang/invoke/CallSite.java
+++ b/ojluni/src/main/java/java/lang/invoke/CallSite.java
@@ -260,7 +260,7 @@
         }
     }
 
-    /* Android-changed: not used. */
+    // Android-changed: not used.
     // /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
     // /*package-private*/
     // static Empty uninitializedCallSite() {
@@ -292,7 +292,7 @@
         UNSAFE.putObjectVolatile(this, TARGET_OFFSET, newTarget);
     }
 
-    /* Android-changed: not used. */
+    // Android-changed: not used.
     // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
     // static CallSite makeSite(MethodHandle bootstrapMethod,
     //                          // Callee information:
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
index 6e414d0..94c9917 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
@@ -1978,22 +1978,18 @@
      * @throws NullPointerException if either argument is null
      * @throws WrongMethodTypeException if the conversion cannot be made
      * @see MethodHandle#asType
-     *
-     * @hide
      */
     public static
     MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
         explicitCastArgumentsChecks(target, newType);
         // use the asTypeCache when possible:
         MethodType oldType = target.type();
-        if (oldType == newType)  return target;
+        if (oldType == newType) return target;
         if (oldType.explicitCastEquivalentToAsType(newType)) {
             return target.asFixedArity().asType(newType);
         }
 
-        // return MethodHandleImpl.makePairwiseConvert(target, newType, false);
-        // TODO(narayan): Implement explicitCastArguments, remove @hide.
-        throw new UnsupportedOperationException("MethodHandles.explicitCastArguments is not implemented");
+        return new Transformers.ExplicitCastArguments(target, newType);
     }
 
     private static void explicitCastArgumentsChecks(MethodHandle target, MethodType newType) {
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodType.java b/ojluni/src/main/java/java/lang/invoke/MethodType.java
index 61e0675..bfa7ccd 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodType.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodType.java
@@ -870,18 +870,20 @@
      *  MHs.eCA has the following "upgrades" to MH.asType:
      *  1. interfaces are unchecked (that is, treated as if aliased to Object)
      *     Therefore, {@code Object->CharSequence} is possible in both cases but has different semantics
-     *  2. the full matrix of primitive-to-primitive conversions is supported
-     *     Narrowing like {@code long->byte} and basic-typing like {@code boolean->int}
-     *     are not supported by asType, but anything supported by asType is equivalent
-     *     with MHs.eCE.
+     *  2a. the full matrix of primitive-to-primitive conversions is supported
+     *      Narrowing like {@code long->byte} and basic-typing like {@code boolean->int}
+     *      are not supported by asType, but anything supported by asType is equivalent
+     *      with MHs.eCE.
+     *  2b. conversion of void->primitive means explicit cast has to insert zero/false/null.
      *  3a. unboxing conversions can be followed by the full matrix of primitive conversions
      *  3b. unboxing of null is permitted (creates a zero primitive value)
      * Other than interfaces, reference-to-reference conversions are the same.
      * Boxing primitives to references is the same for both operators.
      */
     private static boolean explicitCastEquivalentToAsType(Class<?> src, Class<?> dst) {
-        if (src == dst || dst == Object.class || dst == void.class)  return true;
-        if (src.isPrimitive()) {
+        if (src == dst || dst == Object.class || dst == void.class) {
+            return true;
+        } else if (src.isPrimitive() && src != void.class) {
             // Could be a prim/prim conversion, where casting is a strict superset.
             // Or a boxing conversion, which is always to an exact wrapper class.
             return canConvert(src, dst);
diff --git a/ojluni/src/main/java/java/lang/invoke/Transformers.java b/ojluni/src/main/java/java/lang/invoke/Transformers.java
index 82cc797..75ee192 100644
--- a/ojluni/src/main/java/java/lang/invoke/Transformers.java
+++ b/ojluni/src/main/java/java/lang/invoke/Transformers.java
@@ -22,6 +22,7 @@
 
 import dalvik.system.EmulatedStackFrame;
 import dalvik.system.EmulatedStackFrame.Range;
+import dalvik.system.EmulatedStackFrame.StackFrameAccessor;
 import dalvik.system.EmulatedStackFrame.StackFrameReader;
 import dalvik.system.EmulatedStackFrame.StackFrameWriter;
 import java.lang.reflect.Array;
@@ -742,11 +743,7 @@
                     case 'F': { o = reader.nextFloat(); break; }
                     case 'D': { o = reader.nextDouble(); break; }
                 }
-                if (o != null && !elementType.isAssignableFrom(o.getClass())) {
-                    throw new ClassCastException(
-                        o.getClass() + " not assignable to " + elementType);
-                }
-                Array.set(arityArray, i, o);
+                Array.set(arityArray, i, elementType.cast(o));
             }
             return arityArray;
         }
@@ -1765,4 +1762,409 @@
             calleeFrame.copyReturnValueTo(stackFrame);
         }
     }
+
+
+    /**
+     * Implements {@link java.lang.invokeMethodHandles#explicitCastArguments()}.
+     */
+    public static class ExplicitCastArguments extends Transformer {
+        private final MethodHandle target;
+
+        public ExplicitCastArguments(MethodHandle target, MethodType type) {
+            super(type);
+            this.target = target;
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+            // Create a new stack frame for the target.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+            explicitCastArguments(callerFrame, targetFrame);
+            target.invoke(targetFrame);
+            explicitCastReturnValue(callerFrame, targetFrame);
+        }
+
+        private void explicitCastArguments(final EmulatedStackFrame callerFrame,
+                                           final EmulatedStackFrame targetFrame) {
+            final StackFrameReader reader = new StackFrameReader();
+            reader.attach(callerFrame);
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(targetFrame);
+
+            final Class<?>[] fromTypes = type().ptypes();
+            final Class<?>[] toTypes = target.type().ptypes();
+            for (int i = 0; i < fromTypes.length; ++i) {
+                explicitCast(reader, fromTypes[i], writer, toTypes[i]);
+            }
+        }
+
+        private void explicitCastReturnValue(final EmulatedStackFrame callerFrame,
+                                             final EmulatedStackFrame targetFrame) {
+            Class<?> from = target.type().rtype();
+            Class<?> to = type().rtype();
+            if (to != void.class) {
+                final StackFrameWriter writer = new StackFrameWriter();
+                writer.attach(callerFrame);
+                writer.makeReturnValueAccessor();
+                if (from == void.class) {
+                    if (to.isPrimitive()) {
+                        unboxNull(writer, to);
+                    } else {
+                        writer.putNextReference(null, to);
+                    }
+                } else {
+                    final StackFrameReader reader = new StackFrameReader();
+                    reader.attach(targetFrame);
+                    reader.makeReturnValueAccessor();
+                    explicitCast(reader, target.type().rtype(), writer, type().rtype());
+                }
+            }
+        }
+
+        private static void throwUnexpectedType(final Class<?> unexpectedType) {
+            throw new InternalError("Unexpected type: " + unexpectedType);
+        }
+
+        private static void explicitCastFromBoolean(boolean fromValue,
+                                                    final StackFrameWriter writer,
+                                                    final Class<?> to) {
+            int value = fromValue ? 1 : 0;
+            if (to == byte.class) {
+                writer.putNextByte((byte) value);
+            } else if (to == char.class) {
+                writer.putNextChar((char) value);
+            } else if (to == short.class) {
+                writer.putNextShort((short) value);
+            } else if (to == int.class) {
+                writer.putNextInt(value);
+            } else if (to == long.class) {
+                writer.putNextLong(value);
+            } else if (to == float.class) {
+                writer.putNextFloat(value);
+            } else if (to == double.class) {
+                writer.putNextDouble(value);
+            } else {
+                throwUnexpectedType(to);
+            }
+        }
+
+        /**
+         * Converts byte value to boolean according to
+         * {@link java.lang.invoke.MethodHandles#explicitCast()}
+         */
+        private static boolean toBoolean(byte value) {
+            return (value & 1) == 1;
+        }
+
+        private static byte readPrimitiveAsByte(final StackFrameReader reader,
+                                                final Class<?> from) {
+            if (from == byte.class) {
+                return (byte) reader.nextByte();
+            } else if (from == char.class) {
+                return (byte) reader.nextChar();
+            } else if (from == short.class) {
+                return (byte) reader.nextShort();
+            } else if (from == int.class) {
+                return (byte) reader.nextInt();
+            } else if (from == long.class) {
+                return (byte) reader.nextLong();
+            } else if (from == float.class) {
+                return (byte) reader.nextFloat();
+            } else if (from == double.class) {
+                return (byte) reader.nextDouble();
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static char readPrimitiveAsChar(final StackFrameReader reader,
+                                                final Class<?> from) {
+            if (from == byte.class) {
+                return (char) reader.nextByte();
+            } else if (from == char.class) {
+                return (char) reader.nextChar();
+            } else if (from == short.class) {
+                return (char) reader.nextShort();
+            } else if (from == int.class) {
+                return (char) reader.nextInt();
+            } else if (from == long.class) {
+                return (char) reader.nextLong();
+            } else if (from == float.class) {
+                return (char) reader.nextFloat();
+            } else if (from == double.class) {
+                return (char) reader.nextDouble();
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static short readPrimitiveAsShort(final StackFrameReader reader,
+                                                  final Class<?> from) {
+            if (from == byte.class) {
+                return (short) reader.nextByte();
+            } else if (from == char.class) {
+                return (short) reader.nextChar();
+            } else if (from == short.class) {
+                return (short) reader.nextShort();
+            } else if (from == int.class) {
+                return (short) reader.nextInt();
+            } else if (from == long.class) {
+                return (short) reader.nextLong();
+            } else if (from == float.class) {
+                return (short) reader.nextFloat();
+            } else if (from == double.class) {
+                return (short) reader.nextDouble();
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static int readPrimitiveAsInt(final StackFrameReader reader,
+                                              final Class<?> from) {
+            if (from == byte.class) {
+                return (int) reader.nextByte();
+            } else if (from == char.class) {
+                return (int) reader.nextChar();
+            } else if (from == short.class) {
+                return (int) reader.nextShort();
+            } else if (from == int.class) {
+                return (int) reader.nextInt();
+            } else if (from == long.class) {
+                return (int) reader.nextLong();
+            } else if (from == float.class) {
+                return (int) reader.nextFloat();
+            } else if (from == double.class) {
+                return (int) reader.nextDouble();
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static long readPrimitiveAsLong(final StackFrameReader reader,
+                                                final Class<?> from) {
+            if (from == byte.class) {
+                return (long) reader.nextByte();
+            } else if (from == char.class) {
+                return (long) reader.nextChar();
+            } else if (from == short.class) {
+                return (long) reader.nextShort();
+            } else if (from == int.class) {
+                return (long) reader.nextInt();
+            } else if (from == long.class) {
+                return (long) reader.nextLong();
+            } else if (from == float.class) {
+                return (long) reader.nextFloat();
+            } else if (from == double.class) {
+                return (long) reader.nextDouble();
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static float readPrimitiveAsFloat(final StackFrameReader reader,
+                                                  final Class<?> from) {
+            if (from == byte.class) {
+                return (float) reader.nextByte();
+            } else if (from == char.class) {
+                return (float) reader.nextChar();
+            } else if (from == short.class) {
+                return (float) reader.nextShort();
+            } else if (from == int.class) {
+                return (float) reader.nextInt();
+            } else if (from == long.class) {
+                return (float) reader.nextLong();
+            } else if (from == float.class) {
+                return (float) reader.nextFloat();
+            } else if (from == double.class) {
+                return (float) reader.nextDouble();
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static double readPrimitiveAsDouble(final StackFrameReader reader,
+                                                    final Class<?> from) {
+            if (from == byte.class) {
+                return (double) reader.nextByte();
+            } else if (from == char.class) {
+                return (double) reader.nextChar();
+            } else if (from == short.class) {
+                return (double) reader.nextShort();
+            } else if (from == int.class) {
+                return (double) reader.nextInt();
+            } else if (from == long.class) {
+                return (double) reader.nextLong();
+            } else if (from == float.class) {
+                return (double) reader.nextFloat();
+            } else if (from == double.class) {
+                return (double) reader.nextDouble();
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static void explicitCastToBoolean(final StackFrameReader reader,
+                                                  final Class<?> from,
+                                                  final StackFrameWriter writer) {
+            byte byteValue = readPrimitiveAsByte(reader, from);
+            writer.putNextBoolean(toBoolean(byteValue));
+        }
+
+        private static void explicitCastPrimitives(final StackFrameReader reader,
+                                                   final Class<?> from,
+                                                   final StackFrameWriter writer,
+                                                   final Class<?> to) {
+            if (to == byte.class) {
+                byte value = readPrimitiveAsByte(reader, from);
+                writer.putNextByte(value);
+            } else if (to == char.class) {
+                char value = readPrimitiveAsChar(reader, from);
+                writer.putNextChar(value);
+            } else if (to == short.class) {
+                short value = readPrimitiveAsShort(reader, from);
+                writer.putNextShort(value);
+            } else if (to == int.class) {
+                int value = readPrimitiveAsInt(reader, from);
+                writer.putNextInt(value);
+            } else if (to == long.class) {
+                long value = readPrimitiveAsLong(reader, from);
+                writer.putNextLong(value);
+            } else if (to == float.class) {
+                float value = readPrimitiveAsFloat(reader, from);
+                writer.putNextFloat(value);
+            } else if (to == double.class) {
+                double value = readPrimitiveAsDouble(reader, from);
+                writer.putNextDouble(value);
+            } else {
+                throwUnexpectedType(to);
+            }
+        }
+
+        private static void unboxNull(final StackFrameWriter writer, final Class<?> to) {
+            if (to == boolean.class) {
+                writer.putNextBoolean(false);
+            } else if (to == byte.class) {
+                writer.putNextByte((byte) 0);
+            } else if (to == char.class) {
+                writer.putNextChar((char) 0);
+            } else if (to == short.class) {
+                writer.putNextShort((short) 0);
+            } else if (to == int.class) {
+                writer.putNextInt((int) 0);
+            } else if (to == long.class) {
+                writer.putNextLong((long) 0);
+            } else if (to == float.class) {
+                writer.putNextFloat((float) 0);
+            } else if (to == double.class) {
+                writer.putNextDouble((double) 0);
+            } else {
+                throwUnexpectedType(to);
+            }
+        }
+
+        private static void unboxNonNull(final Object ref, final Class<?> from,
+                                         final StackFrameWriter writer, final Class<?> to) {
+            if (to == boolean.class) {
+                if (from == Boolean.class) {
+                    writer.putNextBoolean((boolean) ref);
+                } else if (from == Float.class || from == Double.class) {
+                    byte b = (byte) ((double) ref);
+                    writer.putNextBoolean(toBoolean(b));
+                } else {
+                    byte b = (byte) ((long) ref);
+                    writer.putNextBoolean(toBoolean(b));
+                }
+            } else if (to == byte.class) {
+                writer.putNextByte((byte) ref);
+            } else if (to == char.class) {
+                writer.putNextChar((char) ref);
+            } else if (to == short.class) {
+                writer.putNextShort((short) ref);
+            } else if (to == int.class) {
+                writer.putNextInt((int) ref);
+            } else if (to == long.class) {
+                writer.putNextLong((long) ref);
+            } else if (to == float.class) {
+                writer.putNextFloat((float) ref);
+            } else if (to == double.class) {
+                writer.putNextDouble((double) ref);
+            } else {
+                throwUnexpectedType(to);
+            }
+        }
+
+        private static void unbox(final Object ref, final Class<?> from,
+                                  final StackFrameWriter writer, final Class<?> to) {
+            if (ref == null) {
+                unboxNull(writer, to);
+            } else {
+                unboxNonNull(ref, from, writer, to);
+            }
+        }
+
+        private static void box(final StackFrameReader reader, final Class<?> from,
+                                final StackFrameWriter writer, final Class<?> to) {
+            Object boxed = null;
+            if (from == boolean.class) {
+                boxed = Boolean.valueOf(reader.nextBoolean());
+            } else if (from == byte.class) {
+                boxed = Byte.valueOf(reader.nextByte());
+            } else if (from == char.class) {
+                boxed = Character.valueOf(reader.nextChar());
+            } else if (from == short.class) {
+                boxed = Short.valueOf(reader.nextShort());
+            } else if (from == int.class) {
+                boxed = Integer.valueOf(reader.nextInt());
+            } else if (from == long.class) {
+                boxed = Long.valueOf(reader.nextLong());
+            } else if (from == float.class) {
+                boxed = Float.valueOf(reader.nextFloat());
+            } else if (from == double.class) {
+                boxed = Double.valueOf(reader.nextDouble());
+            } else {
+                throwUnexpectedType(from);
+            }
+            writer.putNextReference(to.cast(boxed), to);
+        }
+
+        private static void explicitCast(final StackFrameReader reader, final Class<?> from,
+                                         final StackFrameWriter writer, final Class<?> to) {
+            if (from.equals(to)) {
+                StackFrameAccessor.copyNext(reader, writer, from);
+            } else if (!from.isPrimitive()) {
+                Object ref = reader.nextReference(from);
+                if (to.isInterface()) {
+                    // Pass from without a cast according to description for
+                    // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}.
+                    writer.putNextReference(ref, to);
+                } else if (!to.isPrimitive()) {
+                    // |to| is a reference type, perform class cast check.
+                    writer.putNextReference(to.cast(ref), to);
+                } else {
+                    // |from| is a reference type, |to| is a primitive type,
+                    unbox(ref, from, writer, to);
+                }
+            } else if (to.isPrimitive()) {
+                // |from| and |to| are primitive types.
+                if (from == boolean.class) {
+                    explicitCastFromBoolean(reader.nextBoolean(), writer, to);
+                } else if (to == boolean.class) {
+                    explicitCastToBoolean(reader, from, writer);
+                } else {
+                    explicitCastPrimitives(reader, from, writer, to);
+                }
+            } else {
+                // |from| is a primitive type, |to| is a reference type.
+                box(reader, from, writer, to);
+            }
+        }
+    }
 }
diff --git a/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java b/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
index 8c687ec..16cf18c 100644
--- a/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
+++ b/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
@@ -49,8 +49,8 @@
 {
     /* instance variable for SO_TIMEOUT */
     int timeout;   // timeout in millisec
-    // traffic class
-    private int trafficClass;
+    // Android-removed: traffic class is set through socket
+    // private int trafficClass;
 
     private boolean shut_rd = false;
     private boolean shut_wr = false;
@@ -205,17 +205,19 @@
         if (isClosedOrPending()) {
             throw new SocketException("Socket Closed");
         }
+        // Android-removed: Logic dealing with value type moved to socketSetOption.
+        /*
         boolean on = true;
         switch (opt) {
             /* check type safety b4 going native.  These should never
              * fail, since only java.Socket* has access to
              * PlainSocketImpl.setOption().
-             */
+             *
         case SO_LINGER:
             if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
                 throw new SocketException("Bad parameter for option");
             if (val instanceof Boolean) {
-                /* true only if disabling - enabling should be Integer */
+                /* true only if disabling - enabling should be Integer *
                 on = false;
             }
             break;
@@ -267,6 +269,11 @@
             throw new SocketException("unrecognized TCP option: " + opt);
         }
         socketSetOption(opt, on, val);
+        */
+        if (opt == SO_TIMEOUT) {
+            timeout = (Integer) val;
+        }
+        socketSetOption(opt, val);
     }
     public Object getOption(int opt) throws SocketException {
         if (isClosedOrPending()) {
@@ -275,6 +282,8 @@
         if (opt == SO_TIMEOUT) {
             return new Integer(timeout);
         }
+        // Android-removed: Logic dealing with value type moved to socketGetOption.
+        /*
         int ret = 0;
         /*
          * The native socketGetOption() knows about 3 options.
@@ -282,7 +291,7 @@
          * to what we're asking.  A return of -1 means it understands
          * the option but its turned off.  It will raise a SocketException
          * if "opt" isn't one it understands.
-         */
+         *
 
         switch (opt) {
         case TCP_NODELAY:
@@ -324,6 +333,8 @@
         default:
             return null;
         }
+        */
+        return socketGetOption(opt);
     }
 
     /**
@@ -725,9 +736,12 @@
         throws IOException;
     abstract void socketShutdown(int howto)
         throws IOException;
-    abstract void socketSetOption(int cmd, boolean on, Object value)
-        throws SocketException;
-    abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
+
+    // Android-changed: Method signature changed, socket{Get,Set}Option work directly with Object
+    // values.
+    abstract void socketSetOption(int cmd, Object value) throws SocketException;
+    abstract Object socketGetOption(int opt) throws SocketException;
+
     abstract void socketSendUrgentData(int data)
         throws IOException;
 
diff --git a/ojluni/src/main/java/java/net/DatagramSocket.java b/ojluni/src/main/java/java/net/DatagramSocket.java
index 34f3a2d..31a4db4 100755
--- a/ojluni/src/main/java/java/net/DatagramSocket.java
+++ b/ojluni/src/main/java/java/net/DatagramSocket.java
@@ -1347,17 +1347,16 @@
         factory = fac;
     }
 
+    // Android-added: for testing and internal use.
     /**
-     * Android-added: for testing and internal use.
-     *
      * @hide internal use only
      */
     public FileDescriptor getFileDescriptor$() {
         return impl.fd;
     }
 
+    // Android-added: setNetworkInterface() to set the network interface used by this socket.
     /**
-     * Android-added:
      * Sets the network interface used by this socket.  Any packets sent
      * via this socket are transmitted via the specified interface.  Any
      * packets received by this socket will come from the specified
diff --git a/ojluni/src/main/java/java/net/Inet6Address.java b/ojluni/src/main/java/java/net/Inet6Address.java
index 51b0927..ee946ee 100644
--- a/ojluni/src/main/java/java/net/Inet6Address.java
+++ b/ojluni/src/main/java/java/net/Inet6Address.java
@@ -262,7 +262,8 @@
             }
         }
 
-        /* ----- Android-removed -----
+        // Android-removed: getnameinfo returns smarter representations than getHostAddress()
+        /*
         String getHostAddress() {
             String s = numericToTextFormat(ipaddress);
             if (scope_ifname != null) { // must check this first
@@ -271,7 +272,8 @@
                 s = s + "%" + scope_id;
             }
             return s;
-        } */
+        }
+        */
 
         public boolean equals(Object o) {
             if (! (o instanceof Inet6AddressHolder)) {
@@ -870,7 +872,7 @@
      */
     @Override
     public String getHostAddress() {
-        // Android-changed: getnameinfo returns smarter representations
+        // Android-changed: getnameinfo returns smarter representations than getHostAddress()
         // return holder6.getHostAddress();
         return Libcore.os.getnameinfo(this, NI_NUMERICHOST); // Can't throw.
     }
diff --git a/ojluni/src/main/java/java/net/PlainSocketImpl.java b/ojluni/src/main/java/java/net/PlainSocketImpl.java
index f02006d..656defc 100644
--- a/ojluni/src/main/java/java/net/PlainSocketImpl.java
+++ b/ojluni/src/main/java/java/net/PlainSocketImpl.java
@@ -101,9 +101,9 @@
         return (T)flow;
     }
 
-    protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
+    protected void socketSetOption(int opt, Object val) throws SocketException {
         try {
-            socketSetOption0(opt, b, val);
+            socketSetOption0(opt, val);
         } catch (SocketException se) {
             if (socket == null || !socket.isConnected())
                 throw se;
@@ -268,10 +268,18 @@
         }
     }
 
-    native void socketSetOption0(int cmd, boolean on, Object value)
-        throws SocketException;
+    void socketSetOption0(int cmd, Object value) throws SocketException {
+        // OpenJDK does not set SO_TIMEOUT on Linux.
+        if (cmd == SO_TIMEOUT) {
+            return;
+        }
 
-    native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
+        IoBridge.setSocketOption(fd, cmd, value);
+    }
+
+    Object socketGetOption(int opt) throws SocketException {
+        return IoBridge.getSocketOption(fd, opt);
+    }
 
     void socketSendUrgentData(int data) throws IOException {
         if (fd == null || !fd.valid()) {
diff --git a/ojluni/src/main/java/java/net/ServerSocket.java b/ojluni/src/main/java/java/net/ServerSocket.java
index 670acf2..20ae95a 100644
--- a/ojluni/src/main/java/java/net/ServerSocket.java
+++ b/ojluni/src/main/java/java/net/ServerSocket.java
@@ -922,9 +922,8 @@
         /* Not implemented yet */
     }
 
+    // Android-added: for testing and internal use.
     /**
-     * Android-added: for testing and internal use.
-     *
      * @hide internal use only
      */
     public FileDescriptor getFileDescriptor$() {
diff --git a/ojluni/src/main/java/java/net/Socket.java b/ojluni/src/main/java/java/net/Socket.java
index 9d566b1..03e2b71 100644
--- a/ojluni/src/main/java/java/net/Socket.java
+++ b/ojluni/src/main/java/java/net/Socket.java
@@ -1768,9 +1768,8 @@
         /* Not implemented yet */
     }
 
+    // Android-added: for testing and internal use.
     /**
-     * Android-added: for testing and internal use.
-     *
      * @hide internal use only
      */
     public FileDescriptor getFileDescriptor$() {
diff --git a/ojluni/src/main/java/java/net/SocketTimeoutException.java b/ojluni/src/main/java/java/net/SocketTimeoutException.java
index 3b5b50a..2c61415 100644
--- a/ojluni/src/main/java/java/net/SocketTimeoutException.java
+++ b/ojluni/src/main/java/java/net/SocketTimeoutException.java
@@ -50,11 +50,13 @@
     public SocketTimeoutException() {}
 
     /** @hide */
+    // Android-added: Additional constructor for internal use.
     public SocketTimeoutException(Throwable cause) {
         super(cause);
     }
 
     /** @hide */
+    // Android-added: Additional constructor for internal use.
     public SocketTimeoutException(String msg, Throwable cause) {
         super(msg, cause);
     }
diff --git a/ojluni/src/main/java/java/net/SocksSocketImpl.java b/ojluni/src/main/java/java/net/SocksSocketImpl.java
index f1b29b0..a81e219 100644
--- a/ojluni/src/main/java/java/net/SocksSocketImpl.java
+++ b/ojluni/src/main/java/java/net/SocksSocketImpl.java
@@ -347,8 +347,9 @@
                                       epoint.getPort());
         }
         if (server == null) {
+            // Android-removed: Logic to establish proxy connection based on default ProxySelector
             /*
-             * Android-changed: Removed code that tried to establish proxy connection if
+             * Removed code that tried to establish proxy connection if
              * ProxySelector#getDefault() is not null.
              * This was never the case in previous android releases, was causing
              * issues and therefore was removed.
diff --git a/ojluni/src/main/java/java/security/KeyPairGenerator.java b/ojluni/src/main/java/java/security/KeyPairGenerator.java
index 1e46cee..68ab5e9 100644
--- a/ojluni/src/main/java/java/security/KeyPairGenerator.java
+++ b/ojluni/src/main/java/java/security/KeyPairGenerator.java
@@ -34,11 +34,6 @@
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
 
-/*
-Android-removed: this debugging mechanism is not supported in Android.
-import sun.security.util.Debug;
-*/
-
 /**
  * The KeyPairGenerator class is used to generate pairs of
  * public and private keys. Key pair generators are constructed using the
@@ -149,8 +144,8 @@
 
 public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
 
+    // Android-removed: this debugging mechanism is not used in Android.
     /*
-    Android-removed: this debugging mechanism is not supported in Android.
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -199,8 +194,8 @@
         }
         kpg.provider = instance.provider;
 
+        // Android-removed: this debugging mechanism is not used in Android.
         /*
-        Android-removed: this debugging mechanism is not supported in Android.
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyPairGenerator." + algorithm +
                 " algorithm from: " + kpg.provider.getName());
@@ -598,8 +593,8 @@
             this.serviceIterator = serviceIterator;
             initType = I_NONE;
 
+            // Android-removed: this debugging mechanism is not used in Android.
             /*
-            Android-removed: this debugging mechanism is not supported in Android.
             if (!skipDebug && pdebug != null) {
                 pdebug.println("KeyPairGenerator." + algorithm +
                     " algorithm from: " + provider.getName());
diff --git a/ojluni/src/main/java/java/security/MessageDigest.java b/ojluni/src/main/java/java/security/MessageDigest.java
index df6c456..5f586ac 100644
--- a/ojluni/src/main/java/java/security/MessageDigest.java
+++ b/ojluni/src/main/java/java/security/MessageDigest.java
@@ -35,10 +35,6 @@
 
 import java.nio.ByteBuffer;
 
-/*
-Android-removed: this debugging mechanism is not available in Android.
-import sun.security.util.Debug;
-*/
 /**
  * This MessageDigest class provides applications the functionality of a
  * message digest algorithm, such as SHA-1 or SHA-256.
@@ -134,8 +130,8 @@
 
 public abstract class MessageDigest extends MessageDigestSpi {
 
+    // Android-removed: this debugging mechanism is not used in Android.
     /*
-    Android-removed: this debugging mechanism is not available in Android.
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -205,8 +201,8 @@
             }
             md.provider = (Provider)objs[1];
 
+            // Android-removed: this debugging mechanism is not used in Android.
             /*
-            Android-removed: this debugging mechanism is not available in Android.
             if (!skipDebug && pdebug != null) {
                 pdebug.println("MessageDigest." + algorithm +
                     " algorithm from: " + md.provider.getName());
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index d38882a..d1fbd29 100644
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -977,7 +977,7 @@
             if (typeAndAlg == null) {
                 return;
             }
-            String type = typeAndAlg[0];
+            String type = getEngineName(typeAndAlg[0]);
             String aliasAlg = typeAndAlg[1].intern();
             ServiceKey key = new ServiceKey(type, stdAlg, true);
             Service s = legacyMap.get(key);
@@ -997,7 +997,7 @@
             int i = typeAndAlg[1].indexOf(' ');
             if (i == -1) {
                 // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
-                String type = typeAndAlg[0];
+                String type = getEngineName(typeAndAlg[0]);
                 String stdAlg = typeAndAlg[1].intern();
                 String className = value;
                 ServiceKey key = new ServiceKey(type, stdAlg, true);
@@ -1012,7 +1012,7 @@
             } else { // attribute
                 // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
                 String attributeValue = value;
-                String type = typeAndAlg[0];
+                String type = getEngineName(typeAndAlg[0]);
                 String attributeString = typeAndAlg[1];
                 String stdAlg = attributeString.substring(0, i).intern();
                 String attributeName = attributeString.substring(i + 1);
@@ -1324,10 +1324,8 @@
 
     private static void addEngine(String name, boolean sp, String paramName) {
         EngineDescription ed = new EngineDescription(name, sp, paramName);
-        // NOTE: The original OpenJDK code supported case-insensitive lookups on the list
-        // of known engines.
-        //
-        // knownEngines.put(name.toLowerCase(ENGLISH), ed);
+        // also index by canonical name to avoid toLowerCase() for some lookups
+        knownEngines.put(name.toLowerCase(ENGLISH), ed);
         knownEngines.put(name, ed);
     }
 
@@ -1378,6 +1376,17 @@
                             "java.lang.Object");
     }
 
+    // get the "standard" (mixed-case) engine name for arbitary case engine name
+    // if there is no known engine by that name, return s
+    private static String getEngineName(String s) {
+        // try original case first, usually correct
+        EngineDescription e = knownEngines.get(s);
+        if (e == null) {
+            e = knownEngines.get(s.toLowerCase(ENGLISH));
+        }
+        return (e == null) ? s : e.name;
+    }
+
     /**
      * The description of a security service. It encapsulates the properties
      * of a service and contains a factory method to obtain new implementation
@@ -1481,8 +1490,7 @@
                 throw new NullPointerException();
             }
             this.provider = provider;
-            // Android-changed.
-            this.type = type;
+            this.type = getEngineName(type);
             this.algorithm = algorithm;
             this.className = className;
             if (aliases == null) {
diff --git a/ojluni/src/main/java/java/security/SecureRandom.java b/ojluni/src/main/java/java/security/SecureRandom.java
index 78eac68..f512264 100644
--- a/ojluni/src/main/java/java/security/SecureRandom.java
+++ b/ojluni/src/main/java/java/security/SecureRandom.java
@@ -99,7 +99,7 @@
 
 public class SecureRandom extends java.util.Random {
 
-    // Android-removed: this debugging mechanism is not supported in Android.
+    // Android-removed: this debugging mechanism is not used in Android.
     /*
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
diff --git a/ojluni/src/main/java/java/text/DateFormatSymbols.java b/ojluni/src/main/java/java/text/DateFormatSymbols.java
index aa57aad..96a966c 100644
--- a/ojluni/src/main/java/java/text/DateFormatSymbols.java
+++ b/ojluni/src/main/java/java/text/DateFormatSymbols.java
@@ -865,35 +865,17 @@
         }
     }
 
+    // BEGIN Android-changed: extract initialization of zoneStrings to separate method.
     private final synchronized String[][] internalZoneStrings() {
         if (zoneStrings == null) {
             zoneStrings = TimeZoneNames.getZoneStrings(locale);
-            // If icu4c doesn't have a name, our array contains a null. TimeZone.getDisplayName
-            // knows how to format GMT offsets (and, unlike icu4c, has accurate data). http://b/8128460.
-            for (String[] zone : zoneStrings) {
-                String id = zone[0];
-                if (zone[1] == null) {
-                    zone[1] =
-                        TimeZone.getTimeZone(id).getDisplayName(false, TimeZone.LONG, locale);
-                }
-                if (zone[2] == null) {
-                    zone[2] =
-                        TimeZone.getTimeZone(id).getDisplayName(false, TimeZone.SHORT, locale);
-                }
-                if (zone[3] == null) {
-                    zone[3] = TimeZone.getTimeZone(id).getDisplayName(true, TimeZone.LONG, locale);
-                }
-                if (zone[4] == null) {
-                    zone[4] =
-                        TimeZone.getTimeZone(id).getDisplayName(true, TimeZone.SHORT, locale);
-                }
-            }
         }
         return zoneStrings;
     }
 
     private final String[][] getZoneStringsImpl(boolean needsCopy) {
         String[][] zoneStrings = internalZoneStrings();
+        // END Android-changed: extract initialization of zoneStrings to separate method.
 
         if (!needsCopy) {
             return zoneStrings;
@@ -964,6 +946,7 @@
      * @since 1.6
      */
     private void writeObject(ObjectOutputStream stream) throws IOException {
+        // Android-changed: extract initialization of zoneStrings to separate method.
         internalZoneStrings();
         stream.defaultWriteObject();
     }
diff --git a/ojluni/src/main/java/java/time/chrono/HijrahChronology.java b/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
index 98b79c4..e7b3554 100644
--- a/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
+++ b/ojluni/src/main/java/java/time/chrono/HijrahChronology.java
@@ -544,7 +544,7 @@
     //-----------------------------------------------------------------------
     @Override
     public boolean isLeapYear(long prolepticYear) {
-      checkCalendarInit();
+        checkCalendarInit();
         if (prolepticYear < getMinimumYear() || prolepticYear > getMaximumYear()) {
             return false;
         }
diff --git a/ojluni/src/main/java/java/util/ArrayList.java b/ojluni/src/main/java/java/util/ArrayList.java
index dd465c9..d65bf1f 100644
--- a/ojluni/src/main/java/java/util/ArrayList.java
+++ b/ojluni/src/main/java/java/util/ArrayList.java
@@ -103,8 +103,8 @@
  * @see     Vector
  * @since   1.2
  */
+// Android-changed: Inlined methods; CME in iterators; throw AIOOBE when toIndex < fromIndex.
 /*
- * Android-changed:
  * - AOSP commit 3be987f0f18648b3c532c8b89d09505e18594241
  *   Inline for improved performance:
  *   - checkForComodification
diff --git a/ojluni/src/main/java/java/util/Arrays.java b/ojluni/src/main/java/java/util/Arrays.java
index b4f52a4..72c5f93 100644
--- a/ojluni/src/main/java/java/util/Arrays.java
+++ b/ojluni/src/main/java/java/util/Arrays.java
@@ -124,11 +124,10 @@
         }
     }
 
+    // BEGIN Android-added: checkOffsetAndCount() helper method for AIOOBE enforcement.
     /**
      * Checks that the range described by {@code offset} and {@code count} doesn't exceed
      * {@code arrayLength}.
-     *
-     * Android-changed.
      * @hide
      */
     public static void checkOffsetAndCount(int arrayLength, int offset, int count) {
@@ -137,6 +136,7 @@
                     count);
         }
     }
+    // END Android-added: checkOffsetAndCount() helper method for AIOOBE enforcement.
 
     /*
      * Sorting methods. Note that all public "sort" methods take the
diff --git a/ojluni/src/main/java/java/util/Collections.java b/ojluni/src/main/java/java/util/Collections.java
index 4818ee6..5d0325f 100644
--- a/ojluni/src/main/java/java/util/Collections.java
+++ b/ojluni/src/main/java/java/util/Collections.java
@@ -151,7 +151,7 @@
     @SuppressWarnings("unchecked")
     public static <T extends Comparable<? super T>> void sort(List<T> list) {
         // Android-changed: Call sort(list, null) here to be consistent
-        // with that method's (Android-changed) behavior.
+        // with that method's (Android changed) behavior.
         // list.sort(null);
         sort(list, null);
     }
diff --git a/ojluni/src/main/java/java/util/LinkedHashMap.java b/ojluni/src/main/java/java/util/LinkedHashMap.java
index 3b5c3af..aec40bc 100644
--- a/ojluni/src/main/java/java/util/LinkedHashMap.java
+++ b/ojluni/src/main/java/java/util/LinkedHashMap.java
@@ -190,7 +190,7 @@
      * LinkedHashMap.Entry is now treated as intermediary node class
      * that can also be converted to tree form.
      *
-     * BEGIN Android-changed
+     // BEGIN Android-changed
      * LinkedHashMapEntry should not be renamed. Specifically, for
      * source compatibility with earlier versions of Android, this
      * nested class must not be named "Entry". Otherwise, it would
@@ -201,7 +201,7 @@
      * To compile, that code snippet's "LinkedHashMap.Entry" must
      * mean java.util.Map.Entry which is the compile time type of
      * entrySet()'s elements.
-     * END Android-changed
+     // END Android-changed
      *
      * The changes in node classes also require using two fields
      * (head, tail) rather than a pointer to a header node to maintain
diff --git a/ojluni/src/main/java/java/util/Locale.java b/ojluni/src/main/java/java/util/Locale.java
index 437cc66..9bd3126 100644
--- a/ojluni/src/main/java/java/util/Locale.java
+++ b/ojluni/src/main/java/java/util/Locale.java
@@ -512,6 +512,14 @@
  *     <td><a href="http://site.icu-project.org/download/55">ICU 55.1</a></td>
  *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-27">CLDR 27.0.1</a></td>
  *     <td><a href="http://www.unicode.org/versions/Unicode7.0.0/">Unicode 7.0</a></td></tr>
+ * <tr><td>Android 7.0 (Nougat)</td>
+ *     <td><a href="http://site.icu-project.org/download/56">ICU 56.1</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-28">CLDR 28</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode8.0.0/">Unicode 8.0</a></td></tr>
+ * <tr><td>Android 8.0 (TBD)</td>
+ *     <td><a href="http://site.icu-project.org/download/58">ICU 58.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-30">CLDR 30.0.3</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode9.0.0/">Unicode 9.0</a></td></tr>
  * </table>
  *
  * <a name="default_locale"></a><h4>Be wary of the default locale</h3>
diff --git a/ojluni/src/main/java/java/util/Optional.java b/ojluni/src/main/java/java/util/Optional.java
index 10b7923..bce8ff9 100644
--- a/ojluni/src/main/java/java/util/Optional.java
+++ b/ojluni/src/main/java/java/util/Optional.java
@@ -29,6 +29,7 @@
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 
+// Android-changed: removed ValueBased paragraph.
 /**
  * A container object which may or may not contain a non-null value.
  * If a value is present, {@code isPresent()} will return {@code true} and
diff --git a/ojluni/src/main/java/java/util/OptionalDouble.java b/ojluni/src/main/java/java/util/OptionalDouble.java
index ead3c91..7112df1 100644
--- a/ojluni/src/main/java/java/util/OptionalDouble.java
+++ b/ojluni/src/main/java/java/util/OptionalDouble.java
@@ -28,6 +28,7 @@
 import java.util.function.DoubleSupplier;
 import java.util.function.Supplier;
 
+// Android-changed: removed ValueBased paragraph.
 /**
  * A container object which may or may not contain a {@code double} value.
  * If a value is present, {@code isPresent()} will return {@code true} and
diff --git a/ojluni/src/main/java/java/util/OptionalInt.java b/ojluni/src/main/java/java/util/OptionalInt.java
index 23c8b8c..7907328 100644
--- a/ojluni/src/main/java/java/util/OptionalInt.java
+++ b/ojluni/src/main/java/java/util/OptionalInt.java
@@ -28,6 +28,7 @@
 import java.util.function.IntSupplier;
 import java.util.function.Supplier;
 
+// Android-changed: removed ValueBased paragraph.
 /**
  * A container object which may or may not contain a {@code int} value.
  * If a value is present, {@code isPresent()} will return {@code true} and
diff --git a/ojluni/src/main/java/java/util/OptionalLong.java b/ojluni/src/main/java/java/util/OptionalLong.java
index 21aa70e..b337d83 100644
--- a/ojluni/src/main/java/java/util/OptionalLong.java
+++ b/ojluni/src/main/java/java/util/OptionalLong.java
@@ -28,6 +28,7 @@
 import java.util.function.LongSupplier;
 import java.util.function.Supplier;
 
+// Android-changed: removed ValueBased paragraph.
 /**
  * A container object which may or may not contain a {@code long} value.
  * If a value is present, {@code isPresent()} will return {@code true} and
diff --git a/ojluni/src/main/java/java/util/ResourceBundle.java b/ojluni/src/main/java/java/util/ResourceBundle.java
index 886ffc1..6fff252 100644
--- a/ojluni/src/main/java/java/util/ResourceBundle.java
+++ b/ojluni/src/main/java/java/util/ResourceBundle.java
@@ -360,7 +360,8 @@
      */
     private volatile Set<String> keySet;
 
-    /* Android-changed: Removed used of ResourceBundleControlProvider.
+    // Android-changed: Removed use of ResourceBundleControlProvider.
+    /*
     private static final List<ResourceBundleControlProvider> providers;
 
     static {
diff --git a/ojluni/src/main/java/java/util/TimeZone.java b/ojluni/src/main/java/java/util/TimeZone.java
index 28ad0ca..6ad180b 100644
--- a/ojluni/src/main/java/java/util/TimeZone.java
+++ b/ojluni/src/main/java/java/util/TimeZone.java
@@ -39,20 +39,15 @@
 
 package java.util;
 
+import org.apache.harmony.luni.internal.util.TimezoneGetter;
+import android.icu.text.TimeZoneNames;
 import java.io.IOException;
 import java.io.Serializable;
 import java.time.ZoneId;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.lang.ref.SoftReference;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.concurrent.ConcurrentHashMap;
-import libcore.icu.TimeZoneNames;
 import libcore.io.IoUtils;
 import libcore.util.ZoneInfoDB;
-import sun.security.action.GetPropertyAction;
-import org.apache.harmony.luni.internal.util.TimezoneGetter;
 
 /**
  * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
@@ -387,15 +382,30 @@
      * @param locale the display locale.
      */
     public String getDisplayName(boolean daylightTime, int style, Locale locale) {
-        if (style != SHORT && style != LONG) {
-            throw new IllegalArgumentException("Illegal style: " + style);
+        // BEGIN Android-changed: implement using android.icu.text.TimeZoneNames
+        TimeZoneNames.NameType nameType;
+        switch (style) {
+            case SHORT:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.SHORT_DAYLIGHT
+                        : TimeZoneNames.NameType.SHORT_STANDARD;
+                break;
+            case LONG:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.LONG_DAYLIGHT
+                        : TimeZoneNames.NameType.LONG_STANDARD;
+                break;
+            default:
+                throw new IllegalArgumentException("Illegal style: " + style);
         }
-
-        // Android-changed: implement using libcore.icu.TimeZoneNames
-        String[][] zoneStrings = TimeZoneNames.getZoneStrings(locale);
-        String result = TimeZoneNames.getDisplayName(zoneStrings, getID(), daylightTime, style);
-        if (result != null) {
-            return result;
+        String canonicalID = android.icu.util.TimeZone.getCanonicalID(getID());
+        if (canonicalID != null) {
+            TimeZoneNames names = TimeZoneNames.getInstance(locale);
+            long now = System.currentTimeMillis();
+            String displayName = names.getDisplayName(canonicalID, nameType, now);
+            if (displayName != null) {
+                return displayName;
+            }
         }
 
         // We get here if this is a custom timezone or ICU doesn't have name data for the specific
@@ -406,8 +416,10 @@
         }
         return createGmtOffsetString(true /* includeGmt */, true /* includeMinuteSeparator */,
                 offsetMillis);
+        // END Android-changed: implement using android.icu.text.TimeZoneNames
     }
 
+    // BEGIN Android-added: utility method to format an offset as a GMT offset string.
     /**
      * Returns a string representation of an offset from UTC.
      *
@@ -448,6 +460,7 @@
         }
         builder.append(string);
     }
+    // END Android-added: utility method to format an offset as a GMT offset string.
 
     /**
      * Returns the amount of time to be added to local standard time
diff --git a/ojluni/src/main/java/java/util/XMLUtils.java b/ojluni/src/main/java/java/util/XMLUtils.java
index b7133dc..8f061e5 100644
--- a/ojluni/src/main/java/java/util/XMLUtils.java
+++ b/ojluni/src/main/java/java/util/XMLUtils.java
@@ -92,7 +92,7 @@
     {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         dbf.setIgnoringElementContentWhitespace(true);
-        // Android-chanaged: We don't currently have a validating document builder.
+        // Android-changed: We don't currently have a validating document builder.
         // Revert this if the situation changes.
         //
         // dbf.setValidating(true);
diff --git a/ojluni/src/main/java/java/util/logging/Level.java b/ojluni/src/main/java/java/util/logging/Level.java
index afc7035..c03b171 100644
--- a/ojluni/src/main/java/java/util/logging/Level.java
+++ b/ojluni/src/main/java/java/util/logging/Level.java
@@ -262,7 +262,7 @@
     }
 
     private String computeLocalizedLevelName(Locale newLocale) {
-        // Android-change: Use Thread.currentThread().getContextClassLoader(),
+        // Android-changed: Use Thread.currentThread().getContextClassLoader(),
         // otherwise we might get a BootClassLoader.
         ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale,
                                                      Thread.currentThread().getContextClassLoader());
diff --git a/ojluni/src/main/java/javax/crypto/Cipher.java b/ojluni/src/main/java/javax/crypto/Cipher.java
index c2a2183..c707899 100644
--- a/ojluni/src/main/java/javax/crypto/Cipher.java
+++ b/ojluni/src/main/java/javax/crypto/Cipher.java
@@ -44,9 +44,6 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ReadOnlyBufferException;
-/* Android-removed: this debugging mechanism is not used in Android
-import sun.security.util.Debug;
-*/
 import sun.security.jca.*;
 
 /**
@@ -230,7 +227,8 @@
 
 public class Cipher {
 
-    /* Android-removed: this debugging mechanism is not used in Android
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -835,7 +833,8 @@
 
         initialized = true;
         this.opmode = opmode;
-        /* Android-removed: this debugging mechanism is not used in Android
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
@@ -975,7 +974,8 @@
         initialized = true;
         this.opmode = opmode;
 
-        /* Android-removed: this debugging mechanism is not used in Android
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
@@ -1115,7 +1115,8 @@
         initialized = true;
         this.opmode = opmode;
 
-        /* Android-removed: this debugging mechanism is not used in Android
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
@@ -1301,7 +1302,8 @@
         initialized = true;
         this.opmode = opmode;
 
-        /* Android-removed: this debugging mechanism is not used in Android
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Cipher." + transformation + " " +
                 getOpmodeString(opmode) + " algorithm from: " +
@@ -2171,8 +2173,8 @@
      */
     public static final int getMaxAllowedKeyLength(String transformation)
             throws NoSuchAlgorithmException {
-        // Android-changed: Remove references to CryptoPermission and throw early
-        // if transformation == null or isn't valid.
+        // Android-changed: Remove references to CryptoPermission.
+        // Throw early if transformation == null or isn't valid.
         //
         // CryptoPermission cp = getConfiguredPermission(transformation);
         // return cp.getMaxAllowedKeyLength();
@@ -2204,8 +2206,8 @@
      */
     public static final AlgorithmParameterSpec getMaxAllowedParameterSpec(
             String transformation) throws NoSuchAlgorithmException {
-        // Android-changed: Remove references to CryptoPermission and throw early
-        // if transformation == null or isn't valid.
+        // Android-changed: Remove references to CryptoPermission.
+        // Throw early if transformation == null or isn't valid.
         //
         // CryptoPermission cp = getConfiguredPermission(transformation);
         // return cp.getAlgorithmParameterSpec();
diff --git a/ojluni/src/main/java/javax/crypto/KeyAgreement.java b/ojluni/src/main/java/javax/crypto/KeyAgreement.java
index 8a0b1c1..7c29102 100644
--- a/ojluni/src/main/java/javax/crypto/KeyAgreement.java
+++ b/ojluni/src/main/java/javax/crypto/KeyAgreement.java
@@ -32,9 +32,6 @@
 import java.security.Provider.Service;
 import java.security.spec.*;
 
-/* Android-removed: this debugging mechanism is not used in Android.
-import sun.security.util.Debug;
-*/
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
 
@@ -91,7 +88,8 @@
 
 public class KeyAgreement {
 
-    /* Android-removed: this debugging mechanism is not used in Android.
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -293,7 +291,8 @@
             if (spi != null) {
                 return;
             }
-            /* Android-removed: this debugging mechanism is not used in Android.
+            // Android-removed: this debugging mechanism is not used in Android.
+            /*
             if (debug != null) {
                 int w = --warnCount;
                 if (w >= 0) {
@@ -463,7 +462,8 @@
             }
         }
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
                 this.provider.getName());
@@ -526,7 +526,8 @@
             chooseProvider(I_PARAMS, key, params, random);
         }
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
                 this.provider.getName());
diff --git a/ojluni/src/main/java/javax/crypto/KeyGenerator.java b/ojluni/src/main/java/javax/crypto/KeyGenerator.java
index 8a54e5c..5dfde97 100644
--- a/ojluni/src/main/java/javax/crypto/KeyGenerator.java
+++ b/ojluni/src/main/java/javax/crypto/KeyGenerator.java
@@ -33,9 +33,6 @@
 
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
-/* Android-removed: this debugging mechanism is not used in Android.
-import sun.security.util.Debug;
-*/
 
 /**
  * This class provides the functionality of a secret (symmetric) key generator.
@@ -167,7 +164,8 @@
 
 public class KeyGenerator {
 
-    /* Android-removed: this debugging mechanism is not used in Android.
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -212,7 +210,8 @@
         this.provider = provider;
         this.algorithm = algorithm;
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
                 this.provider.getName());
@@ -232,7 +231,8 @@
                 (algorithm + " KeyGenerator not available");
         }
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
                 this.provider.getName());
diff --git a/ojluni/src/main/java/javax/crypto/Mac.java b/ojluni/src/main/java/javax/crypto/Mac.java
index 2315db7..cdf6105 100644
--- a/ojluni/src/main/java/javax/crypto/Mac.java
+++ b/ojluni/src/main/java/javax/crypto/Mac.java
@@ -34,9 +34,6 @@
 
 import java.nio.ByteBuffer;
 
-/* Android-removed: this debugging mechanism is not used in Android.
-import sun.security.util.Debug;
-*/
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
 
@@ -156,7 +153,8 @@
 
 public class Mac implements Cloneable {
 
-    /* Android-removed: this debugging mechanism is not used in Android.
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
     private static final Debug pdebug =
                         Debug.getInstance("provider", "Provider");
     private static final boolean skipDebug =
@@ -344,7 +342,8 @@
             if (spi != null) {
                 return;
             }
-            /* Android-removed: this debugging mechanism is not used in Android.
+            // Android-removed: this debugging mechanism is not used in Android.
+            /*
             if (debug != null) {
                 int w = --warnCount;
                 if (w >= 0) {
@@ -472,7 +471,8 @@
         }
         initialized = true;
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Mac." + algorithm + " algorithm from: " +
                 this.provider.getName());
@@ -501,7 +501,8 @@
         }
         initialized = true;
 
-        /* Android-removed: this debugging mechanism is not used in Android.
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
         if (!skipDebug && pdebug != null) {
             pdebug.println("Mac." + algorithm + " algorithm from: " +
                 this.provider.getName());
diff --git a/ojluni/src/main/java/jdk/net/package-info.java b/ojluni/src/main/java/jdk/net/package-info.java
deleted file mode 100644
index b05d543..0000000
--- a/ojluni/src/main/java/jdk/net/package-info.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * Platform specific socket options for the {@code java.net} and {@code java.nio.channels}
- * socket classes.
- */
-
-@jdk.Exported
-package jdk.net;
diff --git a/ojluni/src/main/java/sun/misc/FDBigInt.java b/ojluni/src/main/java/sun/misc/FDBigInt.java
deleted file mode 100644
index 85b5b35..0000000
--- a/ojluni/src/main/java/sun/misc/FDBigInt.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-/*
- * A really, really simple bigint package
- * tailored to the needs of floating base conversion.
- */
-public class FDBigInt {
-    int nWords; // number of words used
-    int data[]; // value: data[0] is least significant
-
-
-    public FDBigInt( int v ){
-        nWords = 1;
-        data = new int[1];
-        data[0] = v;
-    }
-
-    public FDBigInt( long v ){
-        data = new int[2];
-        data[0] = (int)v;
-        data[1] = (int)(v>>>32);
-        nWords = (data[1]==0) ? 1 : 2;
-    }
-
-    public FDBigInt( FDBigInt other ){
-        data = new int[nWords = other.nWords];
-        System.arraycopy( other.data, 0, data, 0, nWords );
-    }
-
-    private FDBigInt( int [] d, int n ){
-        data = d;
-        nWords = n;
-    }
-
-    public FDBigInt( long seed, char digit[], int nd0, int nd ){
-        int n= (nd+8)/9;        // estimate size needed.
-        if ( n < 2 ) n = 2;
-        data = new int[n];      // allocate enough space
-        data[0] = (int)seed;    // starting value
-        data[1] = (int)(seed>>>32);
-        nWords = (data[1]==0) ? 1 : 2;
-        int i = nd0;
-        int limit = nd-5;       // slurp digits 5 at a time.
-        int v;
-        while ( i < limit ){
-            int ilim = i+5;
-            v = (int)digit[i++]-(int)'0';
-            while( i <ilim ){
-                v = 10*v + (int)digit[i++]-(int)'0';
-            }
-            multaddMe( 100000, v); // ... where 100000 is 10^5.
-        }
-        int factor = 1;
-        v = 0;
-        while ( i < nd ){
-            v = 10*v + (int)digit[i++]-(int)'0';
-            factor *= 10;
-        }
-        if ( factor != 1 ){
-            multaddMe( factor, v );
-        }
-    }
-
-    /*
-     * Left shift by c bits.
-     * Shifts this in place.
-     */
-    public void
-    lshiftMe( int c )throws IllegalArgumentException {
-        if ( c <= 0 ){
-            if ( c == 0 )
-                return; // silly.
-            else
-                throw new IllegalArgumentException("negative shift count");
-        }
-        int wordcount = c>>5;
-        int bitcount  = c & 0x1f;
-        int anticount = 32-bitcount;
-        int t[] = data;
-        int s[] = data;
-        if ( nWords+wordcount+1 > t.length ){
-            // reallocate.
-            t = new int[ nWords+wordcount+1 ];
-        }
-        int target = nWords+wordcount;
-        int src    = nWords-1;
-        if ( bitcount == 0 ){
-            // special hack, since an anticount of 32 won't go!
-            System.arraycopy( s, 0, t, wordcount, nWords );
-            target = wordcount-1;
-        } else {
-            t[target--] = s[src]>>>anticount;
-            while ( src >= 1 ){
-                t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount);
-            }
-            t[target--] = s[src]<<bitcount;
-        }
-        while( target >= 0 ){
-            t[target--] = 0;
-        }
-        data = t;
-        nWords += wordcount + 1;
-        // may have constructed high-order word of 0.
-        // if so, trim it
-        while ( nWords > 1 && data[nWords-1] == 0 )
-            nWords--;
-    }
-
-    /*
-     * normalize this number by shifting until
-     * the MSB of the number is at 0x08000000.
-     * This is in preparation for quoRemIteration, below.
-     * The idea is that, to make division easier, we want the
-     * divisor to be "normalized" -- usually this means shifting
-     * the MSB into the high words sign bit. But because we know that
-     * the quotient will be 0 < q < 10, we would like to arrange that
-     * the dividend not span up into another word of precision.
-     * (This needs to be explained more clearly!)
-     */
-    public int
-    normalizeMe() throws IllegalArgumentException {
-        int src;
-        int wordcount = 0;
-        int bitcount  = 0;
-        int v = 0;
-        for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){
-            wordcount += 1;
-        }
-        if ( src < 0 ){
-            // oops. Value is zero. Cannot normalize it!
-            throw new IllegalArgumentException("zero value");
-        }
-        /*
-         * In most cases, we assume that wordcount is zero. This only
-         * makes sense, as we try not to maintain any high-order
-         * words full of zeros. In fact, if there are zeros, we will
-         * simply SHORTEN our number at this point. Watch closely...
-         */
-        nWords -= wordcount;
-        /*
-         * Compute how far left we have to shift v s.t. its highest-
-         * order bit is in the right place. Then call lshiftMe to
-         * do the work.
-         */
-        if ( (v & 0xf0000000) != 0 ){
-            // will have to shift up into the next word.
-            // too bad.
-            for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- )
-                v >>>= 1;
-        } else {
-            while ( v <= 0x000fffff ){
-                // hack: byte-at-a-time shifting
-                v <<= 8;
-                bitcount += 8;
-            }
-            while ( v <= 0x07ffffff ){
-                v <<= 1;
-                bitcount += 1;
-            }
-        }
-        if ( bitcount != 0 )
-            lshiftMe( bitcount );
-        return bitcount;
-    }
-
-    /*
-     * Multiply a FDBigInt by an int.
-     * Result is a new FDBigInt.
-     */
-    public FDBigInt
-    mult( int iv ) {
-        long v = iv;
-        int r[];
-        long p;
-
-        // guess adequate size of r.
-        r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ];
-        p = 0L;
-        for( int i=0; i < nWords; i++ ) {
-            p += v * ((long)data[i]&0xffffffffL);
-            r[i] = (int)p;
-            p >>>= 32;
-        }
-        if ( p == 0L){
-            return new FDBigInt( r, nWords );
-        } else {
-            r[nWords] = (int)p;
-            return new FDBigInt( r, nWords+1 );
-        }
-    }
-
-    /*
-     * Multiply a FDBigInt by an int and add another int.
-     * Result is computed in place.
-     * Hope it fits!
-     */
-    public void
-    multaddMe( int iv, int addend ) {
-        long v = iv;
-        long p;
-
-        // unroll 0th iteration, doing addition.
-        p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL);
-        data[0] = (int)p;
-        p >>>= 32;
-        for( int i=1; i < nWords; i++ ) {
-            p += v * ((long)data[i]&0xffffffffL);
-            data[i] = (int)p;
-            p >>>= 32;
-        }
-        if ( p != 0L){
-            data[nWords] = (int)p; // will fail noisily if illegal!
-            nWords++;
-        }
-    }
-
-    /*
-     * Multiply a FDBigInt by another FDBigInt.
-     * Result is a new FDBigInt.
-     */
-    public FDBigInt
-    mult( FDBigInt other ){
-        // crudely guess adequate size for r
-        int r[] = new int[ nWords + other.nWords ];
-        int i;
-        // I think I am promised zeros...
-
-        for( i = 0; i < this.nWords; i++ ){
-            long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
-            long p = 0L;
-            int j;
-            for( j = 0; j < other.nWords; j++ ){
-                p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
-                r[i+j] = (int)p;
-                p >>>= 32;
-            }
-            r[i+j] = (int)p;
-        }
-        // compute how much of r we actually needed for all that.
-        for ( i = r.length-1; i> 0; i--)
-            if ( r[i] != 0 )
-                break;
-        return new FDBigInt( r, i+1 );
-    }
-
-    /*
-     * Add one FDBigInt to another. Return a FDBigInt
-     */
-    public FDBigInt
-    add( FDBigInt other ){
-        int i;
-        int a[], b[];
-        int n, m;
-        long c = 0L;
-        // arrange such that a.nWords >= b.nWords;
-        // n = a.nWords, m = b.nWords
-        if ( this.nWords >= other.nWords ){
-            a = this.data;
-            n = this.nWords;
-            b = other.data;
-            m = other.nWords;
-        } else {
-            a = other.data;
-            n = other.nWords;
-            b = this.data;
-            m = this.nWords;
-        }
-        int r[] = new int[ n ];
-        for ( i = 0; i < n; i++ ){
-            c += (long)a[i] & 0xffffffffL;
-            if ( i < m ){
-                c += (long)b[i] & 0xffffffffL;
-            }
-            r[i] = (int) c;
-            c >>= 32; // signed shift.
-        }
-        if ( c != 0L ){
-            // oops -- carry out -- need longer result.
-            int s[] = new int[ r.length+1 ];
-            System.arraycopy( r, 0, s, 0, r.length );
-            s[i++] = (int)c;
-            return new FDBigInt( s, i );
-        }
-        return new FDBigInt( r, i );
-    }
-
-    /*
-     * Subtract one FDBigInt from another. Return a FDBigInt
-     * Assert that the result is positive.
-     */
-    public FDBigInt
-    sub( FDBigInt other ){
-        int r[] = new int[ this.nWords ];
-        int i;
-        int n = this.nWords;
-        int m = other.nWords;
-        int nzeros = 0;
-        long c = 0L;
-        for ( i = 0; i < n; i++ ){
-            c += (long)this.data[i] & 0xffffffffL;
-            if ( i < m ){
-                c -= (long)other.data[i] & 0xffffffffL;
-            }
-            if ( ( r[i] = (int) c ) == 0 )
-                nzeros++;
-            else
-                nzeros = 0;
-            c >>= 32; // signed shift
-        }
-        assert c == 0L : c; // borrow out of subtract
-        assert dataInRangeIsZero(i, m, other); // negative result of subtract
-        return new FDBigInt( r, n-nzeros );
-    }
-
-    private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) {
-        while ( i < m )
-            if (other.data[i++] != 0)
-                return false;
-        return true;
-    }
-
-    /*
-     * Compare FDBigInt with another FDBigInt. Return an integer
-     * >0: this > other
-     *  0: this == other
-     * <0: this < other
-     */
-    public int
-    cmp( FDBigInt other ){
-        int i;
-        if ( this.nWords > other.nWords ){
-            // if any of my high-order words is non-zero,
-            // then the answer is evident
-            int j = other.nWords-1;
-            for ( i = this.nWords-1; i > j ; i-- )
-                if ( this.data[i] != 0 ) return 1;
-        }else if ( this.nWords < other.nWords ){
-            // if any of other's high-order words is non-zero,
-            // then the answer is evident
-            int j = this.nWords-1;
-            for ( i = other.nWords-1; i > j ; i-- )
-                if ( other.data[i] != 0 ) return -1;
-        } else{
-            i = this.nWords-1;
-        }
-        for ( ; i > 0 ; i-- )
-            if ( this.data[i] != other.data[i] )
-                break;
-        // careful! want unsigned compare!
-        // use brute force here.
-        int a = this.data[i];
-        int b = other.data[i];
-        if ( a < 0 ){
-            // a is really big, unsigned
-            if ( b < 0 ){
-                return a-b; // both big, negative
-            } else {
-                return 1; // b not big, answer is obvious;
-            }
-        } else {
-            // a is not really big
-            if ( b < 0 ) {
-                // but b is really big
-                return -1;
-            } else {
-                return a - b;
-            }
-        }
-    }
-
-    /*
-     * Compute
-     * q = (int)( this / S )
-     * this = 10 * ( this mod S )
-     * Return q.
-     * This is the iteration step of digit development for output.
-     * We assume that S has been normalized, as above, and that
-     * "this" has been lshift'ed accordingly.
-     * Also assume, of course, that the result, q, can be expressed
-     * as an integer, 0 <= q < 10.
-     */
-    public int
-    quoRemIteration( FDBigInt S )throws IllegalArgumentException {
-        // ensure that this and S have the same number of
-        // digits. If S is properly normalized and q < 10 then
-        // this must be so.
-        if ( nWords != S.nWords ){
-            throw new IllegalArgumentException("disparate values");
-        }
-        // estimate q the obvious way. We will usually be
-        // right. If not, then we're only off by a little and
-        // will re-add.
-        int n = nWords-1;
-        long q = ((long)data[n]&0xffffffffL) / (long)S.data[n];
-        long diff = 0L;
-        for ( int i = 0; i <= n ; i++ ){
-            diff += ((long)data[i]&0xffffffffL) -  q*((long)S.data[i]&0xffffffffL);
-            data[i] = (int)diff;
-            diff >>= 32; // N.B. SIGNED shift.
-        }
-        if ( diff != 0L ) {
-            // damn, damn, damn. q is too big.
-            // add S back in until this turns +. This should
-            // not be very many times!
-            long sum = 0L;
-            while ( sum ==  0L ){
-                sum = 0L;
-                for ( int i = 0; i <= n; i++ ){
-                    sum += ((long)data[i]&0xffffffffL) +  ((long)S.data[i]&0xffffffffL);
-                    data[i] = (int) sum;
-                    sum >>= 32; // Signed or unsigned, answer is 0 or 1
-                }
-                /*
-                 * Originally the following line read
-                 * "if ( sum !=0 && sum != -1 )"
-                 * but that would be wrong, because of the
-                 * treatment of the two values as entirely unsigned,
-                 * it would be impossible for a carry-out to be interpreted
-                 * as -1 -- it would have to be a single-bit carry-out, or
-                 * +1.
-                 */
-                assert sum == 0 || sum == 1 : sum; // carry out of division correction
-                q -= 1;
-            }
-        }
-        // finally, we can multiply this by 10.
-        // it cannot overflow, right, as the high-order word has
-        // at least 4 high-order zeros!
-        long p = 0L;
-        for ( int i = 0; i <= n; i++ ){
-            p += 10*((long)data[i]&0xffffffffL);
-            data[i] = (int)p;
-            p >>= 32; // SIGNED shift.
-        }
-        assert p == 0L : p; // Carry out of *10
-        return (int)q;
-    }
-
-    public long
-    longValue(){
-        // if this can be represented as a long, return the value
-        assert this.nWords > 0 : this.nWords; // longValue confused
-
-        if (this.nWords == 1)
-            return ((long)data[0]&0xffffffffL);
-
-        assert dataInRangeIsZero(2, this.nWords, this); // value too big
-        assert data[1] >= 0;  // value too big
-        return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL);
-    }
-
-    public String
-    toString() {
-        StringBuffer r = new StringBuffer(30);
-        r.append('[');
-        int i = Math.min( nWords-1, data.length-1) ;
-        if ( nWords > data.length ){
-            r.append( "("+data.length+"<"+nWords+"!)" );
-        }
-        for( ; i> 0 ; i-- ){
-            r.append( Integer.toHexString( data[i] ) );
-            r.append(' ');
-        }
-        r.append( Integer.toHexString( data[0] ) );
-        r.append(']');
-        return new String( r );
-    }
-}
diff --git a/ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java b/ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java
index 762df01..3923675 100644
--- a/ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java
+++ b/ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java
@@ -361,9 +361,7 @@
         return dc;
     }
 
-    /*
-     * Android-added: for testing and internal use.
-     */
+    // Android-added: for testing and internal use.
     @Override
     public final FileDescriptor getFileDescriptor$() {
         return dc.fd;
diff --git a/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java b/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
index aa6d834..a2aba2d 100644
--- a/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
+++ b/ojluni/src/main/java/sun/nio/ch/SocketAdaptor.java
@@ -453,9 +453,7 @@
         return !sc.isOutputOpen();
     }
 
-    /*
-     * Android-added: for testing and internal use.
-     */
+    // Android-added: for testing and internal use.
     @Override
     public FileDescriptor getFileDescriptor$() {
         return sc.getFD();
diff --git a/ojluni/src/main/java/sun/security/pkcs/PKCS7.java b/ojluni/src/main/java/sun/security/pkcs/PKCS7.java
index 49d898a..4fa4711 100644
--- a/ojluni/src/main/java/sun/security/pkcs/PKCS7.java
+++ b/ojluni/src/main/java/sun/security/pkcs/PKCS7.java
@@ -1172,5 +1172,6 @@
         }
         return tsReply.getEncodedToken();
     }
-    END Android-removed */
+    */
+    // END Android-removed: unused in Android
 }
diff --git a/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java b/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
index b78fdf9..e2f8e28 100644
--- a/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
+++ b/ojluni/src/main/java/sun/security/pkcs/SignerInfo.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,21 +33,38 @@
 import java.io.OutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
+import java.security.CryptoPrimitive;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.Timestamp;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertPath;
 import java.security.cert.X509Certificate;
-import java.security.*;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
 
+import sun.misc.HexDumpEncoder;
 import sun.security.timestamp.TimestampToken;
-import sun.security.util.*;
+import sun.security.util.Debug;
+import sun.security.util.DerEncoder;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.util.ObjectIdentifier;
 import sun.security.x509.AlgorithmId;
 import sun.security.x509.X500Name;
 import sun.security.x509.KeyUsageExtension;
 import sun.security.x509.PKIXExtensions;
-import sun.misc.HexDumpEncoder;
 
 /**
  * A SignerInfo, as defined in PKCS#7's signedData type.
@@ -56,6 +73,17 @@
  */
 public class SignerInfo implements DerEncoder {
 
+    // Digest and Signature restrictions
+    private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET =
+            Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
+
+    private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET =
+            Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
+
+    private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
+            new DisabledAlgorithmConstraints(
+                    DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
+
     BigInteger version;
     X500Name issuerName;
     BigInteger certificateSerialNumber;
@@ -337,6 +365,13 @@
                 if (messageDigest == null) // fail if there is no message digest
                     return null;
 
+                // check that algorithm is not restricted
+                if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET,
+                        digestAlgname, null)) {
+                    throw new SignatureException("Digest check failed. " +
+                            "Disabled algorithm used: " + digestAlgname);
+                }
+
                 MessageDigest md = MessageDigest.getInstance(digestAlgname);
 
                 byte[] buffer = new byte[4096];
@@ -374,12 +409,24 @@
             String algname = AlgorithmId.makeSigAlg(
                     digestAlgname, encryptionAlgname);
 
-            Signature sig = Signature.getInstance(algname);
-            X509Certificate cert = getCertificate(block);
+            // check that algorithm is not restricted
+            if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) {
+                throw new SignatureException("Signature check failed. " +
+                        "Disabled algorithm used: " + algname);
+            }
 
+            X509Certificate cert = getCertificate(block);
+            PublicKey key = cert.getPublicKey();
             if (cert == null) {
                 return null;
             }
+
+            // check if the public key is restricted
+            if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
+                throw new SignatureException("Public key check failed. " +
+                        "Disabled algorithm used: " + key.getAlgorithm());
+            }
+
             if (cert.hasUnsupportedCriticalExtension()) {
                 throw new SignatureException("Certificate has unsupported "
                                              + "critical extension(s)");
@@ -416,7 +463,7 @@
                 }
             }
 
-            PublicKey key = cert.getPublicKey();
+            Signature sig = Signature.getInstance(algname);
             sig.initVerify(key);
 
             byte[] buffer = new byte[4096];
@@ -549,9 +596,16 @@
      */
     private void verifyTimestamp(TimestampToken token)
         throws NoSuchAlgorithmException, SignatureException {
+        String digestAlgname = token.getHashAlgorithm().getName();
+        // check that algorithm is not restricted
+        if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, digestAlgname,
+                null)) {
+            throw new SignatureException("Timestamp token digest check failed. " +
+                    "Disabled algorithm used: " + digestAlgname);
+        }
 
         MessageDigest md =
-            MessageDigest.getInstance(token.getHashAlgorithm().getName());
+            MessageDigest.getInstance(digestAlgname);
 
         if (!Arrays.equals(token.getHashedMessage(),
             md.digest(encryptedDigest))) {
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java
index e92590a..f727a3a 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/AlgorithmChecker.java
@@ -255,16 +255,17 @@
 
         PublicKey currPubKey = cert.getPublicKey();
 
-        // Check against DisabledAlgorithmConstraints certpath constraints.
-        // permits() will throw exception on failure.
-        certPathDefaultConstraints.permits(primitives,
+        if (constraints instanceof DisabledAlgorithmConstraints) {
+            // Check against DisabledAlgorithmConstraints certpath constraints.
+            // permits() will throw exception on failure.
+            ((DisabledAlgorithmConstraints)constraints).permits(primitives,
                 new CertConstraintParameters((X509Certificate)cert,
                         trustedMatch));
-                // new CertConstraintParameters(x509Cert, trustedMatch));
-        // If there is no previous key, set one and exit
-        if (prevPubKey == null) {
-            prevPubKey = currPubKey;
-            return;
+            // If there is no previous key, set one and exit
+            if (prevPubKey == null) {
+                prevPubKey = currPubKey;
+                return;
+            }
         }
 
         X509CertImpl x509Cert;
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/Builder.java b/ojluni/src/main/java/sun/security/provider/certpath/Builder.java
index 84cbe66..e6b5fc0 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/Builder.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/Builder.java
@@ -102,8 +102,8 @@
 
     /**
      * Verifies whether the input certificate completes the path.
-     * When building forward, a trust anchor will complete the path.
-     * When building reverse, the target certificate will complete the path.
+     * When building in the forward direction, a trust anchor will
+     * complete the path.
      *
      * @param cert the certificate to test
      * @return a boolean value indicating whether the cert completes the path.
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ForwardBuilder.java b/ojluni/src/main/java/sun/security/provider/certpath/ForwardBuilder.java
index 57e819c..27bb25f 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/ForwardBuilder.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/ForwardBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -824,18 +824,19 @@
 
     /**
      * Verifies whether the input certificate completes the path.
-     * Checks the cert against each trust anchor that was specified, in order,
-     * and returns true as soon as it finds a valid anchor.
-     * Returns true if the cert matches a trust anchor specified as a
-     * certificate or if the cert verifies with a trust anchor that
-     * was specified as a trusted {pubkey, caname} pair. Returns false if none
-     * of the trust anchors are valid for this cert.
-     *
-     * @param cert the certificate to test
-     * @return a boolean value indicating whether the cert completes the path.
+     * First checks the cert against each trust anchor that was specified,
+     * in order, and returns true if the cert matches the trust anchor
+     * specified as a certificate or has the same key and subject of an anchor
+     * specified as a trusted {pubkey, caname} pair.
+     * If no match has been found, does a second check of the cert against
+     * anchors specified as a trusted {pubkey, caname} pair to see if the cert
+     * was issued by that anchor.
+     * Returns false if none of the trust anchors are valid for this cert.
      */
     @Override
     boolean isPathCompleted(X509Certificate cert) {
+        List<TrustAnchor> otherAnchors = new ArrayList<>();
+        // first, check if cert is already trusted
         for (TrustAnchor anchor : trustAnchors) {
             if (anchor.getTrustedCert() != null) {
                 if (cert.equals(anchor.getTrustedCert())) {
@@ -857,7 +858,12 @@
                 }
                 // else, it is a self-issued certificate of the anchor
             }
-
+            otherAnchors.add(anchor);
+        }
+        // next, check if cert is issued by anchor specified by key/name
+        for (TrustAnchor anchor : otherAnchors) {
+            X500Principal principal = anchor.getCA();
+            PublicKey publicKey = anchor.getCAPublicKey();
             // Check subject/issuer name chaining
             if (principal == null ||
                     !principal.equals(cert.getIssuerX500Principal())) {
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/OCSPResponse.java b/ojluni/src/main/java/sun/security/provider/certpath/OCSPResponse.java
index 8075d73..c8a75ea 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/OCSPResponse.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/OCSPResponse.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -151,8 +151,8 @@
     private static final int DEFAULT_MAX_CLOCK_SKEW = 900000;
 
     /**
-     * Integer value indicating the maximum allowable clock skew, in seconds,
-     * to be used for the OCSP check.
+     * Integer value indicating the maximum allowable clock skew,
+     * in milliseconds, to be used for the OCSP check.
      */
     private static final int MAX_CLOCK_SKEW = initializeClockSkew();
 
@@ -586,13 +586,14 @@
                 "Unable to verify OCSP Response's signature");
         }
 
-        // Check freshness of OCSPResponse
         if (nonce != null) {
             if (responseNonce != null && !Arrays.equals(nonce, responseNonce)) {
                 throw new CertPathValidatorException("Nonces don't match");
             }
         }
 
+        // Check freshness of OCSPResponse
+
         long now = (date == null) ? System.currentTimeMillis() : date.getTime();
         Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
         Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
@@ -602,13 +603,18 @@
                 if (sr.nextUpdate != null) {
                     until = " until " + sr.nextUpdate;
                 }
-                debug.println("Response's validity interval is from " +
-                              sr.thisUpdate + until);
+                debug.println("OCSP response validity interval is from " +
+                               sr.thisUpdate + until);
+                debug.println("Checking validity of OCSP response on: " +
+                    new Date(now));
             }
 
-            // Check that the test date is within the validity interval
-            if ((sr.thisUpdate != null && nowPlusSkew.before(sr.thisUpdate)) ||
-                (sr.nextUpdate != null && nowMinusSkew.after(sr.nextUpdate)))
+            // Check that the test date is within the validity interval:
+            //   [ thisUpdate - MAX_CLOCK_SKEW,
+            //     MAX(thisUpdate, nextUpdate) + MAX_CLOCK_SKEW ]
+            if (nowPlusSkew.before(sr.thisUpdate) ||
+                nowMinusSkew.after(
+                    sr.nextUpdate != null ? sr.nextUpdate : sr.thisUpdate))
             {
                 throw new CertPathValidatorException(
                                       "Response is unreliable: its validity " +
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/PKIX.java b/ojluni/src/main/java/sun/security/provider/certpath/PKIX.java
index 98c8834..e33d4a2 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/PKIX.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/PKIX.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
 package sun.security.provider.certpath;
 
 import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore;
 import java.security.PublicKey;
 import java.security.cert.*;
 import java.security.interfaces.DSAPublicKey;
@@ -194,7 +193,6 @@
 
     static class BuilderParams extends ValidatorParams {
         private PKIXBuilderParameters params;
-        private boolean buildForward = true;
         private List<CertStore> stores;
         private X500Principal targetSubject;
 
@@ -213,10 +211,6 @@
                     + "targetCertConstraints parameter must be an "
                     + "X509CertSelector");
             }
-            if (params instanceof SunCertPathBuilderParameters) {
-                buildForward =
-                    ((SunCertPathBuilderParameters)params).getBuildForward();
-            }
             this.params = params;
             this.targetSubject = getTargetSubject(
                 certStores(), (X509CertSelector)targetCertConstraints());
@@ -230,7 +224,6 @@
             return stores;
         }
         int maxPathLength() { return params.getMaxPathLength(); }
-        boolean buildForward() { return buildForward; }
         PKIXBuilderParameters params() { return params; }
         X500Principal targetSubject() { return targetSubject; }
 
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java b/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java
index 492e851..d2d9e36 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/PKIXCertPathValidator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -94,9 +94,6 @@
             X509Certificate firstCert = certList.get(0);
             // check trusted certificate's subject
             selector.setSubject(firstCert.getIssuerX500Principal());
-            // check the validity period
-            selector.setValidityPeriod(firstCert.getNotBefore(),
-                                       firstCert.getNotAfter());
             /*
              * Facilitate certification path construction with authority
              * key identifier and subject key identifier.
@@ -162,13 +159,22 @@
                                                         ValidatorParams params)
         throws CertPathValidatorException
     {
+        // add standard checkers that we will be using
+        // Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
+        // check if anchor is untrusted
+        //UntrustedChecker untrustedChecker = new UntrustedChecker();
+        //X509Certificate anchorCert = anchor.getTrustedCert();
+        //if (anchorCert != null) {
+        //    untrustedChecker.check(anchorCert);
+        //}
+
         int certPathLen = params.certificates().size();
 
         // create PKIXCertPathCheckers
         List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>();
         // add standard checkers that we will be using
         // Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
-        // certPathCheckers.add(new UntrustedChecker());
+        // certPathCheckers.add(untrustedChecker);
         certPathCheckers.add(new AlgorithmChecker(anchor));
         certPathCheckers.add(new KeyChecker(certPathLen,
                                             params.targetCertConstraints()));
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ReverseBuilder.java b/ojluni/src/main/java/sun/security/provider/certpath/ReverseBuilder.java
deleted file mode 100644
index 1815a22..0000000
--- a/ojluni/src/main/java/sun/security/provider/certpath/ReverseBuilder.java
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.provider.certpath;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.Principal;
-import java.security.cert.CertificateException;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertStore;
-import java.security.cert.CertStoreException;
-import java.security.cert.PKIXBuilderParameters;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXParameters;
-import java.security.cert.PKIXReason;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.security.cert.X509CertSelector;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.Set;
-
-import javax.security.auth.x500.X500Principal;
-
-import sun.security.provider.certpath.PKIX.BuilderParams;
-import sun.security.util.Debug;
-import sun.security.x509.Extension;
-import static sun.security.x509.PKIXExtensions.*;
-import sun.security.x509.X500Name;
-import sun.security.x509.X509CertImpl;
-import sun.security.x509.PolicyMappingsExtension;
-
-/**
- * This class represents a reverse builder, which is able to retrieve
- * matching certificates from CertStores and verify a particular certificate
- * against a ReverseState.
- *
- * @since       1.4
- * @author      Sean Mullan
- * @author      Yassir Elley
- */
-
-class ReverseBuilder extends Builder {
-
-    private Debug debug = Debug.getInstance("certpath");
-
-    private final Set<String> initPolicies;
-
-    /**
-     * Initialize the builder with the input parameters.
-     *
-     * @param params the parameter set used to build a certification path
-     */
-    ReverseBuilder(BuilderParams buildParams) {
-        super(buildParams);
-
-        Set<String> initialPolicies = buildParams.initialPolicies();
-        initPolicies = new HashSet<String>();
-        if (initialPolicies.isEmpty()) {
-            // if no initialPolicies are specified by user, set
-            // initPolicies to be anyPolicy by default
-            initPolicies.add(PolicyChecker.ANY_POLICY);
-        } else {
-            initPolicies.addAll(initialPolicies);
-        }
-    }
-
-    /**
-     * Retrieves all certs from the specified CertStores that satisfy the
-     * requirements specified in the parameters and the current
-     * PKIX state (name constraints, policy constraints, etc).
-     *
-     * @param currentState the current state.
-     *        Must be an instance of <code>ReverseState</code>
-     * @param certStores list of CertStores
-     */
-    @Override
-    Collection<X509Certificate> getMatchingCerts
-        (State currState, List<CertStore> certStores)
-        throws CertStoreException, CertificateException, IOException
-    {
-        ReverseState currentState = (ReverseState) currState;
-
-        if (debug != null)
-            debug.println("In ReverseBuilder.getMatchingCerts.");
-
-        /*
-         * The last certificate could be an EE or a CA certificate
-         * (we may be building a partial certification path or
-         * establishing trust in a CA).
-         *
-         * Try the EE certs before the CA certs. It will be more
-         * common to build a path to an end entity.
-         */
-        Collection<X509Certificate> certs =
-            getMatchingEECerts(currentState, certStores);
-        certs.addAll(getMatchingCACerts(currentState, certStores));
-
-        return certs;
-    }
-
-    /*
-     * Retrieves all end-entity certificates which satisfy constraints
-     * and requirements specified in the parameters and PKIX state.
-     */
-    private Collection<X509Certificate> getMatchingEECerts
-        (ReverseState currentState, List<CertStore> certStores)
-        throws CertStoreException, CertificateException, IOException {
-
-        /*
-         * Compose a CertSelector to filter out
-         * certs which do not satisfy requirements.
-         *
-         * First, retrieve clone of current target cert constraints, and
-         * then add more selection criteria based on current validation state.
-         */
-        X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone();
-
-        /*
-         * Match on issuer (subject of previous cert)
-         */
-        sel.setIssuer(currentState.subjectDN);
-
-        /*
-         * Match on certificate validity date.
-         */
-        sel.setCertificateValid(buildParams.date());
-
-        /*
-         * Policy processing optimizations
-         */
-        if (currentState.explicitPolicy == 0)
-            sel.setPolicy(getMatchingPolicies());
-
-        /*
-         * If previous cert has a subject key identifier extension,
-         * use it to match on authority key identifier extension.
-         */
-        /*if (currentState.subjKeyId != null) {
-          AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
-                (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
-                null, null);
-        sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
-        }*/
-
-        /*
-         * Require EE certs
-         */
-        sel.setBasicConstraints(-2);
-
-        /* Retrieve matching certs from CertStores */
-        HashSet<X509Certificate> eeCerts = new HashSet<>();
-        addMatchingCerts(sel, certStores, eeCerts, true);
-
-        if (debug != null) {
-            debug.println("ReverseBuilder.getMatchingEECerts got "
-                          + eeCerts.size() + " certs.");
-        }
-        return eeCerts;
-    }
-
-    /*
-     * Retrieves all CA certificates which satisfy constraints
-     * and requirements specified in the parameters and PKIX state.
-     */
-    private Collection<X509Certificate> getMatchingCACerts
-        (ReverseState currentState, List<CertStore> certStores)
-        throws CertificateException, CertStoreException, IOException {
-
-        /*
-         * Compose a CertSelector to filter out
-         * certs which do not satisfy requirements.
-         */
-        X509CertSelector sel = new X509CertSelector();
-
-        /*
-         * Match on issuer (subject of previous cert)
-         */
-        sel.setIssuer(currentState.subjectDN);
-
-        /*
-         * Match on certificate validity date.
-         */
-        sel.setCertificateValid(buildParams.date());
-
-        /*
-         * Match on target subject name (checks that current cert's
-         * name constraints permit it to certify target).
-         * (4 is the integer type for DIRECTORY name).
-         */
-        byte[] subject = targetCertConstraints.getSubjectAsBytes();
-        if (subject != null) {
-            sel.addPathToName(4, subject);
-        } else {
-            X509Certificate cert = targetCertConstraints.getCertificate();
-            if (cert != null) {
-                sel.addPathToName(4,
-                                  cert.getSubjectX500Principal().getEncoded());
-            }
-        }
-
-        /*
-         * Policy processing optimizations
-         */
-        if (currentState.explicitPolicy == 0)
-            sel.setPolicy(getMatchingPolicies());
-
-        /*
-         * If previous cert has a subject key identifier extension,
-         * use it to match on authority key identifier extension.
-         */
-        /*if (currentState.subjKeyId != null) {
-          AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
-                (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
-                                null, null);
-          sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
-        }*/
-
-        /*
-         * Require CA certs
-         */
-        sel.setBasicConstraints(0);
-
-        /* Retrieve matching certs from CertStores */
-        ArrayList<X509Certificate> reverseCerts = new ArrayList<>();
-        addMatchingCerts(sel, certStores, reverseCerts, true);
-
-        /* Sort remaining certs using name constraints */
-        Collections.sort(reverseCerts, new PKIXCertComparator());
-
-        if (debug != null)
-            debug.println("ReverseBuilder.getMatchingCACerts got " +
-                          reverseCerts.size() + " certs.");
-        return reverseCerts;
-    }
-
-    /*
-     * This inner class compares 2 PKIX certificates according to which
-     * should be tried first when building a path to the target. For
-     * now, the algorithm is to look at name constraints in each cert and those
-     * which constrain the path closer to the target should be
-     * ranked higher. Later, we may want to consider other components,
-     * such as key identifiers.
-     */
-    class PKIXCertComparator implements Comparator<X509Certificate> {
-
-        private Debug debug = Debug.getInstance("certpath");
-
-        @Override
-        public int compare(X509Certificate cert1, X509Certificate cert2) {
-
-            /*
-             * if either cert certifies the target, always
-             * put at head of list.
-             */
-            X500Principal targetSubject = buildParams.targetSubject();
-            if (cert1.getSubjectX500Principal().equals(targetSubject)) {
-                return -1;
-            }
-            if (cert2.getSubjectX500Principal().equals(targetSubject)) {
-                return 1;
-            }
-
-            int targetDist1;
-            int targetDist2;
-            try {
-                X500Name targetSubjectName = X500Name.asX500Name(targetSubject);
-                targetDist1 = Builder.targetDistance(
-                    null, cert1, targetSubjectName);
-                targetDist2 = Builder.targetDistance(
-                    null, cert2, targetSubjectName);
-            } catch (IOException e) {
-                if (debug != null) {
-                    debug.println("IOException in call to Builder.targetDistance");
-                    e.printStackTrace();
-                }
-                throw new ClassCastException
-                    ("Invalid target subject distinguished name");
-            }
-
-            if (targetDist1 == targetDist2)
-                return 0;
-
-            if (targetDist1 == -1)
-                return 1;
-
-            if (targetDist1 < targetDist2)
-                return -1;
-
-            return 1;
-        }
-    }
-
-    /**
-     * Verifies a matching certificate.
-     *
-     * This method executes any of the validation steps in the PKIX path validation
-     * algorithm which were not satisfied via filtering out non-compliant
-     * certificates with certificate matching rules.
-     *
-     * If the last certificate is being verified (the one whose subject
-     * matches the target subject, then the steps in Section 6.1.4 of the
-     * Certification Path Validation algorithm are NOT executed,
-     * regardless of whether or not the last cert is an end-entity
-     * cert or not. This allows callers to certify CA certs as
-     * well as EE certs.
-     *
-     * @param cert the certificate to be verified
-     * @param currentState the current state against which the cert is verified
-     * @param certPathList the certPathList generated thus far
-     */
-    @Override
-    void verifyCert(X509Certificate cert, State currState,
-        List<X509Certificate> certPathList)
-        throws GeneralSecurityException
-    {
-        if (debug != null) {
-            debug.println("ReverseBuilder.verifyCert(SN: "
-                + Debug.toHexString(cert.getSerialNumber())
-                + "\n  Subject: " + cert.getSubjectX500Principal() + ")");
-        }
-
-        ReverseState currentState = (ReverseState) currState;
-
-        /* we don't perform any validation of the trusted cert */
-        if (currentState.isInitial()) {
-            return;
-        }
-
-        // BEGIN Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
-        // // Don't bother to verify untrusted certificate more.
-        // currentState.untrustedChecker.check(cert,
-        //                             Collections.<String>emptySet());
-        // END Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
-
-        /*
-         * check for looping - abort a loop if
-         * ((we encounter the same certificate twice) AND
-         * ((policyMappingInhibited = true) OR (no policy mapping
-         * extensions can be found between the occurrences of the same
-         * certificate)))
-         * in order to facilitate the check to see if there are
-         * any policy mapping extensions found between the occurrences
-         * of the same certificate, we reverse the certpathlist first
-         */
-        if ((certPathList != null) && (!certPathList.isEmpty())) {
-            List<X509Certificate> reverseCertList = new ArrayList<>();
-            for (X509Certificate c : certPathList) {
-                reverseCertList.add(0, c);
-            }
-
-            boolean policyMappingFound = false;
-            for (X509Certificate cpListCert : reverseCertList) {
-                X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert);
-                PolicyMappingsExtension policyMappingsExt =
-                        cpListCertImpl.getPolicyMappingsExtension();
-                if (policyMappingsExt != null) {
-                    policyMappingFound = true;
-                }
-                if (debug != null)
-                    debug.println("policyMappingFound = " + policyMappingFound);
-                if (cert.equals(cpListCert)) {
-                    if ((buildParams.policyMappingInhibited()) ||
-                        (!policyMappingFound)){
-                        if (debug != null)
-                            debug.println("loop detected!!");
-                        throw new CertPathValidatorException("loop detected");
-                    }
-                }
-            }
-        }
-
-        /* check if target cert */
-        boolean finalCert = cert.getSubjectX500Principal().equals(buildParams.targetSubject());
-
-        /* check if CA cert */
-        boolean caCert = (cert.getBasicConstraints() != -1 ? true : false);
-
-        /* if there are more certs to follow, verify certain constraints */
-        if (!finalCert) {
-
-            /* check if CA cert */
-            if (!caCert)
-                throw new CertPathValidatorException("cert is NOT a CA cert");
-
-            /* If the certificate was not self-issued, verify that
-             * remainingCerts is greater than zero
-             */
-            if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) {
-                    throw new CertPathValidatorException
-                        ("pathLenConstraint violated, path too long", null,
-                         null, -1, PKIXReason.PATH_TOO_LONG);
-            }
-
-            /*
-             * Check keyUsage extension (only if CA cert and not final cert)
-             */
-            KeyChecker.verifyCAKeyUsage(cert);
-
-        } else {
-
-            /*
-             * If final cert, check that it satisfies specified target
-             * constraints
-             */
-            if (targetCertConstraints.match(cert) == false) {
-                throw new CertPathValidatorException("target certificate " +
-                    "constraints check failed");
-            }
-        }
-
-        /*
-         * Check revocation.
-         */
-        if (buildParams.revocationEnabled() && currentState.revChecker != null) {
-            currentState.revChecker.check(cert, Collections.<String>emptySet());
-        }
-
-        /* Check name constraints if this is not a self-issued cert */
-        if (finalCert || !X509CertImpl.isSelfIssued(cert)){
-            if (currentState.nc != null) {
-                try {
-                    if (!currentState.nc.verify(cert)){
-                        throw new CertPathValidatorException
-                            ("name constraints check failed", null, null, -1,
-                             PKIXReason.INVALID_NAME);
-                    }
-                } catch (IOException ioe) {
-                    throw new CertPathValidatorException(ioe);
-                }
-            }
-        }
-
-        /*
-         * Check policy
-         */
-        X509CertImpl certImpl = X509CertImpl.toImpl(cert);
-        currentState.rootNode = PolicyChecker.processPolicies
-            (currentState.certIndex, initPolicies,
-            currentState.explicitPolicy, currentState.policyMapping,
-            currentState.inhibitAnyPolicy,
-            buildParams.policyQualifiersRejected(), currentState.rootNode,
-            certImpl, finalCert);
-
-        /*
-         * Check CRITICAL private extensions
-         */
-        Set<String> unresolvedCritExts = cert.getCriticalExtensionOIDs();
-        if (unresolvedCritExts == null) {
-            unresolvedCritExts = Collections.<String>emptySet();
-        }
-
-        /*
-         * Check that the signature algorithm is not disabled.
-         */
-        currentState.algorithmChecker.check(cert, unresolvedCritExts);
-
-        for (PKIXCertPathChecker checker : currentState.userCheckers) {
-            checker.check(cert, unresolvedCritExts);
-        }
-
-        /*
-         * Look at the remaining extensions and remove any ones we have
-         * already checked. If there are any left, throw an exception!
-         */
-        if (!unresolvedCritExts.isEmpty()) {
-            unresolvedCritExts.remove(BasicConstraints_Id.toString());
-            unresolvedCritExts.remove(NameConstraints_Id.toString());
-            unresolvedCritExts.remove(CertificatePolicies_Id.toString());
-            unresolvedCritExts.remove(PolicyMappings_Id.toString());
-            unresolvedCritExts.remove(PolicyConstraints_Id.toString());
-            unresolvedCritExts.remove(InhibitAnyPolicy_Id.toString());
-            unresolvedCritExts.remove(SubjectAlternativeName_Id.toString());
-            unresolvedCritExts.remove(KeyUsage_Id.toString());
-            unresolvedCritExts.remove(ExtendedKeyUsage_Id.toString());
-
-            if (!unresolvedCritExts.isEmpty())
-                throw new CertPathValidatorException
-                    ("Unrecognized critical extension(s)", null, null, -1,
-                     PKIXReason.UNRECOGNIZED_CRIT_EXT);
-        }
-
-        /*
-         * Check signature.
-         */
-        if (buildParams.sigProvider() != null) {
-            cert.verify(currentState.pubKey, buildParams.sigProvider());
-        } else {
-            cert.verify(currentState.pubKey);
-        }
-    }
-
-    /**
-     * Verifies whether the input certificate completes the path.
-     * This checks whether the cert is the target certificate.
-     *
-     * @param cert the certificate to test
-     * @return a boolean value indicating whether the cert completes the path.
-     */
-    @Override
-    boolean isPathCompleted(X509Certificate cert) {
-        return cert.getSubjectX500Principal().equals(buildParams.targetSubject());
-    }
-
-    /** Adds the certificate to the certPathList
-     *
-     * @param cert the certificate to be added
-     * @param certPathList the certification path list
-     */
-    @Override
-    void addCertToPath(X509Certificate cert,
-        LinkedList<X509Certificate> certPathList) {
-        certPathList.addLast(cert);
-    }
-
-    /** Removes final certificate from the certPathList
-     *
-     * @param certPathList the certification path list
-     */
-    @Override
-    void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
-        certPathList.removeLast();
-    }
-}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ReverseState.java b/ojluni/src/main/java/sun/security/provider/certpath/ReverseState.java
deleted file mode 100644
index a9944af..0000000
--- a/ojluni/src/main/java/sun/security/provider/certpath/ReverseState.java
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.provider.certpath;
-
-import java.io.IOException;
-import java.security.PublicKey;
-import java.security.cert.CertificateException;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXRevocationChecker;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-import javax.security.auth.x500.X500Principal;
-
-import sun.security.provider.certpath.PKIX.BuilderParams;
-import sun.security.util.Debug;
-import sun.security.x509.NameConstraintsExtension;
-import sun.security.x509.SubjectKeyIdentifierExtension;
-import sun.security.x509.X509CertImpl;
-
-/**
- * A specification of a reverse PKIX validation state
- * which is initialized by each build and updated each time a
- * certificate is added to the current path.
- * @since       1.4
- * @author      Sean Mullan
- * @author      Yassir Elley
- */
-
-class ReverseState implements State {
-
-    private static final Debug debug = Debug.getInstance("certpath");
-
-    /* The subject DN of the last cert in the path */
-    X500Principal subjectDN;
-
-    /* The subject public key of the last cert */
-    PublicKey pubKey;
-
-    /* The subject key identifier extension (if any) of the last cert */
-    SubjectKeyIdentifierExtension subjKeyId;
-
-    /* The PKIX constrained/excluded subtrees state variable */
-    NameConstraintsExtension nc;
-
-    /* The PKIX explicit policy, policy mapping, and inhibit_any-policy
-       state variables */
-    int explicitPolicy;
-    int policyMapping;
-    int inhibitAnyPolicy;
-    int certIndex;
-    PolicyNodeImpl rootNode;
-
-    /* The number of remaining CA certs which may follow in the path.
-     * -1: previous cert was an EE cert
-     * 0: only EE certs may follow.
-     * >0 and <Integer.MAX_VALUE:no more than this number of CA certs may follow
-     * Integer.MAX_VALUE: unlimited
-     */
-    int remainingCACerts;
-
-    /* The list of user-defined checkers retrieved from the PKIXParameters
-     * instance */
-    ArrayList<PKIXCertPathChecker> userCheckers;
-
-    /* Flag indicating if state is initial (path is just starting) */
-    private boolean init = true;
-
-    /* the checker used for revocation status */
-    RevocationChecker revChecker;
-
-    /* the algorithm checker */
-    AlgorithmChecker algorithmChecker;
-
-    /* the untrusted certificates checker */
-    // Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
-    // UntrustedChecker untrustedChecker;
-
-    /* the trust anchor used to validate the path */
-    TrustAnchor trustAnchor;
-
-    /* Flag indicating if current cert can vouch for the CRL for
-     * the next cert
-     */
-    boolean crlSign = true;
-
-    /**
-     * Returns a boolean flag indicating if the state is initial
-     * (just starting)
-     *
-     * @return boolean flag indicating if the state is initial (just starting)
-     */
-    @Override
-    public boolean isInitial() {
-        return init;
-    }
-
-    /**
-     * Display state for debugging purposes
-     */
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("State [");
-        sb.append("\n  subjectDN of last cert: ").append(subjectDN);
-        sb.append("\n  subjectKeyIdentifier: ").append
-                 (String.valueOf(subjKeyId));
-        sb.append("\n  nameConstraints: ").append(String.valueOf(nc));
-        sb.append("\n  certIndex: ").append(certIndex);
-        sb.append("\n  explicitPolicy: ").append(explicitPolicy);
-        sb.append("\n  policyMapping:  ").append(policyMapping);
-        sb.append("\n  inhibitAnyPolicy:  ").append(inhibitAnyPolicy);
-        sb.append("\n  rootNode: ").append(rootNode);
-        sb.append("\n  remainingCACerts: ").append(remainingCACerts);
-        sb.append("\n  crlSign: ").append(crlSign);
-        sb.append("\n  init: ").append(init);
-        sb.append("\n]\n");
-        return sb.toString();
-    }
-
-    /**
-     * Initialize the state.
-     *
-     * @param buildParams builder parameters
-     */
-    public void initState(BuilderParams buildParams)
-        throws CertPathValidatorException
-    {
-        /*
-         * Initialize number of remainingCACerts.
-         * Note that -1 maxPathLen implies unlimited.
-         * 0 implies only an EE cert is acceptable.
-         */
-        int maxPathLen = buildParams.maxPathLength();
-        remainingCACerts = (maxPathLen == -1) ? Integer.MAX_VALUE
-                                              : maxPathLen;
-
-        /* Initialize explicit policy state variable */
-        if (buildParams.explicitPolicyRequired()) {
-            explicitPolicy = 0;
-        } else {
-            // unconstrained if maxPathLen is -1,
-            // otherwise, we want to initialize this to the value of the
-            // longest possible path + 1 (i.e. maxpathlen + finalcert + 1)
-            explicitPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
-        }
-
-        /* Initialize policy mapping state variable */
-        if (buildParams.policyMappingInhibited()) {
-            policyMapping = 0;
-        } else {
-            policyMapping = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
-        }
-
-        /* Initialize inhibit any policy state variable */
-        if (buildParams.anyPolicyInhibited()) {
-            inhibitAnyPolicy = 0;
-        } else {
-            inhibitAnyPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
-        }
-
-        /* Initialize certIndex */
-        certIndex = 1;
-
-        /* Initialize policy tree */
-        Set<String> initExpPolSet = new HashSet<>(1);
-        initExpPolSet.add(PolicyChecker.ANY_POLICY);
-
-        rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null,
-                                      false, initExpPolSet, false);
-
-        /*
-         * Initialize each user-defined checker
-         * Shallow copy the checkers
-         */
-        userCheckers = new ArrayList<>(buildParams.certPathCheckers());
-        /* initialize each checker (just in case) */
-        for (PKIXCertPathChecker checker : userCheckers) {
-            checker.init(false);
-        }
-
-        /* Start by trusting the cert to sign CRLs */
-        crlSign = true;
-
-        init = true;
-    }
-
-    /**
-     * Update the state with the specified trust anchor.
-     *
-     * @param anchor the most-trusted CA
-     * @param buildParams builder parameters
-     */
-    public void updateState(TrustAnchor anchor, BuilderParams buildParams)
-        throws CertificateException, IOException, CertPathValidatorException
-    {
-        trustAnchor = anchor;
-        X509Certificate trustedCert = anchor.getTrustedCert();
-        if (trustedCert != null) {
-            updateState(trustedCert);
-        } else {
-            X500Principal caName = anchor.getCA();
-            updateState(anchor.getCAPublicKey(), caName);
-        }
-
-        // The user specified AlgorithmChecker and RevocationChecker may not be
-        // able to set the trust anchor until now.
-        boolean revCheckerAdded = false;
-        for (PKIXCertPathChecker checker : userCheckers) {
-            if (checker instanceof AlgorithmChecker) {
-                ((AlgorithmChecker)checker).trySetTrustAnchor(anchor);
-            } else if (checker instanceof PKIXRevocationChecker) {
-                if (revCheckerAdded) {
-                    throw new CertPathValidatorException(
-                        "Only one PKIXRevocationChecker can be specified");
-                }
-                // if it's our own, initialize it
-                if (checker instanceof RevocationChecker) {
-                    ((RevocationChecker)checker).init(anchor, buildParams);
-                }
-                ((PKIXRevocationChecker)checker).init(false);
-                revCheckerAdded = true;
-            }
-        }
-
-        // only create a RevocationChecker if revocation is enabled and
-        // a PKIXRevocationChecker has not already been added
-        if (buildParams.revocationEnabled() && !revCheckerAdded) {
-            revChecker = new RevocationChecker(anchor, buildParams);
-            revChecker.init(false);
-        }
-
-        init = false;
-    }
-
-    /**
-     * Update the state. This method is used when the most-trusted CA is
-     * a trusted public-key and caName, instead of a trusted cert.
-     *
-     * @param pubKey the public key of the trusted CA
-     * @param subjectDN the subject distinguished name of the trusted CA
-     */
-    private void updateState(PublicKey pubKey, X500Principal subjectDN) {
-
-        /* update subject DN */
-        this.subjectDN = subjectDN;
-
-        /* update subject public key */
-        this.pubKey = pubKey;
-    }
-
-    /**
-     * Update the state with the next certificate added to the path.
-     *
-     * @param cert the certificate which is used to update the state
-     */
-    public void updateState(X509Certificate cert)
-        throws CertificateException, IOException, CertPathValidatorException {
-
-        if (cert == null) {
-            return;
-        }
-
-        /* update subject DN */
-        subjectDN = cert.getSubjectX500Principal();
-
-        /* check for key needing to inherit alg parameters */
-        X509CertImpl icert = X509CertImpl.toImpl(cert);
-        PublicKey newKey = cert.getPublicKey();
-        if (PKIX.isDSAPublicKeyWithoutParams(newKey)) {
-            newKey = BasicChecker.makeInheritedParamsKey(newKey, pubKey);
-        }
-
-        /* update subject public key */
-        pubKey = newKey;
-
-        /*
-         * if this is a trusted cert (init == true), then we
-         * don't update any of the remaining fields
-         */
-        if (init) {
-            init = false;
-            return;
-        }
-
-        /* update subject key identifier */
-        subjKeyId = icert.getSubjectKeyIdentifierExtension();
-
-        /* update crlSign */
-        crlSign = RevocationChecker.certCanSignCrl(cert);
-
-        /* update current name constraints */
-        if (nc != null) {
-            nc.merge(icert.getNameConstraintsExtension());
-        } else {
-            nc = icert.getNameConstraintsExtension();
-            if (nc != null) {
-                // Make sure we do a clone here, because we're probably
-                // going to modify this object later and we don't want to
-                // be sharing it with a Certificate object!
-                nc = (NameConstraintsExtension) nc.clone();
-            }
-        }
-
-        /* update policy state variables */
-        explicitPolicy =
-            PolicyChecker.mergeExplicitPolicy(explicitPolicy, icert, false);
-        policyMapping =
-            PolicyChecker.mergePolicyMapping(policyMapping, icert);
-        inhibitAnyPolicy =
-            PolicyChecker.mergeInhibitAnyPolicy(inhibitAnyPolicy, icert);
-        certIndex++;
-
-        /*
-         * Update remaining CA certs
-         */
-        remainingCACerts =
-            ConstraintsChecker.mergeBasicConstraints(cert, remainingCACerts);
-
-        init = false;
-    }
-
-    /**
-     * Returns a boolean flag indicating if a key lacking necessary key
-     * algorithm parameters has been encountered.
-     *
-     * @return boolean flag indicating if key lacking parameters encountered.
-     */
-    @Override
-    public boolean keyParamsNeeded() {
-        /* when building in reverse, we immediately get parameters needed
-         * or else throw an exception
-         */
-        return false;
-    }
-
-    /*
-     * Clone current state. The state is cloned as each cert is
-     * added to the path. This is necessary if backtracking occurs,
-     * and a prior state needs to be restored.
-     *
-     * Note that this is a SMART clone. Not all fields are fully copied,
-     * because some of them (e.g., subjKeyId) will
-     * not have their contents modified by subsequent calls to updateState.
-     */
-    @Override
-    @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
-    public Object clone() {
-        try {
-            ReverseState clonedState = (ReverseState) super.clone();
-
-            /* clone checkers, if cloneable */
-            clonedState.userCheckers =
-                        (ArrayList<PKIXCertPathChecker>)userCheckers.clone();
-            ListIterator<PKIXCertPathChecker> li =
-                        clonedState.userCheckers.listIterator();
-            while (li.hasNext()) {
-                PKIXCertPathChecker checker = li.next();
-                if (checker instanceof Cloneable) {
-                    li.set((PKIXCertPathChecker)checker.clone());
-                }
-            }
-
-            /* make copy of name constraints */
-            if (nc != null) {
-                clonedState.nc = (NameConstraintsExtension) nc.clone();
-            }
-
-            /* make copy of policy tree */
-            if (rootNode != null) {
-                clonedState.rootNode = rootNode.copyTree();
-            }
-
-            return clonedState;
-        } catch (CloneNotSupportedException e) {
-            throw new InternalError(e.toString(), e);
-        }
-    }
-}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java b/ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java
index 61d5fd7..7445ade 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java
@@ -1041,20 +1041,17 @@
                 boolean signFlag = true;
                 List<? extends Certificate> cpList =
                     cpbr.getCertPath().getCertificates();
-                if (cpList.isEmpty()) {
-                    return;
-                }
                 try {
-                    for (int i = cpList.size()-1; i >= 0; i-- ) {
-                        X509Certificate cert = (X509Certificate)cpList.get(i);
+                    for (int i = cpList.size() - 1; i >= 0; i--) {
+                        X509Certificate cert = (X509Certificate) cpList.get(i);
 
                         if (debug != null) {
                             debug.println("RevocationChecker.buildToNewKey()"
-                                          + " index " + i + " checking "
-                                          + cert);
+                                    + " index " + i + " checking "
+                                    + cert);
                         }
                         checkCRLs(cert, prevKey2, null, signFlag, true,
-                                  stackedCerts, newAnchors);
+                                stackedCerts, newAnchors);
                         signFlag = certCanSignCrl(cert);
                         prevKey2 = cert.getPublicKey();
                     }
@@ -1073,8 +1070,10 @@
                 // If it doesn't check out, try to find a different key.
                 // And if we can't find a key, then return false.
                 PublicKey newKey = cpbr.getPublicKey();
+                X509Certificate newCert = cpList.isEmpty() ?
+                    null : (X509Certificate) cpList.get(0);
                 try {
-                    checkCRLs(currCert, newKey, (X509Certificate) cpList.get(0),
+                    checkCRLs(currCert, newKey, newCert,
                               true, false, null, params.trustAnchors());
                     // If that passed, the cert is OK!
                     return;
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java
index 9b21a99..7ff8d6c 100644
--- a/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java
+++ b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java
@@ -35,8 +35,6 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.LinkedList;
 import java.util.Set;
@@ -47,8 +45,7 @@
 import sun.security.util.Debug;
 
 /**
- * This class is able to build certification paths in either the forward
- * or reverse directions.
+ * This class builds certification paths in the forward direction.
  *
  * <p> If successful, it returns a certification path which has successfully
  * satisfied all the constraints and requirements specified in the
@@ -102,10 +99,8 @@
     /**
      * Attempts to build a certification path using the Sun build
      * algorithm from a trusted anchor(s) to a target subject, which must both
-     * be specified in the input parameter set. By default, this method will
-     * attempt to build in the forward direction. In order to build in the
-     * reverse direction, the caller needs to pass in an instance of
-     * SunCertPathBuilderParameters with the buildForward flag set to false.
+     * be specified in the input parameter set. This method will
+     * attempt to build in the forward direction: from the target to the CA.
      *
      * <p>The certification path that is constructed is validated
      * according to the PKIX specification.
@@ -162,11 +157,7 @@
         policyTreeResult = null;
         LinkedList<X509Certificate> certPathList = new LinkedList<>();
         try {
-            if (buildParams.buildForward()) {
-                buildForward(adjList, certPathList, searchAllCertStores);
-            } else {
-                buildReverse(adjList, certPathList);
-            }
+            buildForward(adjList, certPathList, searchAllCertStores);
         } catch (GeneralSecurityException | IOException e) {
             if (debug != null) {
                 debug.println("SunCertPathBuilder.engineBuild() exception in "
@@ -210,82 +201,6 @@
     }
 
     /*
-     * Private build reverse method.
-     */
-    private void buildReverse(List<List<Vertex>> adjacencyList,
-                              LinkedList<X509Certificate> certPathList)
-        throws GeneralSecurityException, IOException
-    {
-        if (debug != null) {
-            debug.println("SunCertPathBuilder.buildReverse()...");
-            debug.println("SunCertPathBuilder.buildReverse() InitialPolicies: "
-                + buildParams.initialPolicies());
-        }
-
-        ReverseState currentState = new ReverseState();
-        /* Initialize adjacency list */
-        adjacencyList.clear();
-        adjacencyList.add(new LinkedList<Vertex>());
-
-        /*
-         * Perform a search using each trust anchor, until a valid
-         * path is found
-         */
-        Iterator<TrustAnchor> iter = buildParams.trustAnchors().iterator();
-        while (iter.hasNext()) {
-            TrustAnchor anchor = iter.next();
-
-            /* check if anchor satisfies target constraints */
-            if (anchorIsTarget(anchor, buildParams.targetCertConstraints())) {
-                this.trustAnchor = anchor;
-                this.pathCompleted = true;
-                this.finalPublicKey = anchor.getTrustedCert().getPublicKey();
-                break;
-            }
-
-            // skip anchor if it contains a DSA key with no DSA params
-            X509Certificate trustedCert = anchor.getTrustedCert();
-            PublicKey pubKey = trustedCert != null ? trustedCert.getPublicKey()
-                                                   : anchor.getCAPublicKey();
-
-            if (PKIX.isDSAPublicKeyWithoutParams(pubKey)) {
-                continue;
-            }
-
-            /* Initialize current state */
-            currentState.initState(buildParams);
-            currentState.updateState(anchor, buildParams);
-
-            currentState.algorithmChecker = new AlgorithmChecker(anchor);
-            // Android-removed: Android doesn't use this mechanism for checking untrusted certificates
-            // currentState.untrustedChecker = new UntrustedChecker();
-            try {
-                depthFirstSearchReverse(null, currentState,
-                                        new ReverseBuilder(buildParams),
-                                        adjacencyList, certPathList);
-            } catch (GeneralSecurityException | IOException e) {
-                // continue on error if more anchors to try
-                if (iter.hasNext())
-                    continue;
-                else
-                    throw e;
-            }
-
-            // break out of loop if search is successful
-            if (pathCompleted) {
-                break;
-            }
-        }
-
-        if (debug != null) {
-            debug.println("SunCertPathBuilder.buildReverse() returned from "
-                + "depthFirstSearchReverse()");
-            debug.println("SunCertPathBuilder.buildReverse() "
-                + "certPathList.size: " + certPathList.size());
-        }
-    }
-
-    /*
      * Private build forward method.
      */
     private void buildForward(List<List<Vertex>> adjacencyList,
@@ -634,147 +549,6 @@
     }
 
     /*
-     * This method performs a depth first search for a certification
-     * path while building reverse which meets the requirements set in
-     * the parameters object.
-     * It uses an adjacency list to store all certificates which were
-     * tried (i.e. at one time added to the path - they may not end up in
-     * the final path if backtracking occurs). This information can
-     * be used later to debug or demo the build.
-     *
-     * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
-     * for an explanation of the DFS algorithm.
-     *
-     * @param dN the distinguished name being currently searched for certs
-     * @param currentState the current PKIX validation state
-     */
-    private void depthFirstSearchReverse(X500Principal dN,
-                                         ReverseState currentState,
-                                         ReverseBuilder builder,
-                                         List<List<Vertex>> adjList,
-                                         LinkedList<X509Certificate> cpList)
-        throws GeneralSecurityException, IOException
-    {
-        if (debug != null)
-            debug.println("SunCertPathBuilder.depthFirstSearchReverse(" + dN
-                + ", " + currentState.toString() + ")");
-
-        /*
-         * Find all the certificates issued by dN which
-         * satisfy the PKIX certification path constraints.
-         */
-        Collection<X509Certificate> certs =
-            builder.getMatchingCerts(currentState, buildParams.certStores());
-        List<Vertex> vertices = addVertices(certs, adjList);
-        if (debug != null)
-            debug.println("SunCertPathBuilder.depthFirstSearchReverse(): "
-                + "certs.size=" + vertices.size());
-
-        /*
-         * For each cert in the collection, verify anything
-         * that hasn't been checked yet (signature, revocation, etc)
-         * and check for loops. Call depthFirstSearchReverse()
-         * recursively for each good cert.
-         */
-        for (Vertex vertex : vertices) {
-            /**
-             * Restore state to currentState each time through the loop.
-             * This is important because some of the user-defined
-             * checkers modify the state, which MUST be restored if
-             * the cert eventually fails to lead to the target and
-             * the next matching cert is tried.
-             */
-            ReverseState nextState = (ReverseState) currentState.clone();
-            X509Certificate cert = vertex.getCertificate();
-            try {
-                builder.verifyCert(cert, nextState, cpList);
-            } catch (GeneralSecurityException gse) {
-                if (debug != null)
-                    debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
-                        + ": validation failed: " + gse);
-                vertex.setThrowable(gse);
-                continue;
-            }
-
-            /*
-             * Certificate is good, add it to the path (if it isn't a
-             * self-signed cert) and update state
-             */
-            if (!currentState.isInitial())
-                builder.addCertToPath(cert, cpList);
-            // save trust anchor
-            this.trustAnchor = currentState.trustAnchor;
-
-            /*
-             * Check if path is completed, return ASAP if so.
-             */
-            if (builder.isPathCompleted(cert)) {
-                if (debug != null)
-                    debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
-                        + ": path completed!");
-                pathCompleted = true;
-
-                PolicyNodeImpl rootNode = nextState.rootNode;
-
-                if (rootNode == null)
-                    policyTreeResult = null;
-                else {
-                    policyTreeResult = rootNode.copyTree();
-                    ((PolicyNodeImpl)policyTreeResult).setImmutable();
-                }
-
-                /*
-                 * Extract and save the final target public key
-                 */
-                finalPublicKey = cert.getPublicKey();
-                if (PKIX.isDSAPublicKeyWithoutParams(finalPublicKey)) {
-                    finalPublicKey =
-                        BasicChecker.makeInheritedParamsKey
-                            (finalPublicKey, currentState.pubKey);
-                }
-
-                return;
-            }
-
-            /* Update the PKIX state */
-            nextState.updateState(cert);
-
-            /*
-             * Append an entry for cert in adjacency list and
-             * set index for current vertex.
-             */
-            adjList.add(new LinkedList<Vertex>());
-            vertex.setIndex(adjList.size() - 1);
-
-            /* recursively search for matching certs at next dN */
-            depthFirstSearchReverse(cert.getSubjectX500Principal(), nextState,
-                                    builder, adjList, cpList);
-
-            /*
-             * If path has been completed, return ASAP!
-             */
-            if (pathCompleted) {
-                return;
-            } else {
-                /*
-                 * If we get here, it means we have searched all possible
-                 * certs issued by the dN w/o finding any matching certs. This
-                 * means we have to backtrack to the previous cert in the path
-                 * and try some other paths.
-                 */
-                if (debug != null)
-                    debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
-                        + ": backtracking");
-                if (!currentState.isInitial())
-                    builder.removeFinalCertFromPath(cpList);
-            }
-        }
-        if (debug != null)
-            debug.println("SunCertPathBuilder.depthFirstSearchReverse() all "
-                + "certs in this adjacency list checked");
-    }
-
-    /*
      * Adds a collection of matching certificates to the
      * adjacency list.
      */
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderParameters.java b/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderParameters.java
deleted file mode 100644
index 186e252..0000000
--- a/ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderParameters.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.provider.certpath;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.cert.*;
-import java.util.Set;
-
-/**
- * This class specifies the set of parameters used as input for the Sun
- * certification path build algorithm. It is identical to PKIXBuilderParameters
- * with the addition of a <code>buildForward</code> parameter which allows
- * the caller to specify whether or not the path should be constructed in
- * the forward direction.
- *
- * The default for the <code>buildForward</code> parameter is
- * true, which means that the build algorithm should construct paths
- * from the target subject back to the trusted anchor.
- *
- * @since       1.4
- * @author      Sean Mullan
- * @author      Yassir Elley
- */
-public class SunCertPathBuilderParameters extends PKIXBuilderParameters {
-
-    private boolean buildForward = true;
-
-    /**
-     * Creates an instance of <code>SunCertPathBuilderParameters</code> with the
-     * specified parameter values.
-     *
-     * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
-     * @param targetConstraints a <code>CertSelector</code> specifying the
-     * constraints on the target certificate
-     * @throws InvalidAlgorithmParameterException if the specified
-     * <code>Set</code> is empty <code>(trustAnchors.isEmpty() == true)</code>
-     * @throws NullPointerException if the specified <code>Set</code> is
-     * <code>null</code>
-     * @throws ClassCastException if any of the elements in the <code>Set</code>
-     * are not of type <code>java.security.cert.TrustAnchor</code>
-     */
-    public SunCertPathBuilderParameters(Set<TrustAnchor> trustAnchors,
-        CertSelector targetConstraints) throws InvalidAlgorithmParameterException
-    {
-        super(trustAnchors, targetConstraints);
-        setBuildForward(true);
-    }
-
-    /**
-     * Creates an instance of <code>SunCertPathBuilderParameters</code> that
-     * uses the specified <code>KeyStore</code> to populate the set
-     * of most-trusted CA certificates.
-     *
-     * @param keystore A keystore from which the set of most-trusted
-     * CA certificates will be populated.
-     * @param targetConstraints a <code>CertSelector</code> specifying the
-     * constraints on the target certificate
-     * @throws KeyStoreException if the keystore has not been initialized.
-     * @throws InvalidAlgorithmParameterException if the keystore does
-     * not contain at least one trusted certificate entry
-     * @throws NullPointerException if the keystore is <code>null</code>
-     */
-    public SunCertPathBuilderParameters(KeyStore keystore,
-        CertSelector targetConstraints)
-        throws KeyStoreException, InvalidAlgorithmParameterException
-    {
-        super(keystore, targetConstraints);
-        setBuildForward(true);
-    }
-
-    /**
-     * Returns the value of the buildForward flag.
-     *
-     * @return the value of the buildForward flag
-     */
-    public boolean getBuildForward() {
-        return this.buildForward;
-    }
-
-    /**
-     * Sets the value of the buildForward flag. If true, paths
-     * are built from the target subject to the trusted anchor.
-     * If false, paths are built from the trusted anchor to the
-     * target subject. The default value if not specified is true.
-     *
-     * @param buildForward the value of the buildForward flag
-     */
-    public void setBuildForward(boolean buildForward) {
-        this.buildForward = buildForward;
-    }
-
-    /**
-     * Returns a formatted string describing the parameters.
-     *
-     * @return a formatted string describing the parameters.
-     */
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[\n");
-        sb.append(super.toString());
-        sb.append("  Build Forward Flag: " + String.valueOf(buildForward) + "\n");
-        sb.append("]\n");
-        return sb.toString();
-    }
-}
diff --git a/ojluni/src/main/java/sun/security/util/AbstractAlgorithmConstraints.java b/ojluni/src/main/java/sun/security/util/AbstractAlgorithmConstraints.java
index 1b64d9d..2e851e2 100644
--- a/ojluni/src/main/java/sun/security/util/AbstractAlgorithmConstraints.java
+++ b/ojluni/src/main/java/sun/security/util/AbstractAlgorithmConstraints.java
@@ -46,19 +46,23 @@
     // Get algorithm constraints from the specified security property.
     static String[] getAlgorithms(String propertyName) {
         String property = AccessController.doPrivileged(
-                (PrivilegedAction<String>) () -> Security.getProperty(
-                        propertyName));
+                new PrivilegedAction<String>() {
+                    @Override
+                    public String run() {
+                        return Security.getProperty(propertyName);
+                    }
+                });
+
 
         String[] algorithmsInProperty = null;
         if (property != null && !property.isEmpty()) {
             // remove double quote marks from beginning/end of the property
-            if (property.charAt(0) == '"'
-                    && property.charAt(property.length() - 1) == '"') {
+            if (property.length() >= 2 && property.charAt(0) == '"' &&
+                    property.charAt(property.length() - 1) == '"') {
                 property = property.substring(1, property.length() - 1);
             }
             algorithmsInProperty = property.split(",");
-            for (int i = 0; i < algorithmsInProperty.length;
-                    i++) {
+            for (int i = 0; i < algorithmsInProperty.length; i++) {
                 algorithmsInProperty[i] = algorithmsInProperty[i].trim();
             }
         }
diff --git a/ojluni/src/main/java/sun/security/util/AnchorCertificates.java b/ojluni/src/main/java/sun/security/util/AnchorCertificates.java
index 6bc0030..8498342 100644
--- a/ojluni/src/main/java/sun/security/util/AnchorCertificates.java
+++ b/ojluni/src/main/java/sun/security/util/AnchorCertificates.java
@@ -56,7 +56,7 @@
                 try {
                     cacerts = KeyStore.getInstance("JKS");
                     try (FileInputStream fis = new FileInputStream(f)) {
-                        cacerts.load(fis, "changeit".toCharArray());
+                        cacerts.load(fis, null);
                         certs = new HashSet<>();
                         Enumeration<String> list = cacerts.aliases();
                         String alias;
diff --git a/ojluni/src/main/java/sun/security/util/DerInputBuffer.java b/ojluni/src/main/java/sun/security/util/DerInputBuffer.java
index b375c60..01f7df5 100644
--- a/ojluni/src/main/java/sun/security/util/DerInputBuffer.java
+++ b/ojluni/src/main/java/sun/security/util/DerInputBuffer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,6 +71,7 @@
         return retval;
     }
 
+    // BEGIN Android-added: Added getPos & getSlice, needed for APK parsing
     int getPos() {
         return pos;
     }
@@ -80,6 +81,7 @@
         System.arraycopy(buf, startPos, result, 0, size);
         return result;
     }
+    // END Android-added: Added getPos & getSlice, needed for APK parsing
 
     int peek() throws IOException {
         if (pos >= count)
@@ -157,6 +159,11 @@
         System.arraycopy(buf, pos, bytes, 0, len);
         skip(len);
 
+        // check to make sure no extra leading 0s for DER
+        if (len >= 2 && (bytes[0] == 0) && (bytes[1] >= 0)) {
+            throw new IOException("Invalid encoding: redundant leading 0s");
+        }
+
         if (makePositive) {
             return new BigInteger(1, bytes);
         } else {
diff --git a/ojluni/src/main/java/sun/security/util/DerInputStream.java b/ojluni/src/main/java/sun/security/util/DerInputStream.java
index dae8afd..b182d4e 100644
--- a/ojluni/src/main/java/sun/security/util/DerInputStream.java
+++ b/ojluni/src/main/java/sun/security/util/DerInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -77,7 +77,7 @@
      * @param data the buffer from which to create the string (CONSUMED)
      */
     public DerInputStream(byte[] data) throws IOException {
-        init(data, 0, data.length);
+        init(data, 0, data.length, true);
     }
 
     /**
@@ -92,23 +92,48 @@
      *          starting at "offset"
      */
     public DerInputStream(byte[] data, int offset, int len) throws IOException {
-        init(data, offset, len);
+        init(data, offset, len, true);
+    }
+
+    /**
+     * Create a DER input stream from part of a data buffer with
+     * additional arg to indicate whether to allow constructed
+     * indefinite-length encoding.
+     * The buffer is not copied, it is shared.  Accordingly, the
+     * buffer should be treated as read-only.
+     *
+     * @param data the buffer from which to create the string (CONSUMED)
+     * @param offset the first index of <em>data</em> which will
+     *          be read as DER input in the new stream
+     * @param len how long a chunk of the buffer to use,
+     *          starting at "offset"
+     * @param allowIndefiniteLength whether to allow constructed
+     *          indefinite-length encoding
+     */
+    public DerInputStream(byte[] data, int offset, int len,
+        boolean allowIndefiniteLength) throws IOException {
+        init(data, offset, len, allowIndefiniteLength);
     }
 
     /*
      * private helper routine
      */
-    private void init(byte[] data, int offset, int len) throws IOException {
+    private void init(byte[] data, int offset, int len,
+        boolean allowIndefiniteLength) throws IOException {
         if ((offset+2 > data.length) || (offset+len > data.length)) {
             throw new IOException("Encoding bytes too short");
         }
         // check for indefinite length encoding
         if (DerIndefLenConverter.isIndefinite(data[offset+1])) {
-            byte[] inData = new byte[len];
-            System.arraycopy(data, offset, inData, 0, len);
+            if (!allowIndefiniteLength) {
+                throw new IOException("Indefinite length BER encoding found");
+            } else {
+                byte[] inData = new byte[len];
+                System.arraycopy(data, offset, inData, 0, len);
 
-            DerIndefLenConverter derIn = new DerIndefLenConverter();
-            buffer = new DerInputBuffer(derIn.convert(inData));
+                DerIndefLenConverter derIn = new DerIndefLenConverter();
+                buffer = new DerInputBuffer(derIn.convert(inData));
+            }
         } else
             buffer = new DerInputBuffer(data, offset, len);
         buffer.mark(Integer.MAX_VALUE);
@@ -233,12 +258,21 @@
          * First byte = number of excess bits in the last octet of the
          * representation.
          */
-        int validBits = length*8 - buffer.read();
+        int excessBits = buffer.read();
+        if (excessBits < 0) {
+            throw new IOException("Unused bits of bit string invalid");
+        }
+        int validBits = length*8 - excessBits;
+        if (validBits < 0) {
+            throw new IOException("Valid bits of bit string invalid");
+        }
 
         byte[] repn = new byte[length];
 
-        if ((length != 0) && (buffer.read(repn) != length))
-            throw new IOException("short read of DER bit string");
+        if ((length != 0) && (buffer.read(repn) != length)) {
+            throw new IOException("Short read of DER bit string");
+        }
+
         return new BitArray(validBits, repn);
     }
 
@@ -252,7 +286,7 @@
         int length = getLength(buffer);
         byte[] retval = new byte[length];
         if ((length != 0) && (buffer.read(retval) != length))
-            throw new IOException("short read of DER octet string");
+            throw new IOException("Short read of DER octet string");
 
         return retval;
     }
@@ -262,7 +296,7 @@
      */
     public void getBytes(byte[] val) throws IOException {
         if ((val.length != 0) && (buffer.read(val) != val.length)) {
-            throw new IOException("short read of DER octet string");
+            throw new IOException("Short read of DER octet string");
         }
     }
 
@@ -384,7 +418,7 @@
         DerInputStream  newstr;
 
         byte lenByte = (byte)buffer.read();
-        int len = getLength((lenByte & 0xff), buffer);
+        int len = getLength(lenByte, buffer);
 
         if (len == -1) {
            // indefinite length encoding found
@@ -430,7 +464,7 @@
         } while (newstr.available() > 0);
 
         if (newstr.available() != 0)
-            throw new IOException("extra data at end of vector");
+            throw new IOException("Extra data at end of vector");
 
         /*
          * Now stick them into the array we're returning.
@@ -521,7 +555,7 @@
         int length = getLength(buffer);
         byte[] retval = new byte[length];
         if ((length != 0) && (buffer.read(retval) != length))
-            throw new IOException("short read of DER " +
+            throw new IOException("Short read of DER " +
                                   stringName + " string");
 
         return new String(retval, enc);
@@ -582,7 +616,11 @@
      */
     static int getLength(int lenByte, InputStream in) throws IOException {
         int value, tmp;
+        if (lenByte == -1) {
+            throw new IOException("Short read of DER length");
+        }
 
+        String mdName = "DerInputStream.getLength(): ";
         tmp = lenByte;
         if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum
             value = tmp;
@@ -596,17 +634,23 @@
             if (tmp == 0)
                 return -1;
             if (tmp < 0 || tmp > 4)
-                throw new IOException("DerInputStream.getLength(): lengthTag="
-                    + tmp + ", "
+                throw new IOException(mdName + "lengthTag=" + tmp + ", "
                     + ((tmp < 0) ? "incorrect DER encoding." : "too big."));
 
-            for (value = 0; tmp > 0; tmp --) {
+            value = 0x0ff & in.read();
+            tmp--;
+            if (value == 0) {
+                // DER requires length value be encoded in minimum number of bytes
+                throw new IOException(mdName + "Redundant length bytes found");
+            }
+            while (tmp-- > 0) {
                 value <<= 8;
                 value += 0x0ff & in.read();
             }
             if (value < 0) {
-                throw new IOException("DerInputStream.getLength(): "
-                        + "Invalid length bytes");
+                throw new IOException(mdName + "Invalid length bytes");
+            } else if (value <= 127) {
+                throw new IOException(mdName + "Should use short form for length");
             }
         }
         return value;
diff --git a/ojluni/src/main/java/sun/security/util/DerValue.java b/ojluni/src/main/java/sun/security/util/DerValue.java
index 6bca1f7..21116dc 100644
--- a/ojluni/src/main/java/sun/security/util/DerValue.java
+++ b/ojluni/src/main/java/sun/security/util/DerValue.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -257,7 +257,7 @@
         int startPosInInput = in.getPos();
         tag = (byte)in.read();
         byte lenByte = (byte)in.read();
-        length = DerInputStream.getLength((lenByte & 0xff), in);
+        length = DerInputStream.getLength(lenByte, in);
         if (length == -1) {  // indefinite length encoding found
             DerInputBuffer inbuf = in.dup();
             int readLen = inbuf.available();
@@ -375,7 +375,7 @@
 
         tag = (byte)in.read();
         byte lenByte = (byte)in.read();
-        length = DerInputStream.getLength((lenByte & 0xff), in);
+        length = DerInputStream.getLength(lenByte, in);
         if (length == -1) { // indefinite length encoding found
             int readLen = in.available();
             int offset = 2;     // for tag and length bytes
diff --git a/ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java b/ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java
index d8c1462..aecb341 100644
--- a/ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java
+++ b/ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java
@@ -56,6 +56,9 @@
     public final static String PROPERTY_TLS_DISABLED_ALGS =
             "jdk.tls.disabledAlgorithms";
 
+    // the known security property, jdk.jar.disabledAlgorithms
+    public static final String PROPERTY_JAR_DISABLED_ALGS =
+            "jdk.jar.disabledAlgorithms";
 
     private final String[] disabledAlgorithms;
     private final Constraints algorithmConstraints;
@@ -257,14 +260,15 @@
                                     toUpperCase(Locale.ENGLISH));
                     policy = constraintEntry.substring(space + 1);
                 } else {
-                    constraintsMap.computeIfAbsent(
+                    constraintsMap.putIfAbsent(
                             constraintEntry.toUpperCase(Locale.ENGLISH),
-                            k -> new HashSet<>());
+                            new HashSet<>());
                     continue;
                 }
 
                 // Convert constraint conditions into Constraint classes
-                Constraint c, lastConstraint = null;
+                Constraint c = null;
+                Constraint lastConstraint = null;
                 // Allow only one jdkCA entry per constraint entry
                 boolean jdkCALimit = false;
 
@@ -292,11 +296,7 @@
                         }
                         c = new jdkCAConstraint(algorithm);
                         jdkCALimit = true;
-                    } else {
-                        throw new IllegalArgumentException("Error in security" +
-                                " property. Constraint unknown: " + entry);
                     }
-
                     // Link multiple conditions for a single constraint
                     // into a linked list.
                     if (lastConstraint == null) {
@@ -304,7 +304,9 @@
                             constraintsMap.putIfAbsent(algorithm,
                                     new HashSet<>());
                         }
-                        constraintsMap.get(algorithm).add(c);
+                        if (c != null) {
+                            constraintsMap.get(algorithm).add(c);
+                        }
                     } else {
                         lastConstraint.nextConstraint = c;
                     }
diff --git a/ojluni/src/main/java/sun/security/util/SignatureFileVerifier.java b/ojluni/src/main/java/sun/security/util/SignatureFileVerifier.java
index fa0f530..ed563dc 100644
--- a/ojluni/src/main/java/sun/security/util/SignatureFileVerifier.java
+++ b/ojluni/src/main/java/sun/security/util/SignatureFileVerifier.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,26 +25,49 @@
 
 package sun.security.util;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.CodeSigner;
+import java.security.CryptoPrimitive;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
 import java.security.cert.CertPath;
 import java.security.cert.X509Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
-import java.security.*;
-import java.io.*;
-import java.util.*;
-import java.util.jar.*;
-
-import sun.security.pkcs.*;
+import java.util.ArrayList;
 import java.util.Base64;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarException;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
 
 import sun.security.jca.Providers;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
 
 public class SignatureFileVerifier {
 
     /* Are we debugging ? */
     private static final Debug debug = Debug.getInstance("jar");
 
-    /* cache of CodeSigner objects */
+    private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET =
+            Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
+
+    private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
+            new DisabledAlgorithmConstraints(
+                    DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
+
     private ArrayList<CodeSigner[]> signerCache;
 
     private static final String ATTR_DIGEST =
@@ -200,8 +223,15 @@
 
     /** get digest from cache */
 
-    private MessageDigest getDigest(String algorithm)
-    {
+    private MessageDigest getDigest(String algorithm) throws SignatureException {
+        // check that algorithm is not restricted
+        if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, algorithm, null)) {
+            SignatureException e =
+                    new SignatureException("SignatureFile check failed. " +
+                            "Disabled algorithm used: " + algorithm);
+            throw e;
+        }
+
         if (createdDigests == null)
             createdDigests = new HashMap<String, MessageDigest>();
 
@@ -321,7 +351,7 @@
     private boolean verifyManifestHash(Manifest sf,
                                        ManifestDigester md,
                                        List<Object> manifestDigests)
-         throws IOException
+         throws IOException, SignatureException
     {
         Attributes mattr = sf.getMainAttributes();
         boolean manifestSigned = false;
@@ -365,7 +395,7 @@
 
     private boolean verifyManifestMainAttrs(Manifest sf,
                                         ManifestDigester md)
-         throws IOException
+         throws IOException, SignatureException
     {
         Attributes mattr = sf.getMainAttributes();
         boolean attrsVerified = true;
@@ -431,14 +461,14 @@
     private boolean verifySection(Attributes sfAttr,
                                   String name,
                                   ManifestDigester md)
-         throws IOException
+         throws IOException, SignatureException
     {
         boolean oneDigestVerified = false;
         ManifestDigester.Entry mde = md.get(name,block.isOldStyle());
 
         if (mde == null) {
             throw new SecurityException(
-                  "no manifiest section for signature file entry "+name);
+                  "no manifest section for signature file entry "+name);
         }
 
         if (sfAttr != null) {
diff --git a/ojluni/src/main/java/sun/util/calendar/CalendarSystem.java b/ojluni/src/main/java/sun/util/calendar/CalendarSystem.java
index 58707fb..17ad0e8 100644
--- a/ojluni/src/main/java/sun/util/calendar/CalendarSystem.java
+++ b/ojluni/src/main/java/sun/util/calendar/CalendarSystem.java
@@ -122,7 +122,7 @@
             return GREGORIAN_INSTANCE;
         }
 
-        //Android-changed: remove lazy initialization, use classes instead of class names.
+        // Android-changed: remove lazy initialization, use classes instead of class names.
 
         CalendarSystem cal = calendars.get(calendarName);
         if (cal != null) {
diff --git a/ojluni/src/main/native/PlainSocketImpl.c b/ojluni/src/main/native/PlainSocketImpl.c
deleted file mode 100644
index c4b5be7..0000000
--- a/ojluni/src/main/native/PlainSocketImpl.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#if defined(__linux__) && !defined(USE_SELECT)
-#include <sys/poll.h>
-#endif
-#include <netinet/tcp.h>        /* Defines TCP_NODELAY, needed for 2.6 */
-#include <netinet/in.h>
-#ifdef __linux__
-#include <netinet/ip.h>
-#endif
-#include <netdb.h>
-#include <stdlib.h>
-
-#ifdef __solaris__
-#include <fcntl.h>
-#endif
-#ifdef __linux__
-#include <unistd.h>
-//#include <sys/sysctl.h>
-#endif
-
-#include "jvm.h"
-#include "jni_util.h"
-#include "net_util.h"
-
-#include "java_net_SocketOptions.h"
-#include "java_net_PlainSocketImpl.h"
-#include "JNIHelp.h"
-
-#define NATIVE_METHOD(className, functionName, signature) \
-{ #functionName, signature, (void*)(className ## _ ## functionName) }
-
-/************************************************************************
- * PlainSocketImpl
- */
-
-static jfieldID IO_fd_fdID;
-
-jfieldID psi_fdID;
-jfieldID psi_addressID;
-jfieldID psi_ipaddressID;
-jfieldID psi_portID;
-jfieldID psi_localportID;
-jfieldID psi_timeoutID;
-jfieldID psi_trafficClassID;
-jfieldID psi_serverSocketID;
-jfieldID psi_fdLockID;
-jfieldID psi_closePendingID;
-
-extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);
-
-
-#define SET_NONBLOCKING(fd) {           \
-        int flags = fcntl(fd, F_GETFL); \
-        flags |= O_NONBLOCK;            \
-        fcntl(fd, F_SETFL, flags);      \
-}
-
-#define SET_BLOCKING(fd) {              \
-        int flags = fcntl(fd, F_GETFL); \
-        flags &= ~O_NONBLOCK;           \
-        fcntl(fd, F_SETFL, flags);      \
-}
-
-/*
- * Return the file descriptor given a PlainSocketImpl
- */
-static int getFD(JNIEnv *env, jobject this) {
-    jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
-    CHECK_NULL_RETURN(fdObj, -1);
-    return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-}
-
-static void PlainSocketImpl_initProto(JNIEnv *env) {
-    jclass cls = (*env)->FindClass(env, "java/net/PlainSocketImpl");
-    psi_fdID = (*env)->GetFieldID(env, cls , "fd",
-                                  "Ljava/io/FileDescriptor;");
-    CHECK_NULL(psi_fdID);
-    psi_addressID = (*env)->GetFieldID(env, cls, "address",
-                                          "Ljava/net/InetAddress;");
-    CHECK_NULL(psi_addressID);
-    psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
-    CHECK_NULL(psi_portID);
-    psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
-    CHECK_NULL(psi_localportID);
-    psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
-    CHECK_NULL(psi_timeoutID);
-    psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
-    CHECK_NULL(psi_trafficClassID);
-    psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",
-                        "Ljava/net/ServerSocket;");
-    CHECK_NULL(psi_serverSocketID);
-    psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",
-                                      "Ljava/lang/Object;");
-    CHECK_NULL(psi_fdLockID);
-    psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");
-    CHECK_NULL(psi_closePendingID);
-    IO_fd_fdID = NET_GetFileDescriptorID(env);
-    CHECK_NULL(IO_fd_fdID);
-}
-
-/* a global reference to the java.net.SocketException class. In
- * socketCreate, we ensure that this is initialized. This is to
- * prevent the problem where socketCreate runs out of file
- * descriptors, and is then unable to load the exception class.
- */
-static jclass socketExceptionCls;
-
-/*
- * Class:     java_net_PlainSocketImpl
- * Method:    socketSetOption0
- * Signature: (IZLjava/lang/Object;)V
- */
-JNIEXPORT void JNICALL
-PlainSocketImpl_socketSetOption0(JNIEnv *env, jobject this,
-                                              jint cmd, jboolean on,
-                                              jobject value) {
-    int fd;
-    int level, optname, optlen;
-    union {
-        int i;
-        struct linger ling;
-    } optval;
-
-    /*
-     * Check that socket hasn't been closed
-     */
-    fd = getFD(env, this);
-    if (fd < 0) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        "Socket closed");
-        return;
-    }
-
-    /*
-     * SO_TIMEOUT is a NOOP on Solaris/Linux
-     */
-    if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
-        return;
-    }
-
-    /*
-     * Map the Java level socket option to the platform specific
-     * level and option name.
-     */
-    if (NET_MapSocketOption(cmd, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
-        return;
-    }
-
-    switch (cmd) {
-        case java_net_SocketOptions_SO_SNDBUF :
-        case java_net_SocketOptions_SO_RCVBUF :
-        case java_net_SocketOptions_SO_LINGER :
-        case java_net_SocketOptions_IP_TOS :
-            {
-                jclass cls;
-                jfieldID fid;
-
-                cls = (*env)->FindClass(env, "java/lang/Integer");
-                CHECK_NULL(cls);
-                fid = (*env)->GetFieldID(env, cls, "value", "I");
-                CHECK_NULL(fid);
-
-                if (cmd == java_net_SocketOptions_SO_LINGER) {
-                    if (on) {
-                        optval.ling.l_onoff = 1;
-                        optval.ling.l_linger = (*env)->GetIntField(env, value, fid);
-                    } else {
-                        optval.ling.l_onoff = 0;
-                        optval.ling.l_linger = 0;
-                    }
-                    optlen = sizeof(optval.ling);
-                } else {
-                    optval.i = (*env)->GetIntField(env, value, fid);
-                    optlen = sizeof(optval.i);
-                }
-
-                break;
-            }
-
-        /* Boolean -> int */
-        default :
-            optval.i = (on ? 1 : 0);
-            optlen = sizeof(optval.i);
-
-    }
-
-    if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
-#ifdef __solaris__
-        if (errno == EINVAL) {
-            // On Solaris setsockopt will set errno to EINVAL if the socket
-            // is closed. The default error message is then confusing
-            char fullMsg[128];
-            jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer");
-            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
-            return;
-        }
-#endif /* __solaris__ */
-        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
-                                      "Error setting socket option");
-    }
-}
-
-/*
- * Class:     java_net_PlainSocketImpl
- * Method:    socketGetOption
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL
-PlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
-                                              jint cmd, jobject iaContainerObj) {
-
-    int fd;
-    int level, optname, optlen;
-    union {
-        int i;
-        struct linger ling;
-    } optval;
-
-    /*
-     * Check that socket hasn't been closed
-     */
-    fd = getFD(env, this);
-    if (fd < 0) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        "Socket closed");
-        return -1;
-    }
-
-    /*
-     * SO_BINDADDR isn't a socket option
-     */
-    if (cmd == java_net_SocketOptions_SO_BINDADDR) {
-        SOCKADDR him;
-        socklen_t len = 0;
-        int port;
-        jobject iaObj;
-        jclass iaCntrClass;
-        jfieldID iaFieldID;
-
-        len = SOCKADDR_LEN;
-
-        if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {
-            NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
-                             "Error getting socket name");
-            return -1;
-        }
-        iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
-        CHECK_NULL_RETURN(iaObj, -1);
-
-        iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
-        iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
-        CHECK_NULL_RETURN(iaFieldID, -1);
-        (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
-        return 0; /* notice change from before */
-    }
-
-    /*
-     * Map the Java level socket option to the platform specific
-     * level and option name.
-     */
-    if (NET_MapSocketOption(cmd, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
-        return -1;
-    }
-
-    /*
-     * Args are int except for SO_LINGER
-     */
-    if (cmd == java_net_SocketOptions_SO_LINGER) {
-        optlen = sizeof(optval.ling);
-    } else {
-        optlen = sizeof(optval.i);
-    }
-
-    if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
-        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
-                                      "Error getting socket option");
-        return -1;
-    }
-
-    switch (cmd) {
-        case java_net_SocketOptions_SO_LINGER:
-            return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
-
-        case java_net_SocketOptions_SO_SNDBUF:
-        case java_net_SocketOptions_SO_RCVBUF:
-        case java_net_SocketOptions_IP_TOS:
-            return optval.i;
-
-        default :
-            return (optval.i == 0) ? -1 : 1;
-    }
-}
-
-
-static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(PlainSocketImpl, socketGetOption, "(ILjava/lang/Object;)I"),
-  NATIVE_METHOD(PlainSocketImpl, socketSetOption0, "(IZLjava/lang/Object;)V"),
-};
-
-void register_java_net_PlainSocketImpl(JNIEnv* env) {
-  jniRegisterNativeMethods(env, "java/net/PlainSocketImpl", gMethods, NELEM(gMethods));
-  PlainSocketImpl_initProto(env);
-}
diff --git a/ojluni/src/main/native/Register.cpp b/ojluni/src/main/native/Register.cpp
index 40c034c..588eedb 100644
--- a/ojluni/src/main/native/Register.cpp
+++ b/ojluni/src/main/native/Register.cpp
@@ -56,7 +56,6 @@
 extern void register_java_net_Inet6Address(JNIEnv*);
 extern void register_java_net_InetAddress(JNIEnv*);
 extern void register_java_net_PlainDatagramSocketImpl(JNIEnv*);
-extern void register_java_net_PlainSocketImpl(JNIEnv*);
 extern void register_java_net_SocketInputStream(JNIEnv*);
 extern void register_java_net_SocketOutputStream(JNIEnv*);
 extern void register_java_nio_Bits(JNIEnv* env);
@@ -125,7 +124,6 @@
     register_java_net_InetAddress(env);
     register_java_net_Inet4Address(env);
     register_java_net_Inet6Address(env);
-    register_java_net_PlainSocketImpl(env);
     register_java_net_SocketInputStream(env);
     register_java_net_SocketOutputStream(env);
     register_java_nio_Bits(env);
diff --git a/ojluni/src/main/native/System.c b/ojluni/src/main/native/System.c
index e75e01c..22c4d52 100644
--- a/ojluni/src/main/native/System.c
+++ b/ojluni/src/main/native/System.c
@@ -244,10 +244,6 @@
     }
 
     WITH_PLATFORM_STRING(env, javaMessage, message) {
-      if (message == NULL) {
-          // Since this function is used for last-gasp debugging output, be noisy on failure.
-          return;
-      }
       LOG_PRI(priority, "System", "%s", message);
     } END_PLATFORM_STRING(env, message);
 
diff --git a/ojluni/src/main/native/java_net_SocketOptions.h b/ojluni/src/main/native/java_net_SocketOptions.h
deleted file mode 100644
index e428bb5..0000000
--- a/ojluni/src/main/native/java_net_SocketOptions.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* This file was generated from java/net/SocketOptions.java and is licensed
- * under the same terms. The copyright and license information for
- * java/net/SocketOptions.java follows.
- *
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class java_net_SocketOptions */
-
-#ifndef _Included_java_net_SocketOptions
-#define _Included_java_net_SocketOptions
-#ifdef __cplusplus
-extern "C" {
-#endif
-#undef java_net_SocketOptions_TCP_NODELAY
-#define java_net_SocketOptions_TCP_NODELAY 1L
-#undef java_net_SocketOptions_SO_BINDADDR
-#define java_net_SocketOptions_SO_BINDADDR 15L
-#undef java_net_SocketOptions_SO_REUSEADDR
-#define java_net_SocketOptions_SO_REUSEADDR 4L
-#undef java_net_SocketOptions_SO_BROADCAST
-#define java_net_SocketOptions_SO_BROADCAST 32L
-#undef java_net_SocketOptions_IP_MULTICAST_IF
-#define java_net_SocketOptions_IP_MULTICAST_IF 16L
-#undef java_net_SocketOptions_IP_MULTICAST_IF2
-#define java_net_SocketOptions_IP_MULTICAST_IF2 31L
-#undef java_net_SocketOptions_IP_MULTICAST_LOOP
-#define java_net_SocketOptions_IP_MULTICAST_LOOP 18L
-#undef java_net_SocketOptions_IP_TOS
-#define java_net_SocketOptions_IP_TOS 3L
-#undef java_net_SocketOptions_SO_LINGER
-#define java_net_SocketOptions_SO_LINGER 128L
-#undef java_net_SocketOptions_SO_TIMEOUT
-#define java_net_SocketOptions_SO_TIMEOUT 4102L
-#undef java_net_SocketOptions_SO_SNDBUF
-#define java_net_SocketOptions_SO_SNDBUF 4097L
-#undef java_net_SocketOptions_SO_RCVBUF
-#define java_net_SocketOptions_SO_RCVBUF 4098L
-#undef java_net_SocketOptions_SO_KEEPALIVE
-#define java_net_SocketOptions_SO_KEEPALIVE 8L
-#undef java_net_SocketOptions_SO_OOBINLINE
-#define java_net_SocketOptions_SO_OOBINLINE 4099L
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/ojluni/src/main/native/net_util.h b/ojluni/src/main/native/net_util.h
index 839e947..afd94ed 100644
--- a/ojluni/src/main/native/net_util.h
+++ b/ojluni/src/main/native/net_util.h
@@ -78,6 +78,8 @@
 extern jclass ia4_class;
 extern jmethodID ia4_ctrID;
 
+/* Android-removed: NetworkInterface moved away fro JNI */
+#if 0
 /* NetworkInterface fields */
 extern jclass ni_class;
 extern jfieldID ni_nameID;
@@ -85,13 +87,17 @@
 extern jfieldID ni_addrsID;
 extern jfieldID ni_descID;
 extern jmethodID ni_ctrID;
+#endif
 
+/* Android-removed: PlainSocketImpl moved away fro JNI */
+#if 0
 /* PlainSocketImpl fields */
 extern jfieldID psi_timeoutID;
 extern jfieldID psi_fdID;
 extern jfieldID psi_addressID;
 extern jfieldID psi_portID;
 extern jfieldID psi_localportID;
+#endif
 
 /* Android-removed: DatagramSocket moved away from JNI */
 #if 0
@@ -138,8 +144,11 @@
 void initLocalAddrTable ();
 void parseExclusiveBindProperty(JNIEnv *env);
 
+// Android-removed: unused
+#if 0
 void
 NET_SetTrafficClass(struct sockaddr *him, int trafficClass);
+#endif
 
 JNIEXPORT jint JNICALL
 NET_GetPortFromSockaddr(struct sockaddr *him);
@@ -156,8 +165,11 @@
 int
 NET_IsEqual(jbyte* caddr1, jbyte* caddr2);
 
+// Android-removed: unused
+#if 0
 int
 NET_IsZeroAddr(jbyte* caddr);
+#endif
 
 /* Socket operations
  *
@@ -174,11 +186,14 @@
 JNIEXPORT int JNICALL
 NET_Bind(int fd, struct sockaddr *him, int len);
 
+// Android-removed: unused
+#if 0
 JNIEXPORT int JNICALL
 NET_MapSocketOption(jint cmd, int *level, int *optname);
 
 JNIEXPORT int JNICALL
 NET_MapSocketOptionV6(jint cmd, int *level, int *optname);
+#endif
 
 int getScopeID (struct sockaddr *);
 
diff --git a/ojluni/src/main/native/net_util_md.c b/ojluni/src/main/native/net_util_md.c
index 49c9779..d15e29d 100644
--- a/ojluni/src/main/native/net_util_md.c
+++ b/ojluni/src/main/native/net_util_md.c
@@ -64,7 +64,11 @@
 #include "jvm.h"
 #include "net_util.h"
 
+// Android-removed: unused
+#if 0
 #include "java_net_SocketOptions.h"
+#endif
+
 
 /* needed from libsocket on Solaris 8 */
 
@@ -83,6 +87,8 @@
 #define UDP_EXCLBIND            0x0101
 #endif
 
+// Android-removed: unused
+#if 0
 void setDefaultScopeID(JNIEnv *env, struct sockaddr *him)
 {
 #ifdef MACOSX
@@ -124,6 +130,7 @@
                                                  ni_defaultIndexID);
     return defaultIndex;
 }
+#endif
 
 #ifdef __solaris__
 static int init_tcp_max_buf, init_udp_max_buf;
@@ -817,6 +824,8 @@
     return 0;
 }
 
+// Android-removed: unused
+#if 0
 void
 NET_SetTrafficClass(struct sockaddr *him, int trafficClass) {
 #ifdef AF_INET6
@@ -826,6 +835,7 @@
     }
 #endif /* AF_INET6 */
 }
+#endif
 
 JNIEXPORT jint JNICALL
 NET_GetPortFromSockaddr(struct sockaddr *him) {
@@ -876,6 +886,8 @@
     return (jboolean)(getaddrinfo_ptr != NULL);
 }
 
+// Android-removed: unused
+#if 0
 int NET_IsZeroAddr(jbyte* caddr) {
     int i;
     for (i = 0; i < 16; i++) {
@@ -885,7 +897,10 @@
     }
     return 1;
 }
+#endif
 
+// Android-removed: unused
+#if 0
 /*
  * Map the Java level socket option to the platform specific
  * level and option name.
@@ -952,6 +967,7 @@
     /* not found */
     return -1;
 }
+#endif
 
 /*
  * Wrapper for getsockopt system routine - does any necessary
@@ -1321,6 +1337,8 @@
     return rv;
 }
 
+// Android-removed: unused
+#if 0
 /**
  * Wrapper for select/poll with timeout on a single file descriptor.
  *
@@ -1399,6 +1417,7 @@
 
     return timeout;
 }
+#endif
 
 #if 0
 // Stripped out unused code.
diff --git a/ojluni/src/main/native/net_util_md.h b/ojluni/src/main/native/net_util_md.h
index 46fa8dd..5c6dd42 100644
--- a/ojluni/src/main/native/net_util_md.h
+++ b/ojluni/src/main/native/net_util_md.h
@@ -112,7 +112,10 @@
 #define NET_WAIT_WRITE  0x02
 #define NET_WAIT_CONNECT        0x04
 
+// Android-removed: unused
+#if 0
 extern jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout);
+#endif
 
 /************************************************************************
  * Macros and constants
@@ -149,10 +152,13 @@
 /************************************************************************
  *  Utilities
  */
+// Android-removed: unused
+#if 0
 #ifdef __linux__
 extern int kernelIsV22();
 extern int kernelIsV24();
 #endif
+#endif
 
 void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
                    const char *defaultDetail);
diff --git a/ojluni/src/main/native/openjdksub.mk b/ojluni/src/main/native/openjdksub.mk
index 3d37d00..d60bc09 100644
--- a/ojluni/src/main/native/openjdksub.mk
+++ b/ojluni/src/main/native/openjdksub.mk
@@ -50,7 +50,6 @@
     Inet6Address.c \
     Inet4Address.c \
     linux_close.cpp \
-    PlainSocketImpl.c \
     ServerSocketChannelImpl.c \
     SocketInputStream.c \
     SocketOutputStream.c \
diff --git a/ojluni/src/test/java/security/cert/PKIXCertPathValidatorValidity.java b/ojluni/src/test/java/security/cert/PKIXCertPathValidatorValidity.java
new file mode 100644
index 0000000..fd68b44
--- /dev/null
+++ b/ojluni/src/test/java/security/cert/PKIXCertPathValidatorValidity.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/**
+ * @test
+ * @bug 8021804
+ * @summary CertPath should validate even if the validity period of the
+ *          root cert does not include the validity period of a subordinate
+ *          cert.
+ */
+// Android-changed: Adapted from
+// jdk/test/sun/security/provider/certpath/PKIXCertPathValidator/Validity.java
+// Android-changed: Added package & Test import
+package test.java.security.cert;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+// Android-changed: s/Validity/PKIXCertPathValidatorValidity
+public class PKIXCertPathValidatorValidity {
+
+    /*
+     * Subject: OU=TestOrg, CN=TestCA
+     * Issuer: OU=TestOrg, CN=TestCA
+     * Validity
+     *     Not Before: Feb 26 21:33:55 2014 GMT
+           Not After : Feb 26 21:33:55 2024 GMT
+     * Version 1
+     */
+    static String CACertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBvTCCASYCCQCQRiTo4lBCFjANBgkqhkiG9w0BAQUFADAjMRAwDgYDVQQLDAdU\n" +
+        "ZXN0T3JnMQ8wDQYDVQQDDAZUZXN0Q0EwHhcNMTQwMjI2MjEzMzU1WhcNMjQwMjI2\n" +
+        "MjEzMzU1WjAjMRAwDgYDVQQLDAdUZXN0T3JnMQ8wDQYDVQQDDAZUZXN0Q0EwgZ8w\n" +
+        "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOtKS4ZrsM3ansd61ZxitcrN0w184I+A\n" +
+        "z0kyrSP1eMtlam+cC2U91NpTz11FYV4XUfBhqqxaXW043AWTUer8pS90Pt4sCrUX\n" +
+        "COx1+QA1M3ZhbZ4sTM7XQ90JbGaBJ/sEza9mlQP7hQ2yQO/hATKbP6J5qvgG2sT2\n" +
+        "S2WYjEgwNwmFAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAQ/CXEpnx2WY4LJtv4jwE\n" +
+        "4jIVirur3pdzV5oBhPyqqHMsyhQBkukCfX7uD7L5wN1+xuM81DfANpIxlnUfybp5\n" +
+        "CpjcmktLpmyK4kJ6XnSd2blbLOIpsr9x6FqxPxpVDlyw/ySHYrIG/GZdsLHgmzGn\n" +
+        "B06jeYzH8OLf879VxAxSsPc=\n" +
+        "-----END CERTIFICATE-----";
+
+    /*
+     * Subject: OU=TestOrg, CN=TestEE0
+     * Issuer: OU=TestOrg, CN=TestCA
+     * Validity
+     *     Not Before: Feb 26 22:55:12 2014 GMT
+     *     Not After : Feb 25 22:55:12 2025 GMT
+     * Version 1
+     */
+    static String EECertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBtjCCAR8CAQQwDQYJKoZIhvcNAQEFBQAwIzEQMA4GA1UECwwHVGVzdE9yZzEP\n" +
+        "MA0GA1UEAwwGVGVzdENBMB4XDTE0MDIyNjIyNTUxMloXDTI1MDIyNTIyNTUxMlow\n" +
+        "JDEQMA4GA1UECwwHVGVzdE9yZzEQMA4GA1UEAwwHVGVzdEVFMDCBnzANBgkqhkiG\n" +
+        "9w0BAQEFAAOBjQAwgYkCgYEAt8xz9W3ruCTHjSOtTX6cxsUZ0nRP6EavEfzgcOYh\n" +
+        "CXGA0gr+viSHq3c2vQBxiRny2hm5rLcqpPo+2OxZtw/ajxfyrV6d/r8YyQLBvyl3\n" +
+        "xdCZdOkG1DCM1oFAQDaSRt9wN5Zm5kyg7uMig5Y4L45fP9Yee4x6Xyh36qYbsR89\n" +
+        "rFMCAwEAATANBgkqhkiG9w0BAQUFAAOBgQDZrPqSo08va1m9TOWOztTuWilGdjK/\n" +
+        "2Ed2WXg8utIpy6uAV+NaOYtHQ7ULQBVRNmwg9nKghbVbh+E/xpoihjl1x7OXass4\n" +
+        "TbwXA5GKFIFpNtDvATQ/QQZoCuCzw1FW/mH0Q7UEQ/9/iJdDad6ebkapeMwtj/8B\n" +
+        "s2IZV7s85CEOXw==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() throws Exception {
+
+        String[] certStrs = {EECertStr};
+        String[] trustedCertStrs = {CACertStr};
+        runTest(certStrs, trustedCertStrs);
+
+        System.out.println("Test passed.");
+    }
+
+    private static void runTest(String[] certStrs,
+                                String[] trustedCertStrs)
+            throws Exception {
+
+        CertificateFactory cf = CertificateFactory.getInstance("X509");
+
+        // Generate the CertPath from the certs named in certStrs
+        ArrayList<X509Certificate> certs = new ArrayList<>();
+        for (String certStr : certStrs) {
+            certs.add(generateCert(certStr, cf));
+        }
+        CertPath cp = cf.generateCertPath(certs);
+
+        // Generate the set of Trust Anchors from the certs named in
+        // trustedCertStrs
+        Set<TrustAnchor> trustAnchors = new HashSet<>();
+        for (String trustedCertStr : trustedCertStrs) {
+            TrustAnchor ta = new TrustAnchor(generateCert(trustedCertStr, cf),
+                                             null);
+            trustAnchors.add(ta);
+        }
+        PKIXParameters params = new PKIXParameters(trustAnchors);
+        params.setDate(new Date(114, 3, 1));   // 2014-03-01
+        params.setRevocationEnabled(false);
+
+        // Attempt to validate the CertPath. If no exception thrown, successful.
+        CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
+        cpv.validate(cp, params);
+        System.out.println("CertPath validation successful.");
+    }
+
+    private static X509Certificate generateCert(String certStr,
+                                                CertificateFactory cf)
+            throws Exception {
+        ByteArrayInputStream stream
+                = new ByteArrayInputStream(certStr.getBytes());
+        return (X509Certificate) cf.generateCertificate(stream);
+
+    }
+}
diff --git a/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/DoubleStreamTestDataProvider.java b/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/DoubleStreamTestDataProvider.java
index 700d9c9..614cafa 100644
--- a/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/DoubleStreamTestDataProvider.java
+++ b/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/DoubleStreamTestDataProvider.java
@@ -35,7 +35,8 @@
     private static final double[] to1 = new double[1];
     private static final double[] to10 = new double[10];
     private static final double[] to100 = new double[100];
-    private static final double[] to1000 = new double[1000];
+    // Android-changed: remove 0..1000 test data from data providers.
+    // private static final double[] to1000 = new double[1000];
     private static final double[] reversed = new double[100];
     private static final double[] ones = new double[100];
     private static final double[] twice = new double[200];
@@ -45,7 +46,9 @@
     private static final Object[][] spliteratorTestData;
 
     static {
-        double[][] arrays = {to0, to1, to10, to100, to1000};
+        // Android-changed: remove 0..1000 test data from data providers.
+        // double[][] arrays = {to0, to1, to10, to100, to1000};
+        double[][] arrays = {to0, to1, to10, to100};
         for (double[] arr : arrays) {
             for (int i = 0; i < arr.length; i++) {
                 arr[i] = i;
@@ -70,7 +73,8 @@
             {"0..1", to1},
             {"0..10", to10},
             {"0..100", to100},
-            {"0..1000", to1000},
+            // Android-changed: remove 0..1000 test data from data providers.
+            // {"0..1000", to1000},
             {"100x[1]", ones},
             {"2x[0..100]", twice},
             {"reverse 0..100", reversed},
diff --git a/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/IntStreamTestDataProvider.java b/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/IntStreamTestDataProvider.java
index 972cf31..f80ba4a 100644
--- a/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/IntStreamTestDataProvider.java
+++ b/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/IntStreamTestDataProvider.java
@@ -35,7 +35,8 @@
     private static final int[] to1 = new int[1];
     private static final int[] to10 = new int[10];
     private static final int[] to100 = new int[100];
-    private static final int[] to1000 = new int[1000];
+    // Android-changed: remove 0..1000 test data from data providers.
+    // private static final int[] to1000 = new int[1000];
     private static final int[] reversed = new int[100];
     private static final int[] ones = new int[100];
     private static final int[] twice = new int[200];
@@ -45,7 +46,8 @@
     private static final Object[][] spliteratorTestData;
 
     static {
-        int[][] arrays = {to0, to1, to10, to100, to1000};
+        // Android-changed: remove 0..1000 test data from data providers.
+        int[][] arrays = {to0, to1, to10, to100};
         for (int[] arr : arrays) {
             for (int i = 0; i < arr.length; i++) {
                 arr[i] = i;
@@ -70,7 +72,8 @@
             {"0..1", to1},
             {"0..10", to10},
             {"0..100", to100},
-            {"0..1000", to1000},
+            // Android-changed: remove 0..1000 test data from data providers.
+            // {"0..1000", to1000},
             {"100x[1]", ones},
             {"2x[0..100]", twice},
             {"reverse 0..100", reversed},
diff --git a/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/LongStreamTestDataProvider.java b/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/LongStreamTestDataProvider.java
index 63a39e6..abee8fd 100644
--- a/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/LongStreamTestDataProvider.java
+++ b/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/LongStreamTestDataProvider.java
@@ -35,7 +35,8 @@
     private static final long[] to1 = new long[1];
     private static final long[] to10 = new long[10];
     private static final long[] to100 = new long[100];
-    private static final long[] to1000 = new long[1000];
+    // Android-changed: remove 0..1000 test data from data providers.
+    // private static final long[] to1000 = new long[1000];
     private static final long[] reversed = new long[100];
     private static final long[] ones = new long[100];
     private static final long[] twice = new long[200];
@@ -45,7 +46,8 @@
     private static final Object[][] spliteratorTestData;
 
     static {
-        long[][] arrays = {to0, to1, to10, to100, to1000};
+        // Android-changed: remove 0..1000 test data from data providers.
+        long[][] arrays = {to0, to1, to10, to100};
         for (long[] arr : arrays) {
             for (int i = 0; i < arr.length; i++) {
                 arr[i] = i;
@@ -70,7 +72,8 @@
             {"0..1", to1},
             {"0..10", to10},
             {"0..100", to100},
-            {"0..1000", to1000},
+            // Android-changed: remove 0..1000 test data from data providers.
+            // {"0..1000", to1000},
             {"100x[1]", ones},
             {"2x[0..100]", twice},
             {"reverse 0..100", reversed},
diff --git a/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/StreamTestDataProvider.java b/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/StreamTestDataProvider.java
index f933d4c..0c741bf 100644
--- a/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/StreamTestDataProvider.java
+++ b/ojluni/src/test/java/util/stream/testlib/org/openjdk/testlib/java/util/stream/StreamTestDataProvider.java
@@ -42,7 +42,8 @@
     private static final Integer[] to1 = new Integer[1];
     private static final Integer[] to10 = new Integer[10];
     private static final Integer[] to100 = new Integer[100];
-    private static final Integer[] to1000 = new Integer[1000];
+    // Android-changed: remove 0..1000 test data from data providers.
+    // private static final Integer[] to1000 = new Integer[1000];
     private static final Integer[] reversed = new Integer[100];
     private static final Integer[] ones = new Integer[100];
     private static final Integer[] twice = new Integer[200];
@@ -53,7 +54,8 @@
     private static final Object[][] spliteratorTestData;
 
     static {
-        Integer[][] arrays = {to0, to1, to10, to100, to1000};
+        // Android-changed: remove 0..1000 test data from data providers.
+        Integer[][] arrays = {to0, to1, to10, to100};
         for (Integer[] arr : arrays) {
             for (int i = 0; i < arr.length; i++) {
                 arr[i] = i;
@@ -78,7 +80,8 @@
             {"0..1", to1},
             {"0..10", to10},
             {"0..100", to100},
-            {"0..1000", to1000},
+            // Android-changed: remove 0..1000 test data from data providers.
+            // {"0..1000", to1000},
             {"100x[1]", ones},
             {"2x[0..100]", twice},
             {"reverse 0..100", reversed},
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 3b38617..7c13ca6 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -1342,6 +1342,26 @@
     ojluni/src/main/java/javax/sql/StatementEventListener.java \
     ojluni/src/main/java/sun/reflect/CallerSensitive.java \
 
+# Stubs needed to satisfy javac's dependencies when compiling lambda code. These are
+# not used on Android devices or required by the Jack compiler.
+#
+# On aosp/master:
+# openjdk_lambda_stub_files : These are included in core-oj as stubs
+# openjdk_lambda_duplicate_stub_files : These contain complete implementations in core-oj.
+#
+# On older platforms : Both sets of stub files are used and core-oj does not contain
+# any of these classes.
+openjdk_lambda_stub_files := \
+    ojluni/src/lambda/java/java/lang/invoke/LambdaMetafactory.java \
+    ojluni/src/lambda/java/java/lang/invoke/SerializedLambda.java
+openjdk_lambda_duplicate_stub_files := \
+    ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
+    ojluni/src/lambda/java/java/lang/invoke/MethodHandles.java \
+    ojluni/src/lambda/java/java/lang/invoke/LambdaConversionException.java \
+    ojluni/src/lambda/java/java/lang/invoke/MethodHandle.java \
+    ojluni/src/lambda/java/java/lang/invoke/MethodType.java \
+
+
 # NOTE: Files in java/lang/invoke are listed here because they're not being made public
 # until the entire package is available for use.
 openjdk_java_files := \
@@ -1596,13 +1616,10 @@
     ojluni/src/main/java/sun/security/provider/certpath/PKIXMasterCertPathValidator.java \
     ojluni/src/main/java/sun/security/provider/certpath/PolicyChecker.java \
     ojluni/src/main/java/sun/security/provider/certpath/PolicyNodeImpl.java \
-    ojluni/src/main/java/sun/security/provider/certpath/ReverseBuilder.java \
-    ojluni/src/main/java/sun/security/provider/certpath/ReverseState.java \
     ojluni/src/main/java/sun/security/provider/certpath/RevocationChecker.java \
     ojluni/src/main/java/sun/security/provider/certpath/State.java \
     ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilder.java \
     ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderException.java \
-    ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderParameters.java \
     ojluni/src/main/java/sun/security/provider/certpath/SunCertPathBuilderResult.java \
     ojluni/src/main/java/sun/security/provider/certpath/URICertStore.java \
     ojluni/src/main/java/sun/security/provider/certpath/Vertex.java \
@@ -1741,21 +1758,3 @@
     $(openjdk_javadoc_files) \
     $(openjdk_lambda_stub_files)
 
-# Stubs needed to satisfy javac's dependencies when compiling lambda code. These are
-# not used on Android devices or required by the Jack compiler.
-#
-# On aosp/master:
-# openjdk_lambda_stub_files : These are included in core-oj as stubs
-# openjdk_lambda_duplicate_stub_files : These contain complete implementations in core-oj.
-#
-# On older platforms : Both sets of stub files are used and core-oj does not contain
-# any of these classes.
-openjdk_lambda_stub_files := \
-    ojluni/src/lambda/java/java/lang/invoke/LambdaMetafactory.java \
-    ojluni/src/lambda/java/java/lang/invoke/SerializedLambda.java
-openjdk_lambda_duplicate_stub_files := \
-    ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
-    ojluni/src/lambda/java/java/lang/invoke/MethodHandles.java \
-    ojluni/src/lambda/java/java/lang/invoke/LambdaConversionException.java \
-    ojluni/src/lambda/java/java/lang/invoke/MethodHandle.java \
-    ojluni/src/lambda/java/java/lang/invoke/MethodType.java \
diff --git a/tools/upstream/oj_upstream_comparison.py b/tools/upstream/oj_upstream_comparison.py
index deab5fb..76d63aa 100755
--- a/tools/upstream/oj_upstream_comparison.py
+++ b/tools/upstream/oj_upstream_comparison.py
@@ -85,43 +85,34 @@
             return result
     return None
 
-
-# For files with N and M lines, respectively, this runs in time
-# O(N+M) if the files are identical or O(N*M) if not. This could
-# be improved to O(D*(N+M)) for files with at most D lines
-# difference by only considering array elements within D cells
-# from the diagonal.
-def edit_distance_lines(file_a, file_b):
+# For lists of length N and M, respectively, this runs in time O(N*M).
+# This could be improved to O(D*(N+M)) for lists with distance <= D by
+# only considering array elements within D cells of the diagonal.
+def edit_distance(a, b):
     """
-    Computes the line-based edit distance between two text files, i.e.
-    the smallest number of line deletions, additions or replacements
-    that would transform the content of one file into that of the other.
+    Computes the line-based edit distance between two lists, i.e.
+    the smallest number of list items to delete, insert or replace
+    that would transform the content of one list into the other.
     """
-    if filecmp.cmp(file_a, file_b, shallow=False):
-        return 0 # files identical
-    with open(file_a) as f:
-        lines_a = f.readlines()
-    with open(file_b) as f:
-        lines_b = f.readlines()
-    prev_cost = range(0, len(lines_b) + 1)
-    for end_a in range(1, len(lines_a) + 1):
+    prev_cost = range(0, len(b) + 1)
+    for end_a in range(1, len(a) + 1):
         # For each valid index i, prev_cost[i] is the edit distance between
-        # lines_a[:end_a-1] and lines_b[:i].
+        # a[:end_a-1] and b[:i].
         # We now calculate cur_cost[end_b] as the edit distance between
-        # line_a[:end_a] and lines_b[:end_b]
+        # a[:end_a] and b[:end_b]
         cur_cost = [end_a]
-        for end_b in range(1, len(lines_b) + 1):
+        for end_b in range(1, len(b) + 1):
             c = min(
-                cur_cost[-1] + 1, # append line from b
-                prev_cost[end_b] + 1, # append line from a
-                # match or replace line
-                prev_cost[end_b - 1] + (0 if lines_a[end_a - 1] == lines_b[end_b - 1] else 1)
+                cur_cost[-1] + 1, # append item from b
+                prev_cost[end_b] + 1, # append item from a
+                # match or replace item
+                prev_cost[end_b - 1] + (0 if a[end_a - 1] == b[end_b - 1] else 1)
                 )
             cur_cost.append(c)
         prev_cost = cur_cost
     return prev_cost[-1]
 
-def compare_to_upstreams_and_save(out_file, build_top, upstream_root, upstreams, rel_paths, best_only=False):
+def compare_to_upstreams_and_save(out_file, build_top, upstream_root, upstreams, rel_paths):
     """
     Prints tab-separated values comparing ojluni files vs. each
     upstream, for each of the rel_paths, suitable for human
@@ -144,13 +135,21 @@
             if upstream_file is None:
                 upstream_comparison = "missing"
             else:
-                edit_distance = edit_distance_lines(upstream_file, ojluni_file)
-                if edit_distance == 0:
+                if filecmp.cmp(upstream_file, ojluni_file, shallow=False):
+                    distance = 0
                     upstream_comparison = "identical"
                 else:
-                    upstream_comparison = "different (%d lines)" % (edit_distance)
-                if edit_distance < best_distance:
-                    best_distance = edit_distance
+                    with open(upstream_file) as f:
+                        lines_a = f.readlines()
+                    with open(ojluni_file) as f:
+                        lines_b = f.readlines()
+                    distance = edit_distance(lines_a, lines_b)
+                    # 0% for identical files
+                    # 100% for totally different files or where one file is empty
+                    percent_different = 100.0 * distance / max(len(lines_a), len(lines_b))
+                    upstream_comparison = "%.1f%% different (%d lines)" % (percent_different, distance)
+                if distance < best_distance:
+                    best_distance = distance
                     guessed_upstream = upstream
             upstream_comparisons.append(upstream_comparison)
         writer.writerow([rel_path, guessed_upstream ] + upstream_comparisons)