Merge "Remove Iobridge unused MCAST constants"
diff --git a/Android.mk b/Android.mk
index 17bd4a6..3c25583 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,7 +19,7 @@
 # Subprojects with separate makefiles
 #
 
-subdirs := benchmarks tzdata ojluni
+subdirs := benchmarks tzdata ojluni tools/upstream
 subdir_makefiles := $(call all-named-subdir-makefiles,$(subdirs))
 
 #
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 8b12948..e9fa894 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -102,7 +102,6 @@
 LOCAL_JACK_FLAGS := $(local_jack_flags)
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-all
 LOCAL_REQUIRED_MODULES := tzdata tzlookup.xml
 LOCAL_CORE_LIBRARY := true
@@ -117,7 +116,6 @@
 LOCAL_JACK_FLAGS := $(local_jack_flags)
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-oj
 LOCAL_JAVA_LIBRARIES := core-all
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/ojluni/NOTICE
@@ -134,7 +132,6 @@
 LOCAL_JACK_FLAGS := $(local_jack_flags)
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-libart
 LOCAL_JAVA_LIBRARIES := core-all
 ifeq ($(EMMA_INSTRUMENT),true)
@@ -156,7 +153,6 @@
 LOCAL_JACK_FLAGS := $(local_jack_flags)
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-lambda-stubs
 LOCAL_JAVA_LIBRARIES := core-all
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/ojluni/NOTICE
@@ -177,7 +173,6 @@
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
 LOCAL_DEX_PREOPT := false
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-oj-testdex
 LOCAL_JAVA_LIBRARIES := core-all
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/ojluni/NOTICE
@@ -212,7 +207,6 @@
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
 LOCAL_DEX_PREOPT := false
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-libart-testdex
 LOCAL_JAVA_LIBRARIES := core-all
 LOCAL_CORE_LIBRARY := true
@@ -260,7 +254,6 @@
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_JACK_FLAGS := $(local_jack_flags)
 LOCAL_ERROR_PRONE_FLAGS := -Xep:TryFailThrowable:ERROR -Xep:ComparisonOutOfRange:ERROR
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-tests
 include $(BUILD_STATIC_JAVA_LIBRARY)
 endif
@@ -289,7 +282,6 @@
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_JACK_FLAGS := $(local_jack_flags)
 LOCAL_MODULE := jsr166-tests
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 include $(BUILD_STATIC_JAVA_LIBRARY)
 endif
 
@@ -304,7 +296,6 @@
     LOCAL_JACK_FLAGS := $(local_jack_flags)
     LOCAL_DX_FLAGS := --core-library
     LOCAL_MODULE_TAGS := optional
-    LOCAL_JAVA_LANGUAGE_VERSION := 1.8
     LOCAL_MODULE := core-ojtests
     # jack bug workaround: int[] java.util.stream.StatefulTestOp.-getjava-util-stream-StreamShapeSwitchesValues() is a private synthetic method in an interface which causes a hard verifier error
     LOCAL_DEX_PREOPT := false # disable AOT preverification which breaks the build. it will still throw VerifyError at runtime.
@@ -329,7 +320,6 @@
     LOCAL_JACK_FLAGS := $(local_jack_flags)
     LOCAL_DX_FLAGS := --core-library
     LOCAL_MODULE_TAGS := optional
-    LOCAL_JAVA_LANGUAGE_VERSION := 1.8
     LOCAL_MODULE := core-ojtests-public
     # jack bug workaround: int[] java.util.stream.StatefulTestOp.-getjava-util-stream-StreamShapeSwitchesValues() is a private synthetic method in an interface which causes a hard verifier error
     LOCAL_DEX_PREOPT := false # disable AOT preverification which breaks the build. it will still throw VerifyError at runtime.
@@ -349,7 +339,6 @@
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-all-hostdex
 LOCAL_REQUIRED_MODULES := tzdata-host tzlookup.xml-host
 LOCAL_CORE_LIBRARY := true
@@ -363,7 +352,6 @@
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-oj-hostdex
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/ojluni/NOTICE
 LOCAL_JAVA_LIBRARIES := core-all-hostdex
@@ -379,7 +367,6 @@
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-libart-hostdex
 LOCAL_JAVA_LIBRARIES := core-oj-hostdex
 LOCAL_REQUIRED_MODULES := tzdata-host tzlookup.xml-host
@@ -393,7 +380,6 @@
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_DX_FLAGS := --core-library
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_MODULE := core-lambda-stubs-hostdex
 LOCAL_JAVA_LIBRARIES := core-all-hostdex
 LOCAL_CORE_LIBRARY := true
@@ -425,7 +411,6 @@
         tzdata-testing-hostdex
     LOCAL_JAVACFLAGS := $(local_javac_flags)
     LOCAL_MODULE_TAGS := optional
-    LOCAL_JAVA_LANGUAGE_VERSION := 1.8
     LOCAL_MODULE := core-tests-hostdex
     include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
 endif
@@ -464,7 +449,6 @@
     LOCAL_JAVACFLAGS := $(local_javac_flags)
     LOCAL_DX_FLAGS := --core-library
     LOCAL_MODULE_TAGS := optional
-    LOCAL_JAVA_LANGUAGE_VERSION := 1.8
     LOCAL_MODULE := core-ojtests-hostdex
     include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
 endif
diff --git a/NativeCode.mk b/NativeCode.mk
index 9bfb88d..cedc69b 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -91,6 +91,9 @@
     -Wno-constant-logical-operand \
     -Wno-sometimes-uninitialized
 
+# TODO(http://b/64362645): remove when upstream replaces readdir_r with readdir.
+openjdk_cflags += -Wno-deprecated-declarations
+
 core_test_files := \
   luni/src/test/native/dalvik_system_JniTest.cpp \
   luni/src/test/native/libcore_java_io_FileTest.cpp \
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index bab2f46..0863abd 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -65,7 +65,39 @@
         this.pathList = new DexPathList(this, dexPath, librarySearchPath, null);
 
         if (reporter != null) {
-            reporter.report(this.pathList.getDexPaths());
+            reportClassLoaderChain();
+        }
+    }
+
+    /**
+     * Reports the current class loader chain to the registered {@code reporter}.
+     * The chain is reported only if all its elements are {@code BaseDexClassLoader}.
+     */
+    private void reportClassLoaderChain() {
+        ArrayList<BaseDexClassLoader> classLoadersChain = new ArrayList<>();
+        ArrayList<String> classPaths = new ArrayList<>();
+
+        classLoadersChain.add(this);
+        classPaths.add(String.join(File.pathSeparator, pathList.getDexPaths()));
+
+        boolean onlySawSupportedClassLoaders = true;
+        ClassLoader bootClassLoader = ClassLoader.getSystemClassLoader().getParent();
+        ClassLoader current = getParent();
+
+        while (current != null && current != bootClassLoader) {
+            if (current instanceof BaseDexClassLoader) {
+                BaseDexClassLoader bdcCurrent = (BaseDexClassLoader) current;
+                classLoadersChain.add(bdcCurrent);
+                classPaths.add(String.join(File.pathSeparator, bdcCurrent.pathList.getDexPaths()));
+            } else {
+                onlySawSupportedClassLoaders = false;
+                break;
+            }
+            current = current.getParent();
+        }
+
+        if (onlySawSupportedClassLoaders) {
+            reporter.report(classLoadersChain, classPaths);
         }
     }
 
@@ -206,6 +238,19 @@
      * @hide
      */
     public interface Reporter {
-        public void report(List<String> dexPaths);
+        /**
+         * Reports the construction of a BaseDexClassLoader and provides information about the
+         * class loader chain.
+         * Note that this only reports if all class loader in the chain are BaseDexClassLoader.
+         *
+         * @param classLoadersChain the chain of class loaders used during the construction of the
+         *     class loader. The first element is the BaseDexClassLoader being constructed,
+         *     the second element is its parent, and so on.
+         * @param classPaths the class paths of the class loaders present in
+         *     {@param classLoadersChain}. The first element corresponds to the first class
+         *     loader and so on. A classpath is represented as a list of dex files separated by
+         *     {@code File.pathSeparator}.
+         */
+        void report(List<BaseDexClassLoader> classLoadersChain, List<String> classPaths);
     }
 }
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index 3cd10e3..bc5d3db 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -411,7 +411,7 @@
     /**
      * No dexopt should (or can) be done to update the apk/jar.
      *
-     * See {@link #getDexOptNeeded(String, String, int)}.
+     * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
      *
      * @hide
      */
@@ -420,7 +420,7 @@
     /**
      * dex2oat should be run to update the apk/jar from scratch.
      *
-     * See {@link #getDexOptNeeded(String, String, int)}.
+     * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
      *
      * @hide
      */
@@ -430,7 +430,7 @@
      * dex2oat should be run to update the apk/jar because the existing code
      * is out of date with respect to the boot image.
      *
-     * See {@link #getDexOptNeeded(String, String, int)}.
+     * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
      *
      * @hide
      */
@@ -440,7 +440,7 @@
      * dex2oat should be run to update the apk/jar because the existing code
      * is out of date with respect to the target compiler filter.
      *
-     * See {@link #getDexOptNeeded(String, String, int)}.
+     * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
      *
      * @hide
      */
@@ -450,7 +450,7 @@
      * dex2oat should be run to update the apk/jar because the existing code
      * is not relocated to match the boot image.
      *
-     * See {@link #getDexOptNeeded(String, String, int)}.
+     * See {@link #getDexOptNeeded(String, String, String, boolean, boolean)}.
      *
      * @hide
      */
@@ -467,6 +467,8 @@
      * @param newProfile flag that describes whether a profile corresponding
      *        to the dex file has been recently updated and should be considered
      *        in the state of the file.
+     * @param downgrade flag that describes if the purpose of dexopt is to downgrade the
+     *        compiler filter. If set to false, will be evaluated as an upgrade request.
      * @return NO_DEXOPT_NEEDED, or DEX2OAT_*. See documentation
      *         of the particular status code for more information on its
      *         meaning. Returns a positive status code if the status refers to
@@ -481,7 +483,7 @@
      * @hide
      */
     public static native int getDexOptNeeded(String fileName,
-            String instructionSet, String compilerFilter, boolean newProfile)
+            String instructionSet, String compilerFilter, boolean newProfile, boolean downgrade)
             throws FileNotFoundException, IOException;
 
     /**
diff --git a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
index 9a934f6..f3c552f 100644
--- a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
+++ b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
@@ -16,8 +16,8 @@
 
 #define LOG_TAG "NativeTestTarget"
 
-#include "JNIHelp.h"
-#include "JniConstants.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
 
 static void NativeTestTarget_emptyJniStaticSynchronizedMethod0(JNIEnv*, jclass) { }
 static void NativeTestTarget_emptyJniSynchronizedMethod0(JNIEnv*, jclass) { }
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 441c9ff..3cd2e2a 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1406,17 +1406,6 @@
   name: "com.android.org.apache.harmony.logging.tests.java.util.logging.LevelTest#testSerializationCompatibility"
 },
 {
-  description: "java.util.beans: the harmony tests were broken by Android commit 19a270e90b1e992c1f6639f355ae13564c2f3a6a",
-  bug: 17394106,
-  names: [
-    "com.android.org.apache.harmony.beans.tests.java.beans.PropertyChangeSupportTest#testSerialization",
-    "com.android.org.apache.harmony.beans.tests.java.beans.PropertyChangeSupportTest#testGetPropertyChangeListener_String_Normal",
-    "com.android.org.apache.harmony.beans.tests.java.beans.PropertyChangeSupportTest#testAddPropertyChangeListener_PropertyChangeListener_String_Duplicate",
-    "com.android.org.apache.harmony.beans.tests.java.beans.PropertyChangeSupportTest#testAddPropertyChangeListener_PropertyChangeListener_String_Normal",
-    "com.android.org.apache.harmony.beans.tests.java.beans.PropertyChangeSupportTest#testAddPropertyChangeListener_PropertyChangeListener_Normal"
-  ]
-},
-{
   description: "java.util.beans: the serialized form references org.apache not com.android.org.apache",
   bug: 17394106,
   names: [
@@ -1837,5 +1826,23 @@
   names: [
       "com.android.org.apache.harmony.luni.tests.internal.process.SystemProcessTest#test_interrupt"
   ]
+},
+{
+  description: "Revisit this after http://bugs.icu-project.org/trac/ticket/13021 has been resolved",
+  result: EXEC_FAILED,
+  bug: 64092664,
+  name: "libcore.java.text.OldDecimalFormatTestICU#test_positiveExponentSign"
+},
+{
+  description: "Revisit this after http://bugs.icu-project.org/trac/ticket/13309 has been resolved",
+  result: EXEC_FAILED,
+  bug: 64092664,
+  name: "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parse_with_spaces"
+},
+{
+  description: "Revisit this after http://bugs.icu-project.org/trac/ticket/13310 has been resolved",
+  result: EXEC_FAILED,
+  bug: 64092664,
+  name: "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_withFieldPosition"
 }
 ]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
index bb9e806..45fe5f3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
@@ -736,7 +736,7 @@
             // now create one that is not connected and validate that we get the
             // right answer
             try (DatagramSocket theSocket = new DatagramSocket(null)) {
-                theSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
+                theSocket.bind(new InetSocketAddress(Inet6Address.LOOPBACK, 0));
                 assertNull(theSocket.getRemoteSocketAddress());
 
                 // now connect and validate we get the right answer
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
index 29470d1..798bc51 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
@@ -689,8 +689,12 @@
         format.setPositivePrefix("");
         assertEquals("", format.getPositivePrefix());
 
-        format.setPositivePrefix(null);
-        assertNull(format.getPositivePrefix());
+        try {
+            format.setPositivePrefix(null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+        assertNotNull(format.getPositivePrefix());
     }
 
     public void test_setPositiveSuffix() throws Exception {
@@ -704,8 +708,12 @@
         format.setPositiveSuffix("");
         assertEquals("", format.getPositiveSuffix());
 
-        format.setPositiveSuffix(null);
-        assertNull(format.getPositiveSuffix());
+        try {
+            format.setPositiveSuffix(null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+        assertNotNull(format.getPositiveSuffix());
     }
 
     public void test_setNegativePrefix() throws Exception {
@@ -718,8 +726,12 @@
         format.setNegativePrefix("");
         assertEquals("", format.getNegativePrefix());
 
-        format.setNegativePrefix(null);
-        assertNull(format.getNegativePrefix());
+        try {
+            format.setNegativePrefix(null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+        assertNotNull(format.getNegativePrefix());
     }
 
     public void test_setNegativeSuffix() throws Exception {
@@ -728,13 +740,17 @@
 
         format.setNegativeSuffix("NegSfx");
         assertEquals("NegSfx", format.getNegativeSuffix());
-        assertTrue(format.parse("123.45NegPfx").doubleValue() == 123.45);
+        assertTrue(format.parse("123.45NegSfx").doubleValue() == -123.45);
 
         format.setNegativeSuffix("");
         assertEquals("", format.getNegativeSuffix());
 
-        format.setNegativeSuffix(null);
-        assertNull(format.getNegativeSuffix());
+        try {
+            format.setNegativeSuffix(null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+        assertNotNull(format.getNegativeSuffix());
     }
 
     public void test_setGroupingUsed() {
@@ -869,11 +885,11 @@
 
     public void test_applyPattern() {
         DecimalFormat format = new DecimalFormat("#.#");
-        assertEquals("Wrong pattern 1", "#0.#", format.toPattern());
+        assertEquals("Wrong pattern 1", "0.#", format.toPattern());
         format = new DecimalFormat("#.");
-        assertEquals("Wrong pattern 2", "#0.", format.toPattern());
+        assertEquals("Wrong pattern 2", "0.", format.toPattern());
         format = new DecimalFormat("#");
-        assertEquals("Wrong pattern 3", "#", format.toPattern());
+        assertEquals("Wrong pattern 3", "0", format.toPattern());
         format = new DecimalFormat(".#");
         assertEquals("Wrong pattern 4", "#.0", format.toPattern());
 
@@ -917,12 +933,12 @@
         };
 
         String[] expResult = {
-                "#0.##", "#0.######", "#000000.000000",
-                "#.000000", "#000000.######", " #0.###", "$#0.######",
-                "$$#0.######",
-                "%#,###,####", // icu only. icu supports two grouping sizes
+                "0.##", "0.######", "000000.000000",
+                "#.000000", "000000.######", " 0.###", "$0.######",
+                "$$0.######",
+                "%#,###,###0", // icu only. icu supports two grouping sizes
                 "#,##0.00;(#,##0.00)",
-                "#0.##-E"
+                "0.##-E"
                 // icu only. E in the suffix does not need to be quoted.
         };
 
@@ -940,11 +956,11 @@
 
         // case 1: Try to apply correct variants of pattern.
         format.applyLocalizedPattern("#.#");
-        assertEquals("Wrong pattern 1", "#0.#", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 1", "0.#", format.toLocalizedPattern());
         format.applyLocalizedPattern("#.");
-        assertEquals("Wrong pattern 2", "#0.", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 2", "0.", format.toLocalizedPattern());
         format.applyLocalizedPattern("#");
-        assertEquals("Wrong pattern 3", "#", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 3", "0", format.toLocalizedPattern());
         format.applyLocalizedPattern(".#");
         assertEquals("Wrong pattern 4", "#.0", format.toLocalizedPattern());
 
@@ -966,11 +982,11 @@
     public void test_toPattern() {
         DecimalFormat format = new DecimalFormat();
         format.applyPattern("#.#");
-        assertEquals("Wrong pattern 1", "#0.#", format.toPattern());
+        assertEquals("Wrong pattern 1", "0.#", format.toPattern());
         format.applyPattern("#.");
-        assertEquals("Wrong pattern 2", "#0.", format.toPattern());
+        assertEquals("Wrong pattern 2", "0.", format.toPattern());
         format.applyPattern("#");
-        assertEquals("Wrong pattern 3", "#", format.toPattern());
+        assertEquals("Wrong pattern 3", "0", format.toPattern());
         format.applyPattern(".#");
         assertEquals("Wrong pattern 4", "#.0", format.toPattern());
     }
@@ -979,11 +995,11 @@
         DecimalFormat format = new DecimalFormat();
         format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
         format.applyLocalizedPattern("#.#");
-        assertEquals("Wrong pattern 1", "#0.#", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 1", "0.#", format.toLocalizedPattern());
         format.applyLocalizedPattern("#.");
-        assertEquals("Wrong pattern 2", "#0.", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 2", "0.", format.toLocalizedPattern());
         format.applyLocalizedPattern("#");
-        assertEquals("Wrong pattern 3", "#", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 3", "0", format.toLocalizedPattern());
         format.applyLocalizedPattern(".#");
         assertEquals("Wrong pattern 4", "#.0", format.toLocalizedPattern());
     }
@@ -1064,7 +1080,7 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (2) + "max fractional digits (2) == 4
-        formatTester.format(df, "00.0E0", 0.0);
+        formatTester.format(df, "0.00E0", 0.0);
         formatTester.format(df, "10.0E-1", 1.0);
         formatTester.format(df, "12.0E0", 12.0);
         formatTester.format(df, "12.3E1", 123.0);
@@ -1102,13 +1118,13 @@
         formatTester.format(df, "123E-3", 0.123);
         formatTester.format(df, "123.4E-3", 0.1234);
         formatTester.format(df, "123.46E-3", 0.1234567);
-        formatTester.format(df, "10E-3", 0.01);
-        formatTester.format(df, "12E-3", 0.012);
+        formatTester.format(df, "10.0E-3", 0.01);
+        formatTester.format(df, "12.0E-3", 0.012);
         formatTester.format(df, "12.3E-3", 0.0123);
         formatTester.format(df, "12.34E-3", 0.01234);
         formatTester.format(df, "12.346E-3", 0.01234567);
-        formatTester.format(df, "1.0E-3", 0.001);
-        formatTester.format(df, "1.2E-3", 0.0012);
+        formatTester.format(df, "1.00E-3", 0.001);
+        formatTester.format(df, "1.20E-3", 0.0012);
         formatTester.format(df, "1.23E-3", 0.00123);
         formatTester.format(df, "1.234E-3", 0.001234);
         formatTester.format(df, "1.2346E-3", 0.001234567);
@@ -1117,9 +1133,9 @@
         formatTester.format(df, "123E-6", 0.000123);
         formatTester.format(df, "123.4E-6", 0.0001234);
         formatTester.format(df, "123.46E-6", 0.0001234567);
-        formatTester.format(df, "0.0E0", 0.0);
-        formatTester.format(df, "1.0E0", 1.0);
-        formatTester.format(df, "12E0", 12.0);
+        formatTester.format(df, "0.00E0", 0.0);
+        formatTester.format(df, "1.00E0", 1.0);
+        formatTester.format(df, "12.0E0", 12.0);
         formatTester.format(df, "123E0", 123.0);
         formatTester.format(df, "1.234E3", 1234.0);
         formatTester.format(df, "12.345E3", 12345.0);
@@ -1136,12 +1152,12 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (0) + "max fractional digits (1) == 1
-        formatTester.format(df, "0.0E0", 0.0);
-        formatTester.format(df, "1.0E0", 1.0);
-        formatTester.format(df, "1.0E1", 12.0);
-        formatTester.format(df, "1.0E2", 123.0);
-        formatTester.format(df, "1.0E3", 1234.0);
-        formatTester.format(df, "1.0E4", 9999.0);
+        formatTester.format(df, "0E0", 0.0);
+        formatTester.format(df, "1E0", 1.0);
+        formatTester.format(df, "1E1", 12.0);
+        formatTester.format(df, "1E2", 123.0);
+        formatTester.format(df, "1E3", 1234.0);
+        formatTester.format(df, "1E4", 9999.0);
 
         df = new DecimalFormat("0.E0", dfs);
         // ["0.E0",isDecimalSeparatorAlwaysShown=true,groupingSize=0,multiplier=1,negativePrefix=-,
@@ -1289,7 +1305,7 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (2) + "max fractional digits (2) == 4
-        formatTester.format(df, "-00.0E0", -0.0);
+        formatTester.format(df, "-0.00E0", -0.0);
 
         df = new DecimalFormat("##0.0E0", dfs);
         // ["##0.0E0",isDecimalSeparatorAlwaysShown=false,groupingSize=0,multiplier=1,
@@ -1309,7 +1325,7 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (0) + "max fractional digits (1) == 2
-        formatTester.format(df, "-0.0E0", -0.0);
+        formatTester.format(df, "-0E0", -0.0);
 
         df = new DecimalFormat("0.#E0", dfs);
         // ["0.#E0",isDecimalSeparatorAlwaysShown=false,groupingSize=0,multiplier=1,
@@ -1367,7 +1383,7 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (2) + "max fractional digits (2) == 4
-        formatTester.format(df, "00.0E0", 0);
+        formatTester.format(df, "0.00E0", 0);
         formatTester.format(df, "10.0E-1", 1);
         formatTester.format(df, "12.0E0", 12);
         formatTester.format(df, "12.3E1", 123);
@@ -1406,9 +1422,9 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (2) + "max fractional digits (3) == 5
-        formatTester.format(df, "0.0E0", 0);
-        formatTester.format(df, "1.0E0", 1);
-        formatTester.format(df, "12E0", 12);
+        formatTester.format(df, "0.00E0", 0);
+        formatTester.format(df, "1.00E0", 1);
+        formatTester.format(df, "12.0E0", 12);
         formatTester.format(df, "123E0", 123);
         formatTester.format(df, "1.234E3", 1234);
         formatTester.format(df, "12.345E3", 12345);
@@ -1425,12 +1441,12 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (0) + "max fractional digits (1) == 1
-        formatTester.format(df, "0.0E0", 0);
-        formatTester.format(df, "1.0E0", 1);
-        formatTester.format(df, "1.0E1", 12);
-        formatTester.format(df, "1.0E2", 123);
-        formatTester.format(df, "1.0E3", 1234);
-        formatTester.format(df, "1.0E4", 9999);
+        formatTester.format(df, "0E0", 0);
+        formatTester.format(df, "1E0", 1);
+        formatTester.format(df, "1E1", 12);
+        formatTester.format(df, "1E2", 123);
+        formatTester.format(df, "1E3", 1234);
+        formatTester.format(df, "1E4", 9999);
 
         df = new DecimalFormat("0.#E0", dfs);
         // ["0.#E0",isDecimalSeparatorAlwaysShown=false,groupingSize=0,multiplier=1,
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
index 909dd27..4a5c803 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
@@ -1089,9 +1089,9 @@
         assertEquals(23456, s.nextInt(10));
 
         /*
-         * ''' is used in many locales as group separator.
+         * '’' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         try {
             s.nextInt(10);
@@ -1265,7 +1265,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         try {
             s.nextInt();
@@ -1666,7 +1666,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         try {
             s.nextBigInteger(10);
@@ -1794,7 +1794,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         try {
             s.nextBigInteger();
@@ -1931,7 +1931,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         try {
             s.nextShort(10);
@@ -2067,7 +2067,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         try {
             s.nextShort();
@@ -2204,7 +2204,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         try {
             s.nextLong(10);
@@ -2340,7 +2340,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         try {
             s.nextLong();
@@ -2945,7 +2945,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         assertFalse(s.hasNextBigInteger(10));
         try {
@@ -3131,7 +3131,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         assertFalse(s.hasNextBigInteger());
         try {
@@ -3279,7 +3279,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456");
+        s = new Scanner("23’456");
         s.useLocale(Locale.GERMANY);
         assertFalse(s.hasNextInt(10));
         s.useLocale(new Locale("it", "CH"));
@@ -3476,7 +3476,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456");
+        s = new Scanner("23’456");
         s.useLocale(Locale.GERMANY);
         assertFalse(s.hasNextInt());
         s.useLocale(new Locale("it", "CH"));
@@ -3770,7 +3770,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         assertFalse(s.hasNextShort(10));
         try {
@@ -3933,7 +3933,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         assertFalse(s.hasNextShort());
         try {
@@ -4130,7 +4130,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         assertFalse(s.hasNextLong(10));
         try {
@@ -4327,7 +4327,7 @@
         /*
          * ''' is used in many locales as group separator.
          */
-        s = new Scanner("23'456 23'456");
+        s = new Scanner("23’456 23’456");
         s.useLocale(Locale.GERMANY);
         assertFalse(s.hasNextLong());
         try {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/regex/MatcherTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/regex/MatcherTest.java
index fc36eda..98508e1 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/regex/MatcherTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/regex/MatcherTest.java
@@ -158,8 +158,13 @@
     public void testReset() {
     }
 
+    /**
+     * Ensures {@link Matcher#find(int)} resets the matcher state and creates a new snapshot of the
+     * original CharSequence before doing the find. http://b/38021063
+     */
     public void testFind_invokeReset() {
-        // First, verify find() doesn't reset, and search for the subsequent pattern
+        // Assert that find() doesn't reset the matcher by doing multiple find() calls on the same
+        // input.
         Pattern p = Pattern.compile("a|c");
         StringBuilder sb = new StringBuilder("abc");
         Matcher m = p.matcher(sb);
@@ -168,18 +173,20 @@
         assertTrue(m.find());
         assertEquals(2, m.start());
 
-        // Second, find(int) resets the matcher
+        // Assert that find(int) resets the matcher by checking its state.
         assertTrue(m.find(0));
         assertEquals(0, m.start());
-        sb.replace(0, 3, "bac");
 
-        // Test find(0) reset the cached string value from the StringBuilder
+        // Assert that find(int) refreshes the String being matched against from the input
+        // CharSequence.
+        sb.replace(0, 3, "bac");
         assertTrue(m.find(0));
         assertEquals(1, m.start());
     }
 
     /**
-     * Test reset() reset the cached string value from the StringBuilder
+     * Ensure {@link Matcher#reset()} creates a new snapshot of the original CharSequence.
+     * http://b/38021063
      */
     public void testReset_resetStringCache() {
         Pattern p = Pattern.compile("a");
diff --git a/include/ScopedIcuLocale.h b/include/ScopedIcuLocale.h
index 64186e3..851de76 100644
--- a/include/ScopedIcuLocale.h
+++ b/include/ScopedIcuLocale.h
@@ -17,8 +17,8 @@
 #ifndef SCOPED_ICU_LOCALE_H_included
 #define SCOPED_ICU_LOCALE_H_included
 
-#include "JNIHelp.h"
-#include "ScopedUtfChars.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include "unicode/locid.h"
 
 class ScopedIcuLocale {
diff --git a/include/ScopedJavaUnicodeString.h b/include/ScopedJavaUnicodeString.h
index 4e74ee1..a30aa7e 100644
--- a/include/ScopedJavaUnicodeString.h
+++ b/include/ScopedJavaUnicodeString.h
@@ -17,7 +17,7 @@
 #ifndef SCOPED_JAVA_UNICODE_STRING_H_included
 #define SCOPED_JAVA_UNICODE_STRING_H_included
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include "unicode/unistr.h"
 
 // A smart pointer that provides access to an ICU UnicodeString given a JNI
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java
index 7db7f75..5b9ff47 100644
--- a/luni/src/main/java/android/system/Os.java
+++ b/luni/src/main/java/android/system/Os.java
@@ -223,6 +223,8 @@
 
   /** @hide */ public static StructPasswd getpwuid(int uid) throws ErrnoException { return Libcore.os.getpwuid(uid); }
 
+  /** @hide */ public static StructRlimit getrlimit(int resource) throws ErrnoException { return Libcore.os.getrlimit(resource); }
+
   /**
    * See <a href="http://man7.org/linux/man-pages/man2/getsockname.2.html">getsockname(2)</a>.
    */
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index 72c5734..3e1f007 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -398,6 +398,7 @@
     public static final int PROT_READ = placeholder();
     public static final int PROT_WRITE = placeholder();
     public static final int R_OK = placeholder();
+    /** @hide */ public static final int RLIMIT_NOFILE = placeholder();
     public static final int RT_SCOPE_HOST = placeholder();
     public static final int RT_SCOPE_LINK = placeholder();
     public static final int RT_SCOPE_NOWHERE = placeholder();
diff --git a/luni/src/main/java/android/system/StructRlimit.java b/luni/src/main/java/android/system/StructRlimit.java
new file mode 100644
index 0000000..6bb05a9
--- /dev/null
+++ b/luni/src/main/java/android/system/StructRlimit.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.system;
+
+import libcore.util.Objects;
+
+/**
+ * Information returned by {@link Os#getrlimit}. Corresponds to C's {@code struct rlimit} from
+ * {@code <sys/resource.h>}.
+ *
+ * @hide
+ */
+public final class StructRlimit {
+  public final long rlim_cur;
+  public final long rlim_max;
+
+  public StructRlimit(long rlim_cur, long rlim_max) {
+    this.rlim_cur = rlim_cur;
+    this.rlim_max = rlim_max;
+  }
+
+  @Override public String toString() {
+    return Objects.toString(this);
+  }
+}
diff --git a/luni/src/main/java/android/system/StructTimespec.java b/luni/src/main/java/android/system/StructTimespec.java
index e999249..b5e192e 100644
--- a/luni/src/main/java/android/system/StructTimespec.java
+++ b/luni/src/main/java/android/system/StructTimespec.java
@@ -55,6 +55,24 @@
   }
 
   @Override
+  public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      StructTimespec that = (StructTimespec) o;
+
+      if (tv_sec != that.tv_sec) return false;
+      return tv_nsec == that.tv_nsec;
+  }
+
+  @Override
+  public int hashCode() {
+      int result = (int) (tv_sec ^ (tv_sec >>> 32));
+      result = 31 * result + (int) (tv_nsec ^ (tv_nsec >>> 32));
+      return result;
+  }
+
+  @Override
   public String toString() {
       return Objects.toString(this);
   }
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index 55d4d82..3054dc3 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -28,6 +28,7 @@
 import android.system.StructLinger;
 import android.system.StructPasswd;
 import android.system.StructPollfd;
+import android.system.StructRlimit;
 import android.system.StructStat;
 import android.system.StructStatVfs;
 import android.system.StructTimeval;
@@ -98,6 +99,7 @@
     public int getppid() { return os.getppid(); }
     public StructPasswd getpwnam(String name) throws ErrnoException { return os.getpwnam(name); }
     public StructPasswd getpwuid(int uid) throws ErrnoException { return os.getpwuid(uid); }
+    public StructRlimit getrlimit(int resource) throws ErrnoException { return os.getrlimit(resource); }
     public SocketAddress getsockname(FileDescriptor fd) throws ErrnoException { return os.getsockname(fd); }
     public int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptByte(fd, level, option); }
     public InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException { return os.getsockoptInAddr(fd, level, option); }
diff --git a/luni/src/main/java/libcore/io/Linux.java b/luni/src/main/java/libcore/io/Linux.java
index 09adb09..a0931d2 100644
--- a/luni/src/main/java/libcore/io/Linux.java
+++ b/luni/src/main/java/libcore/io/Linux.java
@@ -28,6 +28,7 @@
 import android.system.StructLinger;
 import android.system.StructPasswd;
 import android.system.StructPollfd;
+import android.system.StructRlimit;
 import android.system.StructStat;
 import android.system.StructStatVfs;
 import android.system.StructTimeval;
@@ -89,6 +90,7 @@
     public native int getppid();
     public native StructPasswd getpwnam(String name) throws ErrnoException;
     public native StructPasswd getpwuid(int uid) throws ErrnoException;
+    public native StructRlimit getrlimit(int resource) throws ErrnoException;
     public native SocketAddress getsockname(FileDescriptor fd) throws ErrnoException;
     public native int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException;
     public native InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index 20a84bd..a8809bf 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -28,6 +28,7 @@
 import android.system.StructLinger;
 import android.system.StructPasswd;
 import android.system.StructPollfd;
+import android.system.StructRlimit;
 import android.system.StructStat;
 import android.system.StructStatVfs;
 import android.system.StructTimeval;
@@ -84,6 +85,7 @@
     public int getppid();
     public StructPasswd getpwnam(String name) throws ErrnoException;
     public StructPasswd getpwuid(int uid) throws ErrnoException;
+    public StructRlimit getrlimit(int resource) throws ErrnoException;
     public SocketAddress getsockname(FileDescriptor fd) throws ErrnoException;
     public int getsockoptByte(FileDescriptor fd, int level, int option) throws ErrnoException;
     public InetAddress getsockoptInAddr(FileDescriptor fd, int level, int option) throws ErrnoException;
diff --git a/luni/src/main/native/ExecStrings.cpp b/luni/src/main/native/ExecStrings.cpp
index 9a408fd..3c68511 100644
--- a/luni/src/main/native/ExecStrings.cpp
+++ b/luni/src/main/native/ExecStrings.cpp
@@ -22,7 +22,7 @@
 
 #include <log/log.h>
 
-#include "ScopedLocalRef.h"
+#include <nativehelper/ScopedLocalRef.h>
 
 ExecStrings::ExecStrings(JNIEnv* env, jobjectArray java_string_array)
     : env_(env), java_array_(java_string_array), array_(NULL) {
diff --git a/luni/src/main/native/IcuUtilities.cpp b/luni/src/main/native/IcuUtilities.cpp
index 0649023..43b2f27 100644
--- a/luni/src/main/native/IcuUtilities.cpp
+++ b/luni/src/main/native/IcuUtilities.cpp
@@ -17,14 +17,14 @@
 #define LOG_TAG "IcuUtilities"
 
 #include <android/log.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedUtfChars.h>
 
 #include "IcuUtilities.h"
 
-#include "JniConstants.h"
 #include "JniException.h"
-#include "JNIHelp.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
 #include "unicode/strenum.h"
 #include "unicode/ustring.h"
 #include "unicode/uloc.h"
diff --git a/luni/src/main/native/JniException.cpp b/luni/src/main/native/JniException.cpp
index 9744777..164281d 100644
--- a/luni/src/main/native/JniException.cpp
+++ b/luni/src/main/native/JniException.cpp
@@ -17,7 +17,7 @@
 #include <stdio.h>  // For BUFSIZ
 
 #include "JniException.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 void jniThrowExceptionWithErrno(JNIEnv* env, const char* exceptionClassName, int error) {
     char buf[BUFSIZ];
diff --git a/luni/src/main/native/NetFd.h b/luni/src/main/native/NetFd.h
index 0397e4d..ae4e5ab 100644
--- a/luni/src/main/native/NetFd.h
+++ b/luni/src/main/native/NetFd.h
@@ -17,7 +17,7 @@
 #ifndef NET_FD_H_included
 #define NET_FD_H_included
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 /**
  * Wraps access to the int inside a java.io.FileDescriptor, taking care of throwing exceptions.
diff --git a/luni/src/main/native/NetworkUtilities.cpp b/luni/src/main/native/NetworkUtilities.cpp
index bf438fa..b259814 100644
--- a/luni/src/main/native/NetworkUtilities.cpp
+++ b/luni/src/main/native/NetworkUtilities.cpp
@@ -17,9 +17,9 @@
 #define LOG_TAG "NetworkUtilities"
 
 #include "NetworkUtilities.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "ScopedLocalRef.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedLocalRef.h>
 
 #include <arpa/inet.h>
 #include <fcntl.h>
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index f642211..0c433da 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -20,8 +20,8 @@
 
 #include "log/log.h"
 
-#include "JniConstants.h"
-#include "ScopedLocalFrame.h"
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedLocalFrame.h>
 
 // DalvikVM calls this on startup, so we can statically register all our native methods.
 jint JNI_OnLoad(JavaVM* vm, void*) {
diff --git a/luni/src/main/native/ZipUtilities.cpp b/luni/src/main/native/ZipUtilities.cpp
index b7d2209..9fd32b5 100644
--- a/luni/src/main/native/ZipUtilities.cpp
+++ b/luni/src/main/native/ZipUtilities.cpp
@@ -17,7 +17,8 @@
 
 #include <memory>
 
-#include "JniConstants.h"
+#include <nativehelper/JniConstants.h>
+
 #include "JniException.h"
 #include "ZipUtilities.h"
 
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index a517475..963439c 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -16,8 +16,8 @@
 
 #define LOG_TAG "OsConstants"
 
-#include "JNIHelp.h"
-#include "JniConstants.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
 #include "Portability.h"
 
 #include <errno.h>
@@ -33,6 +33,7 @@
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
+#include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/un.h>
@@ -432,6 +433,7 @@
     initConstant(env, c, "PROT_READ", PROT_READ);
     initConstant(env, c, "PROT_WRITE", PROT_WRITE);
     initConstant(env, c, "R_OK", R_OK);
+    initConstant(env, c, "RLIMIT_NOFILE", RLIMIT_NOFILE);
 // NOTE: The RT_* constants are not preprocessor defines, they're enum
 // members. The best we can do (barring UAPI / kernel version checks) is
 // to hope they exist on all host linuxes we're building on. These
diff --git a/luni/src/main/native/cbigint.h b/luni/src/main/native/cbigint.h
index 2bf5b1b..9f7f715 100644
--- a/luni/src/main/native/cbigint.h
+++ b/luni/src/main/native/cbigint.h
@@ -18,7 +18,7 @@
 #if !defined(cbigint_h)
 #define cbigint_h
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #include <sys/types.h>
 #include <sys/param.h>
diff --git a/luni/src/main/native/java_lang_StringToReal.cpp b/luni/src/main/native/java_lang_StringToReal.cpp
index c321702..7f368b1 100644
--- a/luni/src/main/native/java_lang_StringToReal.cpp
+++ b/luni/src/main/native/java_lang_StringToReal.cpp
@@ -18,11 +18,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "JniException.h"
-#include "ScopedUtfChars.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include "cbigint.h"
+#include "JniException.h"
 
 /* ************************* Defines ************************* */
 
diff --git a/luni/src/main/native/java_lang_invoke_MethodHandle.cpp b/luni/src/main/native/java_lang_invoke_MethodHandle.cpp
index 4596b42..4574f59 100644
--- a/luni/src/main/native/java_lang_invoke_MethodHandle.cpp
+++ b/luni/src/main/native/java_lang_invoke_MethodHandle.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include "JniConstants.h"
-#include "JNIHelp.h"
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/JNIHelp.h>
 
 static void MethodHandle_invokeExact(JNIEnv* env, jobject, jobjectArray) {
     jniThrowException(env, "java/lang/UnsupportedOperationException",
diff --git a/luni/src/main/native/java_math_NativeBN.cpp b/luni/src/main/native/java_math_NativeBN.cpp
index 5c42be6..066f77e 100644
--- a/luni/src/main/native/java_math_NativeBN.cpp
+++ b/luni/src/main/native/java_math_NativeBN.cpp
@@ -16,12 +16,12 @@
 
 #define LOG_TAG "NativeBN"
 
-#include "JNIHelp.h"
-#include "JniConstants.h"
 #include "JniException.h"
-#include "ScopedPrimitiveArray.h"
-#include "ScopedUtfChars.h"
 #include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include <openssl/bn.h>
 #include <openssl/crypto.h>
 #include <openssl/err.h>
diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp
index 2271ba8..11af4bd 100644
--- a/luni/src/main/native/java_util_regex_Matcher.cpp
+++ b/luni/src/main/native/java_util_regex_Matcher.cpp
@@ -20,14 +20,14 @@
 #include <stdlib.h>
 
 #include <android-base/logging.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedStringChars.h>
 
 #include "IcuUtilities.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
 #include "JniException.h"
 #include "ScopedJavaUnicodeString.h"
-#include "ScopedPrimitiveArray.h"
-#include "ScopedStringChars.h"
 #include "jni.h"
 #include "unicode/parseerr.h"
 #include "unicode/regex.h"
diff --git a/luni/src/main/native/java_util_regex_Pattern.cpp b/luni/src/main/native/java_util_regex_Pattern.cpp
index 4166da03..f4d23cb 100644
--- a/luni/src/main/native/java_util_regex_Pattern.cpp
+++ b/luni/src/main/native/java_util_regex_Pattern.cpp
@@ -18,8 +18,8 @@
 
 #include <stdlib.h>
 
-#include "JNIHelp.h"
-#include "JniConstants.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
 #include "ScopedJavaUnicodeString.h"
 #include "jni.h"
 #include "unicode/parseerr.h"
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 0d8273b..50a5e9b 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -33,16 +33,16 @@
 
 #include <android-base/unique_fd.h>
 #include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <nativehelper/toStringArray.h>
 
 #include "IcuUtilities.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
 #include "JniException.h"
 #include "ScopedIcuLocale.h"
 #include "ScopedJavaUnicodeString.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
-#include "toStringArray.h"
 #include "unicode/brkiter.h"
 #include "unicode/calendar.h"
 #include "unicode/datefmt.h"
diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp
index e51730c..88452b8 100644
--- a/luni/src/main/native/libcore_icu_NativeConverter.cpp
+++ b/luni/src/main/native/libcore_icu_NativeConverter.cpp
@@ -22,16 +22,16 @@
 #include <vector>
 
 #include <android/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <nativehelper/toStringArray.h>
 
 #include "IcuUtilities.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
 #include "JniException.h"
-#include "ScopedLocalRef.h"
-#include "ScopedPrimitiveArray.h"
-#include "ScopedStringChars.h"
-#include "ScopedUtfChars.h"
-#include "toStringArray.h"
 #include "unicode/ucnv.h"
 #include "unicode/ucnv_cb.h"
 #include "unicode/uniset.h"
@@ -427,8 +427,13 @@
 
     EncoderCallbackContext* callbackContext = const_cast<EncoderCallbackContext*>(
             reinterpret_cast<const EncoderCallbackContext*>(oldCallbackContext));
+    // Hold the reference to any new callbackContext we create in a unique_ptr
+    // so that the default behavior is to collect it automatically if we exit
+    // early.
+    std::unique_ptr<EncoderCallbackContext> callbackContextDeleter;
     if (callbackContext == NULL) {
         callbackContext = new EncoderCallbackContext;
+        callbackContextDeleter.reset(callbackContext);
     }
 
     callbackContext->onMalformedInput = getFromUCallback(onMalformedInput);
@@ -444,6 +449,10 @@
 
     UErrorCode errorCode = U_ZERO_ERROR;
     ucnv_setFromUCallBack(cnv, CHARSET_ENCODER_CALLBACK, callbackContext, NULL, NULL, &errorCode);
+    // Iff callbackContextDeleter holds a reference to a callbackContext we can
+    // prevent it being automatically deleted here as responsibility for deletion
+    // has passed to the code that closes the NativeConverter.
+    callbackContextDeleter.release();
     maybeThrowIcuException(env, "ucnv_setFromUCallBack", errorCode);
 }
 
@@ -511,8 +520,13 @@
 
     DecoderCallbackContext* callbackContext = const_cast<DecoderCallbackContext*>(
             reinterpret_cast<const DecoderCallbackContext*>(oldCallbackContext));
+    // Hold the reference to any new callbackContext we create in a unique_ptr
+    // so that the default behavior is to collect it automatically if we exit
+    // early.
+    std::unique_ptr<DecoderCallbackContext> callbackContextDeleter;
     if (callbackContext == NULL) {
         callbackContext = new DecoderCallbackContext;
+        callbackContextDeleter.reset(callbackContext);
     }
 
     callbackContext->onMalformedInput = getToUCallback(onMalformedInput);
@@ -528,6 +542,10 @@
 
     UErrorCode errorCode = U_ZERO_ERROR;
     ucnv_setToUCallBack(cnv, CHARSET_DECODER_CALLBACK, callbackContext, NULL, NULL, &errorCode);
+    // Iff callbackContextDeleter holds a reference to a callbackContext we can
+    // prevent it being automatically deleted here as responsibility for deletion
+    // has passed to the code that closes the NativeConverter.
+    callbackContextDeleter.release();
     maybeThrowIcuException(env, "ucnv_setToUCallBack", errorCode);
 }
 
diff --git a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
index 545c778..29c07e2 100644
--- a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
+++ b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
@@ -18,15 +18,15 @@
 
 #include <memory>
 
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedUtfChars.h>
+
 #include "IcuUtilities.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
 #include "JniException.h"
-#include "JNIHelp.h"
 #include "ScopedIcuLocale.h"
 #include "ScopedJavaUnicodeString.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
 #include "unicode/calendar.h"
 #include "unicode/timezone.h"
 #include "unicode/tznames.h"
diff --git a/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp b/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
index a27e7b8..bf2d3a8 100644
--- a/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
+++ b/luni/src/main/native/libcore_io_AsynchronousCloseMonitor.cpp
@@ -16,9 +16,10 @@
 
 #define LOG_TAG "AsynchronousCloseMonitor"
 
-#include "AsynchronousCloseMonitor.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
+#include <nativehelper/AsynchronousCloseMonitor.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+
 #include "jni.h"
 
 static void AsynchronousCloseMonitor_signalBlockedThreads(JNIEnv* env, jclass, jobject javaFd) {
diff --git a/luni/src/main/native/libcore_io_Linux.cpp b/luni/src/main/native/libcore_io_Linux.cpp
index 176300e..26b7697 100644
--- a/luni/src/main/native/libcore_io_Linux.cpp
+++ b/luni/src/main/native/libcore_io_Linux.cpp
@@ -33,6 +33,7 @@
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
+#include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
@@ -51,19 +52,19 @@
 #include <android-base/file.h>
 #include <android-base/strings.h>
 #include <log/log.h>
+#include <nativehelper/AsynchronousCloseMonitor.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedBytes.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <nativehelper/toStringArray.h>
 
-#include "AsynchronousCloseMonitor.h"
 #include "ExecStrings.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
 #include "JniException.h"
 #include "NetworkUtilities.h"
 #include "Portability.h"
-#include "ScopedBytes.h"
-#include "ScopedLocalRef.h"
-#include "ScopedPrimitiveArray.h"
-#include "ScopedUtfChars.h"
-#include "toStringArray.h"
 
 #ifndef __unused
 #define __unused __attribute__((__unused__))
@@ -1315,6 +1316,19 @@
     return Passwd(env).getpwuid(uid);
 }
 
+static jobject Linux_getrlimit(JNIEnv* env, jobject, jint resource) {
+    struct rlimit r;
+    if (throwIfMinusOne(env, "getrlimit", TEMP_FAILURE_RETRY(getrlimit(resource, &r))) == -1) {
+        return nullptr;
+    }
+
+    ScopedLocalRef<jclass> rlimit_class(env, env->FindClass("android/system/StructRlimit"));
+    jmethodID ctor = env->GetMethodID(rlimit_class.get(), "<init>", "(JJ)V");
+    return env->NewObject(rlimit_class.get(), ctor,
+                          static_cast<jlong>(r.rlim_cur),
+                          static_cast<jlong>(r.rlim_max));
+}
+
 static jobject Linux_getsockname(JNIEnv* env, jobject, jobject javaFd) {
   return doGetSockName(env, javaFd, true);
 }
@@ -2421,6 +2435,7 @@
     NATIVE_METHOD(Linux, getppid, "()I"),
     NATIVE_METHOD(Linux, getpwnam, "(Ljava/lang/String;)Landroid/system/StructPasswd;"),
     NATIVE_METHOD(Linux, getpwuid, "(I)Landroid/system/StructPasswd;"),
+    NATIVE_METHOD(Linux, getrlimit, "(I)Landroid/system/StructRlimit;"),
     NATIVE_METHOD(Linux, getsockname, "(Ljava/io/FileDescriptor;)Ljava/net/SocketAddress;"),
     NATIVE_METHOD(Linux, getsockoptByte, "(Ljava/io/FileDescriptor;II)I"),
     NATIVE_METHOD(Linux, getsockoptInAddr, "(Ljava/io/FileDescriptor;II)Ljava/net/InetAddress;"),
diff --git a/luni/src/main/native/libcore_io_Memory.cpp b/luni/src/main/native/libcore_io_Memory.cpp
index 1acb8f4..5f50751 100644
--- a/luni/src/main/native/libcore_io_Memory.cpp
+++ b/luni/src/main/native/libcore_io_Memory.cpp
@@ -16,18 +16,19 @@
 
 #define LOG_TAG "Memory"
 
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "nativehelper/jni_macros.h"
-#include "Portability.h"
-#include "ScopedBytes.h"
-#include "ScopedPrimitiveArray.h"
-
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
 
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedBytes.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+
+#include "nativehelper/jni_macros.h"
+#include "Portability.h"
+
 // Use packed structures for access to unaligned data on targets with alignment restrictions.
 // The compiler will generate appropriate code to access these structures without
 // generating alignment exceptions.
diff --git a/luni/src/main/native/libcore_util_NativeAllocationRegistry.cpp b/luni/src/main/native/libcore_util_NativeAllocationRegistry.cpp
index 5c0f8df..59bed74 100644
--- a/luni/src/main/native/libcore_util_NativeAllocationRegistry.cpp
+++ b/luni/src/main/native/libcore_util_NativeAllocationRegistry.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "JniConstants.h"
+#include <nativehelper/JniConstants.h>
 
 typedef void (*FreeFunction)(void*);
 
diff --git a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
index aaf3ca1..22496bf 100644
--- a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
+++ b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
@@ -23,15 +23,15 @@
 
 #include <android/log.h>
 #include <android-base/stringprintf.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedUtfChars.h>
 
-#include "JNIHelp.h"
-#include "JniConstants.h"
-#include "JniException.h"
-#include "ScopedLocalRef.h"
-#include "ScopedPrimitiveArray.h"
-#include "ScopedStringChars.h"
-#include "ScopedUtfChars.h"
 #include "jni.h"
+#include "JniException.h"
 #include "unicode/unistr.h"
 
 
diff --git a/luni/src/main/native/sun_misc_Unsafe.cpp b/luni/src/main/native/sun_misc_Unsafe.cpp
index d0a23be..67925b0 100644
--- a/luni/src/main/native/sun_misc_Unsafe.cpp
+++ b/luni/src/main/native/sun_misc_Unsafe.cpp
@@ -16,8 +16,8 @@
 
 #define LOG_TAG "Unsafe"
 
-#include "JNIHelp.h"
-#include "JniConstants.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
 
 static jobject Unsafe_allocateInstance(JNIEnv* env, jclass, jclass c) {
   return env->AllocObject(c);
diff --git a/luni/src/main/native/valueOf.cpp b/luni/src/main/native/valueOf.cpp
index be99cff..fdd2502 100644
--- a/luni/src/main/native/valueOf.cpp
+++ b/luni/src/main/native/valueOf.cpp
@@ -17,8 +17,8 @@
 #define LOG_TAG "valueOf"
 
 #include "valueOf.h"
-#include "JNIHelp.h"
-#include "JniConstants.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
 
 template <typename T>
 static jobject valueOf(JNIEnv* env, jclass c, const char* signature, const T& value) {
diff --git a/luni/src/main/native/valueOf.h b/luni/src/main/native/valueOf.h
index 592977d..5c93b7c 100644
--- a/luni/src/main/native/valueOf.h
+++ b/luni/src/main/native/valueOf.h
@@ -17,7 +17,7 @@
 #ifndef VALUE_OF_H_included
 #define VALUE_OF_H_included
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 jobject booleanValueOf(JNIEnv* env, jboolean b);
 jobject doubleValueOf(JNIEnv* env, jdouble d);
diff --git a/luni/src/test/java/libcore/android/system/StructTimespecTest.java b/luni/src/test/java/libcore/android/system/StructTimespecTest.java
new file mode 100644
index 0000000..1cc4ade
--- /dev/null
+++ b/luni/src/test/java/libcore/android/system/StructTimespecTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.android.system;
+
+import android.system.StructTimespec;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link StructTimespec}
+ */
+public class StructTimespecTest extends TestCase {
+    public void testConstructor() {
+        StructTimespec val = new StructTimespec(Long.MIN_VALUE, 0);
+        assertEquals(Long.MIN_VALUE, val.tv_sec);
+        assertEquals(0, val.tv_nsec);
+
+        val = new StructTimespec(-23, 23);
+        assertEquals(-23, val.tv_sec);
+        assertEquals(23, val.tv_nsec);
+
+        val = new StructTimespec(0, 42);
+        assertEquals(0, val.tv_sec);
+        assertEquals(42, val.tv_nsec);
+
+        val = new StructTimespec(23, 91);
+        assertEquals(23, val.tv_sec);
+        assertEquals(91, val.tv_nsec);
+
+        val = new StructTimespec(Long.MAX_VALUE, 999_999_999);
+        assertEquals(Long.MAX_VALUE, val.tv_sec);
+        assertEquals(999_999_999, val.tv_nsec);
+    }
+
+    public void testConstructorInvalidNsec() {
+        try {
+            new StructTimespec(0, 1_000_000_000);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            new StructTimespec(0, -1);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    public void testCompare() {
+        StructTimespec[] specs = new StructTimespec[]{new StructTimespec(Long.MIN_VALUE, 0),
+                new StructTimespec(-24, 91),
+                new StructTimespec(-23, 23),
+                new StructTimespec(0, 41),
+                new StructTimespec(0, 42),
+                new StructTimespec(22, 91),
+                new StructTimespec(23, 23),
+                new StructTimespec(24, 91),
+                new StructTimespec(Long.MAX_VALUE, 999_999_999)};
+
+        for (int a = 0; a < specs.length; a++) {
+            for (int b = 0; b < specs.length; b++) {
+                if (a < b) {
+                    assertTrue(a + "<" + b, specs[a].compareTo(specs[b]) < 0);
+                } else if (a == b) {
+                    assertTrue(a + "==" + b, specs[a].compareTo(specs[b]) == 0);
+                } else {
+                    assertTrue(a + ">" + b,  specs[a].compareTo(specs[b]) > 0);
+                }
+            }
+        }
+    }
+
+    public void testEquals() {
+        StructTimespec allZero1 = new StructTimespec(0, 0);
+        StructTimespec allZero2 = new StructTimespec(0, 0);
+
+        StructTimespec val1 = new StructTimespec(23, 42);
+        StructTimespec val2 = new StructTimespec(23, 42);
+
+        StructTimespec secZero1 = new StructTimespec(0, 42);
+        StructTimespec secZero2 = new StructTimespec(0, 42);
+
+        StructTimespec nsecZero1 = new StructTimespec(23, 0);
+        StructTimespec nsecZero2 = new StructTimespec(23, 0);
+
+        assertTrue(allZero1.equals(allZero2));
+        assertTrue(val1.equals(val2));
+        assertTrue(secZero1.equals(secZero2));
+        assertTrue(nsecZero1.equals(nsecZero2));
+
+        // Compare equals in both directions
+        assertFalse(allZero1.equals(val1));
+        assertFalse(allZero1.equals(secZero1));
+        assertFalse(allZero1.equals(nsecZero1));
+
+        assertFalse(val1.equals(secZero1));
+        assertFalse(val1.equals(nsecZero1));
+        assertFalse(val1.equals(allZero1));
+
+        assertFalse(secZero1.equals(nsecZero1));
+        assertFalse(secZero1.equals(allZero1));
+        assertFalse(secZero1.equals(val1));
+
+        assertFalse(nsecZero1.equals(allZero1));
+        assertFalse(nsecZero1.equals(val1));
+        assertFalse(nsecZero1.equals(secZero1));
+    }
+
+    public void testHashcode() {
+        StructTimespec allZero1 = new StructTimespec(0, 0);
+        StructTimespec allZero2 = new StructTimespec(0, 0);
+
+        StructTimespec val1 = new StructTimespec(23, 42);
+        StructTimespec val2 = new StructTimespec(23, 42);
+
+        StructTimespec secZero1 = new StructTimespec(0, 42);
+        StructTimespec secZero2 = new StructTimespec(0, 42);
+
+        StructTimespec nsecZero1 = new StructTimespec(23, 0);
+        StructTimespec nsecZero2 = new StructTimespec(23, 0);
+
+        // Equal objects should have same hash code
+        assertEquals(allZero1.hashCode(), allZero2.hashCode());
+        assertEquals(val1.hashCode(), val2.hashCode());
+        assertEquals(secZero1.hashCode(), secZero2.hashCode());
+        assertEquals(nsecZero1.hashCode(), nsecZero2.hashCode());
+    }
+}
diff --git a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
index e2fe951..e7421b7 100644
--- a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
@@ -30,10 +30,12 @@
 
 public final class BaseDexClassLoaderTest extends TestCase {
     private static class Reporter implements BaseDexClassLoader.Reporter {
+        public List<BaseDexClassLoader> classLoaders = new ArrayList<>();
         public List<String> loadedDexPaths = new ArrayList<>();
 
         @Override
-        public void report(List<String> dexPaths) {
+        public void report(List<BaseDexClassLoader> loaders, List<String> dexPaths) {
+            classLoaders.addAll(loaders);
             loadedDexPaths.addAll(dexPaths);
         }
     }
@@ -51,11 +53,19 @@
         Reporter reporter = new Reporter();
         BaseDexClassLoader.setReporter(reporter);
         // Load the jar file using a PathClassLoader.
-        BaseDexClassLoader cl1 = new PathClassLoader(jar.getPath(), pcl);
+        BaseDexClassLoader cl1 = new PathClassLoader(jar.getPath(),
+            ClassLoader.getSystemClassLoader());
 
         // Verify the reporter files.
-        assertEquals(1, reporter.loadedDexPaths.size());
+        assertEquals(2, reporter.loadedDexPaths.size());
+        assertEquals(2, reporter.classLoaders.size());
+
+        // First class loader should be the one loading the files
         assertEquals(jar.getPath(), reporter.loadedDexPaths.get(0));
+        assertEquals(cl1, reporter.classLoaders.get(0));
+        // Second class loader should be the system class loader.
+        // Don't check the actual classpath as that might vary based on system properties.
+        assertEquals(ClassLoader.getSystemClassLoader(), reporter.classLoaders.get(1));
 
         // Reset the reporter and check we don't report anymore.
         BaseDexClassLoader.setReporter(null);
@@ -64,8 +74,12 @@
         BaseDexClassLoader cl2 = new PathClassLoader(jar.getPath(), pcl);
 
         // Verify the list reporter files did not change.
-        assertEquals(1, reporter.loadedDexPaths.size());
+        assertEquals(2, reporter.loadedDexPaths.size());
+        assertEquals(2, reporter.classLoaders.size());
+
         assertEquals(jar.getPath(), reporter.loadedDexPaths.get(0));
+        assertEquals(cl1, reporter.classLoaders.get(0));
+        assertEquals(ClassLoader.getSystemClassLoader(), reporter.classLoaders.get(1));
 
         // Clean up the extracted jar file.
         assertTrue(jar.delete());
diff --git a/luni/src/test/java/libcore/io/BlockGuardOsTest.java b/luni/src/test/java/libcore/io/BlockGuardOsTest.java
index 567cf2d..bb10c3e 100644
--- a/luni/src/test/java/libcore/io/BlockGuardOsTest.java
+++ b/luni/src/test/java/libcore/io/BlockGuardOsTest.java
@@ -70,6 +70,7 @@
                 "getppid()",
                 "getpwnam(java.lang.String)",
                 "getpwuid(int)",
+                "getrlimit(int)",
                 "getsockname(java.io.FileDescriptor)",
                 "getsockoptByte(java.io.FileDescriptor,int,int)",
                 "getsockoptInAddr(java.io.FileDescriptor,int,int)",
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index 0f47d87..a509c2b 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -20,6 +20,7 @@
 import android.system.NetlinkSocketAddress;
 import android.system.OsConstants;
 import android.system.PacketSocketAddress;
+import android.system.StructRlimit;
 import android.system.StructStat;
 import android.system.StructTimeval;
 import android.system.StructUcred;
@@ -803,4 +804,12 @@
     assertEquals(0, structStat1.st_atim.compareTo(structStat2.st_atim));
   }
 
+  public void test_getrlimit() throws Exception {
+    StructRlimit rlimit = Libcore.os.getrlimit(OsConstants.RLIMIT_NOFILE);
+    // We can't really make any assertions about these values since they might vary from
+    // device to device and even process to process. We do know that they will be greater
+    // than zero, though.
+    assertTrue(rlimit.rlim_cur > 0);
+    assertTrue(rlimit.rlim_max > 0);
+  }
 }
diff --git a/luni/src/test/java/libcore/java/net/OldURLClassLoaderTest.java b/luni/src/test/java/libcore/java/net/OldURLClassLoaderTest.java
index 2f1221d..06bd1c5 100644
--- a/luni/src/test/java/libcore/java/net/OldURLClassLoaderTest.java
+++ b/luni/src/test/java/libcore/java/net/OldURLClassLoaderTest.java
@@ -26,10 +26,12 @@
 import java.net.URLClassLoader;
 import java.security.CodeSource;
 import java.security.PermissionCollection;
+import java.security.cert.Certificate;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.jar.Manifest;
+
 import tests.support.Support_TestWebData;
 import tests.support.Support_TestWebServer;
 import tests.support.resource.Support_Resources;
@@ -145,6 +147,19 @@
         } catch (ClassNotFoundException expected) { }
     }
 
+    // http://b/37380202
+    public void test_getPermissions_fileURLConnection_doesNotThrow() throws Exception {
+        File file = File.createTempFile("test_getPermissions_fileURLConnection", "tmp");
+        try {
+            URL url = file.toURL();
+            TestURLClassLoader urlClassLoader = new TestURLClassLoader(new URL[] { url });
+            CodeSource codeSource = new CodeSource(url, new Certificate[0]);
+            urlClassLoader.getPermissions(codeSource);
+        } finally {
+            file.delete();
+        }
+    }
+
     public void test_definePackage() throws MalformedURLException {
         Manifest manifest = new Manifest();
         URL[] u = new URL[0];
diff --git a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
index 7d81af6..8976447 100644
--- a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
@@ -441,6 +441,7 @@
 
         DatagramChannel dc = createReceiverChannel();
         dc.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, true /* enable loop */);
+        dc.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);
         configureChannelForReceiving(dc);
         dc.join(group, networkInterface);
 
diff --git a/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java b/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java
index b01350d..a0e75fe 100644
--- a/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java
+++ b/luni/src/test/java/libcore/java/nio/file/LinkPermissionTest.java
@@ -25,10 +25,11 @@
     public void test_constructor$String() {
         // Only "hard" and "symbolic" are the supported permission target names.
         LinkPermission linkPermission = new LinkPermission("hard");
-        assertNull(linkPermission.getName());
+        // Sanity check that getName() doesn't throw.
+        linkPermission.getName();
 
         linkPermission = new LinkPermission("symbolic");
-        assertNull(linkPermission.getName());
+        linkPermission.getName();
 
         // Non supported permission target names.
         try {
diff --git a/luni/src/test/java/libcore/java/nio/file/WatchServiceTest.java b/luni/src/test/java/libcore/java/nio/file/WatchServiceTest.java
index c53f531..fc5e84e 100644
--- a/luni/src/test/java/libcore/java/nio/file/WatchServiceTest.java
+++ b/luni/src/test/java/libcore/java/nio/file/WatchServiceTest.java
@@ -15,16 +15,11 @@
  */
 package libcore.java.nio.file;
 
-import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 
-import java.io.IOException;
-import java.nio.file.FileStore;
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -78,16 +73,25 @@
         }
     }
 
-    static public void assertWatchServiceEvent(WatchService watchService,
-            WatchKey expectedWatchKey,
-            List<WatchEventResult> expectedEvents,
+    private static void checkWatchServiceEventMultipleKeys(WatchService watchService,
+            Map<WatchKey, List<WatchEventResult>> expectedResults,
             boolean expectedResetResult) throws InterruptedException {
-        Iterator<WatchEventResult> expectedEventsIterator = expectedEvents.iterator();
 
-        while (expectedEventsIterator.hasNext()) {
+        // Make a deep copy
+        HashMap<WatchKey, ArrayList<WatchEventResult>> expectedResultsCopy
+                = new HashMap<>();
+        for (Map.Entry<WatchKey, List<WatchEventResult>> entry : expectedResults.entrySet()) {
+            expectedResultsCopy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
+        }
+
+        while (!expectedResultsCopy.isEmpty()) {
             WatchKey watchKey = watchService.poll(2, TimeUnit.SECONDS);
-            assertEquals(expectedWatchKey, watchKey);
+            assertNotNull(watchKey);
 
+            List<WatchEventResult> expectedEvents = expectedResultsCopy.get(watchKey);
+            assertNotNull(expectedEvents);
+
+            Iterator<WatchEventResult> expectedEventsIterator = expectedEvents.iterator();
             for (WatchEvent<?> event : watchKey.pollEvents()) {
                 WatchEventResult expectedEventResult = expectedEventsIterator.next();
                 assertNotNull(expectedEventResult);
@@ -96,12 +100,24 @@
                 if (expectedEventResult.testCount) {
                     assertEquals(expectedEventResult.expectedCount, event.count());
                 }
+                expectedEventsIterator.remove();
             }
-
             assertEquals(expectedResetResult, watchKey.reset());
+            if (!expectedEventsIterator.hasNext()) {
+                expectedResultsCopy.remove(watchKey);
+            }
         }
     }
 
+    private static void checkWatchServiceEvent(WatchService watchService,
+            WatchKey expectedWatchKey,
+            List<WatchEventResult> expectedEvents,
+            boolean expectedResetResult) throws InterruptedException {
+        Map<WatchKey, List<WatchEventResult>> expected = new HashMap<>();
+        expected.put(expectedWatchKey, expectedEvents);
+        checkWatchServiceEventMultipleKeys(watchService, expected, expectedResetResult);
+    }
+
     @Test
     public void test_singleFile() throws Exception {
         WatchService watchService = FileSystems.getDefault().newWatchService();
@@ -113,13 +129,13 @@
 
         // emit EVENT_CREATE
         Files.createFile(file);
-        assertWatchServiceEvent(watchService, directoryKey1,
+        checkWatchServiceEvent(watchService, directoryKey1,
             Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1)), true);
         assertNull(watchService.poll());
-      
+
         // emit EVENT_MODIFY
         Files.write(file, "hello1".getBytes());
-        assertWatchServiceEvent(watchService, directoryKey1,
+        checkWatchServiceEvent(watchService, directoryKey1,
             Arrays.asList(new WatchEventResult(ENTRY_MODIFY)), true);
 
         // http:///b/35346596
@@ -133,11 +149,11 @@
             assertEquals(ENTRY_MODIFY, event.get(0).kind());
             doubleModifyKey.reset();
         }
-        assertNull(watchService.poll());      
+        assertNull(watchService.poll());
 
         // emit EVENT_DELETE
         Files.delete(file);
-        assertWatchServiceEvent(watchService, directoryKey1,
+        checkWatchServiceEvent(watchService, directoryKey1,
             Arrays.asList(new WatchEventResult(ENTRY_DELETE, 1)), true);
 
         // Assert no more events
@@ -162,7 +178,7 @@
         // emit EVENT_DELETE (masked)
         Files.delete(file);
 
-        assertWatchServiceEvent(watchService, directoryKey1,
+        checkWatchServiceEvent(watchService, directoryKey1,
                 Arrays.asList(new WatchEventResult(ENTRY_DELETE, 1)), true);
         assertNull(watchService.poll());
         watchService.close();
@@ -188,7 +204,7 @@
         // emit EVENT_DELETE
         Files.delete(dirInDir);
 
-        assertWatchServiceEvent(watchService, directoryKey1,
+        checkWatchServiceEvent(watchService, directoryKey1,
                 Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1),
                               new WatchEventResult(ENTRY_DELETE, 1)), true);
         assertNull(watchService.poll());
@@ -221,7 +237,7 @@
         Files.write(file, "hello1".getBytes());
         Files.delete(file);
 
-        assertWatchServiceEvent(watchService, directoryKey1,
+        checkWatchServiceEvent(watchService, directoryKey1,
                 Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1)), false);
         assertNull(watchService.poll());
         watchService.close();
@@ -250,7 +266,7 @@
             Thread.sleep(500);
         }
 
-        assertWatchServiceEvent(watchService, directoryKey1,
+        checkWatchServiceEvent(watchService, directoryKey1,
                 Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1),
                               new WatchEventResult(ENTRY_DELETE, 1)), false);
         assertNull(watchService.poll());
@@ -282,13 +298,17 @@
             Files.delete(path);
         }
 
-        assertWatchServiceEvent(watchService1, directoryKey1,
-                                Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1),
-                                              new WatchEventResult(ENTRY_DELETE, 1)), true);
-        assertWatchServiceEvent(watchService1, directoryKey2,
-                                Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1),
-                                              new WatchEventResult(ENTRY_DELETE, 1)), true);
+        Map<WatchKey, List<WatchEventResult>> expected = new HashMap<>();
+        expected.put(directoryKey1,
+                Arrays.asList(
+                        new WatchEventResult(ENTRY_CREATE, 1),
+                        new WatchEventResult(ENTRY_DELETE, 1)));
+        expected.put(directoryKey2,
+                Arrays.asList(
+                        new WatchEventResult(ENTRY_CREATE, 1),
+                        new WatchEventResult(ENTRY_DELETE, 1)));
 
+        checkWatchServiceEventMultipleKeys(watchService1, expected, true);
         assertNull(watchService1.poll());
         watchService1.close();
     }
@@ -319,10 +339,10 @@
             Files.delete(path);
         }
 
-        assertWatchServiceEvent(watchService1, directoryKey1,
+        checkWatchServiceEvent(watchService1, directoryKey1,
                                 Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1),
                                               new WatchEventResult(ENTRY_DELETE, 1)), true);
-        assertWatchServiceEvent(watchService2, directoryKey2,
+        checkWatchServiceEvent(watchService2, directoryKey2,
                                 Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1),
                                               new WatchEventResult(ENTRY_DELETE, 1)), true);
 
@@ -332,10 +352,10 @@
             Files.createFile(dir1file1);
             Files.delete(dir1file1);
         }
-        assertWatchServiceEvent(watchService1, directoryKey1,
+        checkWatchServiceEvent(watchService1, directoryKey1,
                                 Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1),
                                               new WatchEventResult(ENTRY_DELETE, 1)), true);
-        assertWatchServiceEvent(watchService2, directoryKey3,
+        checkWatchServiceEvent(watchService2, directoryKey3,
                                 Arrays.asList(new WatchEventResult(ENTRY_CREATE, 1),
                                               new WatchEventResult(ENTRY_DELETE, 1)), true);
 
@@ -346,4 +366,4 @@
         assertNull(watchService2.poll());
         watchService2.close();
     }
-}
\ No newline at end of file
+}
diff --git a/luni/src/test/java/libcore/java/text/DecimalFormatTest.java b/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
index ba8cbeb..1d506f3 100644
--- a/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
@@ -248,11 +248,29 @@
       } catch (NullPointerException expected) {
       }
 
-      // These just ignore null.
-      df.setNegativePrefix(null);
-      df.setNegativeSuffix(null);
-      df.setPositivePrefix(null);
-      df.setPositiveSuffix(null);
+      try {
+        df.setNegativePrefix(null);
+        fail();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        df.setNegativeSuffix(null);
+        fail();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        df.setPositivePrefix(null);
+        fail();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        df.setPositiveSuffix(null);
+        fail();
+      } catch (NullPointerException expected) {
+      }
 
       try {
         df.setRoundingMode(null);
@@ -335,4 +353,42 @@
         localeCurrencyFormat.setCurrency(currency);
         return localeCurrencyFormat.format(1000);
     }
+
+    /**
+     * DecimalFormat doesn't support different group separator for currency and non-currency
+     * number formats. Ensure normal group separator is used, and ignore monetary group separator
+     * when formatting currency. http://b/37135768
+     */
+    public void testLocaleGroupingSeparator() {
+        // CLDR uses '.' for currency and '\u00a0' for non-currency number formats in de_AT
+        // Assert ICU is using these characters
+        Locale locale = new Locale("de", "AT");
+        android.icu.text.DecimalFormatSymbols icuDfs =
+                new android.icu.text.DecimalFormatSymbols(locale);
+        assertEquals(icuDfs.getGroupingSeparator(), '\u00a0');
+        assertEquals(icuDfs.getMonetaryGroupingSeparator(), '.');
+
+        // In this class, only '\u00a0' should be used for both cases.
+        DecimalFormatSymbols dfs = new DecimalFormatSymbols(locale);
+        // Assert CLDR uses '\u00a0' as grouping separator
+        assertEquals(dfs.getGroupingSeparator(), '\u00a0');
+
+        // Test non-currency number formats
+        assertEquals("1\u00a0234,00", new DecimalFormat("#,##0.00", dfs).format(1234));
+        // Test currency format
+        assertEquals("\u20ac1\u00a0234,00", new DecimalFormat("¤#,##0.00", dfs).format(1234));
+    }
+
+    /**
+     * Test {@link DecimalFormatSymbols#setGroupingSeparator(char)} for currency and non-currency
+     * number formats. http://b/37135768
+     */
+    public void testSetGroupingSeparator() {
+        DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
+        dfs.setGroupingSeparator(' ');
+        // Test non-currency number formats
+        assertEquals("1 234.00", new DecimalFormat("#,##0.00", dfs).format(1234));
+        // Test currency format
+        assertEquals("$1 234.00", new DecimalFormat("¤#,##0.00", dfs).format(1234));
+    }
 }
diff --git a/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java b/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
index 205faac..eb3f4ca 100644
--- a/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
+++ b/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
@@ -60,14 +60,6 @@
         } catch (IllegalArgumentException e) {
             // expected
         }
-
-        try {
-            format.applyPattern("@.###");
-            fail("expected IllegalArgumentException was not thrown for "
-                    + "pattern \"@.###\".");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
     }
 
     // AndroidOnly: special feature of icu4c
diff --git a/luni/src/test/java/libcore/java/text/OldNumberFormatTest.java b/luni/src/test/java/libcore/java/text/OldNumberFormatTest.java
index ad7ef0b..711409c 100644
--- a/luni/src/test/java/libcore/java/text/OldNumberFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/OldNumberFormatTest.java
@@ -68,7 +68,7 @@
         assertEquals("Wrong result: case 1", "23", format.format(123));
 
         format.setMaximumIntegerDigits(Integer.MIN_VALUE);
-        assertEquals("Wrong result: case 2", "0", format.format(123));
+        assertEquals("Wrong result: case 2", ".0", format.format(123));
     }
 
     public void test_setCurrencyLjava_util_Currency() {
@@ -196,9 +196,6 @@
         nf2.setMaximumIntegerDigits(100);
         assertFalse("Different NumberFormat are equal", nf1.equals(nf2));
 
-        nf2.setMaximumIntegerDigits(nf1.getMaximumIntegerDigits());
-        assertTrue("THe same Objects are not equal", nf1.equals(nf2));
-
         nf1 = NumberFormat.getIntegerInstance();
         nf2 = NumberFormat.getIntegerInstance(Locale.CHINA);
         assertFalse("Different NumberFormat are equal", nf1.equals(nf2));
@@ -223,7 +220,7 @@
         // use de_CH instead
         // assertEquals("Wrong result for double : " + out, "1,234,567,890.012-",
         //         out.toString());
-        assertEquals("Wrong result for double : " + out, "-1'234'567'890.012", out.toString());
+        assertEquals("Wrong result for double : " + out, "-1’234’567’890.012", out.toString());
 
         out = nf1.format(1.0001);
         assertEquals("Wrong result for for double: " + out, "1", out.toString());
@@ -250,7 +247,7 @@
         // use de_CH instead
         // assertEquals("Wrong result for double : " + out, "-1 234 567 890", out
         //         .toString());
-        assertEquals("Wrong result for double : " + out, "-1'234'567'890", out.toString());
+        assertEquals("Wrong result for double : " + out, "-1’234’567’890", out.toString());
 
         // the Locale data of icu uses \uc2a0
         out = nf1.format(1);
@@ -317,7 +314,7 @@
         format = NumberFormat.getCurrencyInstance(atLocale);
         // BEGIN Android-changed: ICU uses non-breaking space after the euro sign; the RI uses ' '.
         assertEquals("\u20ac\u00a035,76", format.format(35.76));
-        assertEquals("\u20ac\u00a0123.456,79", format.format(123456.789));
+        assertEquals("\u20ac\u00a0123\u00a0456,79", format.format(123456.789));
         assertEquals("\u20ac\u00a00,10", format.format(0.1));
         assertEquals("\u20ac\u00a01,00", format.format(0.999));
         try {
@@ -354,9 +351,9 @@
         assertNotSame(null, format);
         assertTrue(format instanceof NumberFormat);
 
-        assertEquals("1'234'567'890.099", format.format(1234567890.0987654321));
+        assertEquals("1’234’567’890.099", format.format(1234567890.0987654321));
         assertEquals("#,##0.###", ((DecimalFormat) format).toPattern());
-        assertEquals("123'456'789", format.format(123456789));
+        assertEquals("123’456’789", format.format(123456789));
 
         try {
             NumberFormat.getInstance(null);
@@ -391,9 +388,9 @@
         assertNotSame("Instance is null", null, format);
         assertTrue("Object is not instance of NumberFormat", format instanceof NumberFormat);
 
-        assertEquals("-1'234'567'890.099", format.format(-1234567890.0987654321));
+        assertEquals("-1’234’567’890.099", format.format(-1234567890.0987654321));
         assertEquals("#,##0.###", ((DecimalFormat) format).toPattern());
-        assertEquals("123'456'789", format.format(123456789));
+        assertEquals("123’456’789", format.format(123456789));
 
         try {
             NumberFormat.getInstance(null);
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 9f7267c..c16f538 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -463,6 +463,7 @@
                 android.icu.util.TimeZone.clearCachedDefault();
             }
         });
+        clearer.setPriority(Thread.MAX_PRIORITY);
         clearer.setName("testSetDefaultRace clearer");
         clearer.setUncaughtExceptionHandler(handler);
 
@@ -472,15 +473,15 @@
                 android.icu.util.TimeZone.getDefault();
             }
         });
+        getter.setPriority(Thread.MAX_PRIORITY);
         getter.setName("testSetDefaultRace getter");
         getter.setUncaughtExceptionHandler(handler);
 
         clearer.start();
         getter.start();
 
-        // 2 seconds is plenty: If successful, we usually complete much faster.
-        clearer.join(1000);
-        getter.join(1000);
+        clearer.join();
+        getter.join();
 
         if (!exceptions.isEmpty()) {
             Throwable firstException = exceptions.get(0);
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
index 5691dfb..f58211d 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
@@ -16,11 +16,23 @@
 
 package libcore.javax.net.ssl;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.Arrays;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import javax.net.ServerSocketFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import junit.framework.TestCase;
 import libcore.java.security.StandardNames;
 import libcore.java.security.TestKeyStore;
-import java.util.Arrays;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import junit.framework.TestCase;
+
 
 public class SSLSessionTest extends TestCase {
 
@@ -310,4 +322,47 @@
         assertEquals(0, s.invalid.getValueNames().length);
         s.close();
     }
+
+    private static String alterOriginalHostName(InetAddress inetAddress, String originalHostName)
+           throws Exception {
+        Method getHolder = InetAddress.class.getDeclaredMethod("holder");
+        getHolder.setAccessible(true);
+
+        Field originalHostNameField = Class.forName("java.net.InetAddress$InetAddressHolder")
+            .getDeclaredField("originalHostName");
+        originalHostNameField.setAccessible(true);
+
+        Object holder = getHolder.invoke(inetAddress);
+        String oldValue = (String)originalHostNameField.get(holder);
+        originalHostNameField.set(holder, originalHostName);
+        return oldValue;
+    }
+
+    // http://b/35942385
+    public void test_SSLSession_getPeerHostFromInetAddress() throws Exception {
+        InetAddress inetAddress = InetAddress.getByName("localhost");
+        String oldOriginalHostName = alterOriginalHostName(inetAddress, "foobar");
+        try {
+            final TestSSLContext c = TestSSLContext.create();
+            final SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(
+                    InetAddress.getByName("localhost"), c.port);
+            final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+
+            ExecutorService executor = Executors.newSingleThreadExecutor();
+            Future<Void> future = executor.submit(() -> {server.startHandshake(); return null;});
+            executor.shutdown();
+            client.startHandshake();
+
+            SSLSession sslSession = client.getSession();
+            assertEquals("foobar", sslSession.getPeerHost());
+
+            future.get();
+            client.close();
+            server.close();
+            c.close();
+        } finally {
+            // Restore the original value (InetAddress objects are cached).
+            alterOriginalHostName(inetAddress, oldOriginalHostName);
+        }
+    }
 }
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 44cda4b..91bd59d 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -791,7 +791,7 @@
         try {
             test_SSLSocket_setUseClientMode(false, false);
             fail();
-        } catch (SocketTimeoutException expected) {
+        } catch (SocketTimeoutException|SSLHandshakeException expected) {
         }
     }
 
diff --git a/luni/src/test/native/libcore_java_io_FileTest.cpp b/luni/src/test/native/libcore_java_io_FileTest.cpp
index 4dcf487..7cc6568 100644
--- a/luni/src/test/native/libcore_java_io_FileTest.cpp
+++ b/luni/src/test/native/libcore_java_io_FileTest.cpp
@@ -22,8 +22,8 @@
 #include <errno.h>
 
 #include <jni.h>
-#include "JNIHelp.h"
-#include "ScopedUtfChars.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
 
 extern "C" void Java_libcore_java_io_FileTest_nativeTestFilesWithSurrogatePairs(
     JNIEnv* env, jobject /* clazz */, jstring baseDir) {
diff --git a/luni/src/test/native/libcore_java_lang_ThreadTest.cpp b/luni/src/test/native/libcore_java_lang_ThreadTest.cpp
index 68e858a..f942607 100644
--- a/luni/src/test/native/libcore_java_lang_ThreadTest.cpp
+++ b/luni/src/test/native/libcore_java_lang_ThreadTest.cpp
@@ -21,7 +21,7 @@
 #include <sys/prctl.h>
 
 #include <jni.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 static JavaVM* javaVm = nullptr;
 
diff --git a/luni/src/test/native/libcore_java_nio_BufferTest.cpp b/luni/src/test/native/libcore_java_nio_BufferTest.cpp
index 2b71b3e..ab7c20e 100644
--- a/luni/src/test/native/libcore_java_nio_BufferTest.cpp
+++ b/luni/src/test/native/libcore_java_nio_BufferTest.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <jni.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 extern "C" jlong Java_libcore_java_nio_BufferTest_jniGetDirectBufferAddress(
     JNIEnv* env, jobject /* clazz */, jobject buffer) {
diff --git a/luni/src/test/native/libcore_util_NativeAllocationRegistryTest.cpp b/luni/src/test/native/libcore_util_NativeAllocationRegistryTest.cpp
index 3b458e2..2260d37 100644
--- a/luni/src/test/native/libcore_util_NativeAllocationRegistryTest.cpp
+++ b/luni/src/test/native/libcore_util_NativeAllocationRegistryTest.cpp
@@ -18,8 +18,8 @@
 #include <string>
 
 #include <jni.h>
-#include "JNIHelp.h"
-#include "ScopedUtfChars.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
 
 uint64_t gNumNativeBytesAllocated = 0;
 
diff --git a/non_openjdk_java_files.mk b/non_openjdk_java_files.mk
index 29f8d0c..7b1d180 100644
--- a/non_openjdk_java_files.mk
+++ b/non_openjdk_java_files.mk
@@ -16,6 +16,7 @@
   luni/src/main/java/android/system/StructLinger.java \
   luni/src/main/java/android/system/StructPasswd.java \
   luni/src/main/java/android/system/StructPollfd.java \
+  luni/src/main/java/android/system/StructRlimit.java \
   luni/src/main/java/android/system/StructStat.java \
   luni/src/main/java/android/system/StructStatVfs.java \
   luni/src/main/java/android/system/StructTimeval.java \
diff --git a/ojluni/src/main/java/java/io/FilePermission.java b/ojluni/src/main/java/java/io/FilePermission.java
index f9544c7..bb69075 100644
--- a/ojluni/src/main/java/java/io/FilePermission.java
+++ b/ojluni/src/main/java/java/io/FilePermission.java
@@ -35,7 +35,7 @@
 
 public final class FilePermission extends Permission implements Serializable {
 
-    public FilePermission(String path, String actions) { super(""); }
+    public FilePermission(String path, String actions) { super(path); }
 
     public boolean implies(Permission p) { return true; }
     public String getActions() { return null; }
diff --git a/ojluni/src/main/java/java/net/Inet4Address.java b/ojluni/src/main/java/java/net/Inet4Address.java
index f9d1015..9c8e5fb 100644
--- a/ojluni/src/main/java/java/net/Inet4Address.java
+++ b/ojluni/src/main/java/java/net/Inet4Address.java
@@ -123,11 +123,13 @@
                 holder().address = address;
             }
         }
+        holder().originalHostName = hostName;
     }
     Inet4Address(String hostName, int address) {
         holder().hostName = hostName;
         holder().family = AF_INET;
         holder().address = address;
+        holder().originalHostName = hostName;
     }
 
     /**
diff --git a/ojluni/src/main/java/java/net/Inet6AddressImpl.java b/ojluni/src/main/java/java/net/Inet6AddressImpl.java
index 311c023..2a897f7 100644
--- a/ojluni/src/main/java/java/net/Inet6AddressImpl.java
+++ b/ojluni/src/main/java/java/net/Inet6AddressImpl.java
@@ -123,6 +123,7 @@
             // TODO: should getaddrinfo set the hostname of the InetAddresses it returns?
             for (InetAddress address : addresses) {
                 address.holder().hostName = host;
+                address.holder().originalHostName = host;
             }
             addressCache.put(host, netId, addresses);
             return addresses;
diff --git a/ojluni/src/main/java/java/net/InetAddress.java b/ojluni/src/main/java/java/net/InetAddress.java
index d8e5958..1468b2d 100644
--- a/ojluni/src/main/java/java/net/InetAddress.java
+++ b/ojluni/src/main/java/java/net/InetAddress.java
@@ -197,7 +197,7 @@
          *
          * Note: May define a new public method in the future if necessary.
          */
-        private String originalHostName;
+        String originalHostName;
 
         InetAddressHolder() {}
 
diff --git a/ojluni/src/main/java/java/security/Permission.java b/ojluni/src/main/java/java/security/Permission.java
index 54163b9..9b258a6 100644
--- a/ojluni/src/main/java/java/security/Permission.java
+++ b/ojluni/src/main/java/java/security/Permission.java
@@ -33,13 +33,19 @@
 
 public abstract class Permission implements Guard, java.io.Serializable {
 
-    public Permission(String name) { }
+    private String name;
+
+    public Permission(String name) {
+        this.name = name;
+    }
 
     public void checkGuard(Object object) throws SecurityException { }
 
     public abstract boolean implies(Permission permission);
 
-    public final String getName() { return null; }
+    public final String getName() {
+        return name;
+    }
 
     public abstract String getActions();
 
diff --git a/ojluni/src/main/java/java/text/DecimalFormat.java b/ojluni/src/main/java/java/text/DecimalFormat.java
index 3ceb9cd..17d5d41 100644
--- a/ojluni/src/main/java/java/text/DecimalFormat.java
+++ b/ojluni/src/main/java/java/text/DecimalFormat.java
@@ -48,6 +48,7 @@
 import java.math.RoundingMode;
 import java.util.Currency;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -1593,36 +1594,87 @@
         ObjectInputStream.GetField fields = stream.readFields();
         this.symbols = (DecimalFormatSymbols) fields.get("symbols", null);
 
-        init("");
+        init("#");
 
-        icuDecimalFormat.setPositivePrefix((String) fields.get("positivePrefix", ""));
-        icuDecimalFormat.setPositiveSuffix((String) fields.get("positiveSuffix", ""));
-        icuDecimalFormat.setNegativePrefix((String) fields.get("negativePrefix", "-"));
-        icuDecimalFormat.setNegativeSuffix((String) fields.get("negativeSuffix", ""));
-        icuDecimalFormat.setMultiplier(fields.get("multiplier", 1));
-        icuDecimalFormat.setGroupingSize(fields.get("groupingSize", (byte) 3));
-        icuDecimalFormat.setGroupingUsed(fields.get("groupingUsed", true));
-        icuDecimalFormat.setDecimalSeparatorAlwaysShown(fields.get("decimalSeparatorAlwaysShown",
-                false));
+        // Calling a setter method on an ICU DecimalFormat object will change the object's internal
+        // state, even if the value set is the same as the default value (ICU Ticket #13266).
+        //
+        // In an attempt to create objects that are equals() to the ones that were serialized, it's
+        // therefore assumed here that any values that are the same as the default values were the
+        // default values (ie. no setter was called to explicitly set that value).
 
-        setRoundingMode((RoundingMode) fields.get("roundingMode", RoundingMode.HALF_EVEN));
+        String positivePrefix = (String) fields.get("positivePrefix", "");
+        if (!Objects.equals(positivePrefix, icuDecimalFormat.getPositivePrefix())) {
+            icuDecimalFormat.setPositivePrefix(positivePrefix);
+        }
 
-        final int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309);
-        final int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309);
-        final int maximumFractionDigits = fields.get("maximumFractionDigits", 340);
-        final int minimumFractionDigits = fields.get("minimumFractionDigits", 340);
-        // Tell ICU what we want, then ask it what we can have, and then
-        // set that in our Java object. This isn't RI-compatible, but then very little of our
-        // behavior in this area is, and it's not obvious how we can second-guess ICU (or tell
-        // it to just do exactly what we ask). We only need to do this with maximumIntegerDigits
-        // because ICU doesn't seem to have its own ideas about the other options.
-        icuDecimalFormat.setMaximumIntegerDigits(maximumIntegerDigits);
-        super.setMaximumIntegerDigits(icuDecimalFormat.getMaximumIntegerDigits());
+        String positiveSuffix = (String) fields.get("positiveSuffix", "");
+        if (!Objects.equals(positiveSuffix, icuDecimalFormat.getPositiveSuffix())) {
+            icuDecimalFormat.setPositiveSuffix(positiveSuffix);
+        }
 
-        setMinimumIntegerDigits(minimumIntegerDigits);
-        setMinimumFractionDigits(minimumFractionDigits);
-        setMaximumFractionDigits(maximumFractionDigits);
-        setParseBigDecimal(fields.get("parseBigDecimal", false));
+        String negativePrefix = (String) fields.get("negativePrefix", "-");
+        if (!Objects.equals(negativePrefix, icuDecimalFormat.getNegativePrefix())) {
+            icuDecimalFormat.setNegativePrefix(negativePrefix);
+        }
+
+        String negativeSuffix = (String) fields.get("negativeSuffix", "");
+        if (!Objects.equals(negativeSuffix, icuDecimalFormat.getNegativeSuffix())) {
+            icuDecimalFormat.setNegativeSuffix(negativeSuffix);
+        }
+
+        int multiplier = fields.get("multiplier", 1);
+        if (multiplier != icuDecimalFormat.getMultiplier()) {
+            icuDecimalFormat.setMultiplier(multiplier);
+        }
+
+        boolean groupingUsed = fields.get("groupingUsed", true);
+        if (groupingUsed != icuDecimalFormat.isGroupingUsed()) {
+            icuDecimalFormat.setGroupingUsed(groupingUsed);
+        }
+
+        int groupingSize = fields.get("groupingSize", (byte) 3);
+        if (groupingSize != icuDecimalFormat.getGroupingSize()) {
+            icuDecimalFormat.setGroupingSize(groupingSize);
+        }
+
+        boolean decimalSeparatorAlwaysShown = fields.get("decimalSeparatorAlwaysShown", false);
+        if (decimalSeparatorAlwaysShown != icuDecimalFormat.isDecimalSeparatorAlwaysShown()) {
+            icuDecimalFormat.setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown);
+        }
+
+        RoundingMode roundingMode =
+                (RoundingMode) fields.get("roundingMode", RoundingMode.HALF_EVEN);
+        if (convertRoundingMode(roundingMode) != icuDecimalFormat.getRoundingMode()) {
+            setRoundingMode(roundingMode);
+        }
+
+        int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309);
+        if (maximumIntegerDigits != icuDecimalFormat.getMaximumIntegerDigits()) {
+            icuDecimalFormat.setMaximumIntegerDigits(maximumIntegerDigits);
+        }
+
+        int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309);
+        if (minimumIntegerDigits != icuDecimalFormat.getMinimumIntegerDigits()) {
+            icuDecimalFormat.setMinimumIntegerDigits(minimumIntegerDigits);
+        }
+
+        int maximumFractionDigits = fields.get("maximumFractionDigits", 340);
+        if (maximumFractionDigits != icuDecimalFormat.getMaximumFractionDigits()) {
+            icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits);
+        }
+
+        int minimumFractionDigits = fields.get("minimumFractionDigits", 340);
+        if (minimumFractionDigits != icuDecimalFormat.getMinimumFractionDigits()) {
+            icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits);
+        }
+
+        boolean parseBigDecimal = fields.get("parseBigDecimal", true);
+        if (parseBigDecimal != icuDecimalFormat.isParseBigDecimal()) {
+            icuDecimalFormat.setParseBigDecimal(parseBigDecimal);
+        }
+
+        updateFieldsFromIcu();
 
         if (fields.get("serialVersionOnStream", 0) < 3) {
             setMaximumIntegerDigits(super.getMaximumIntegerDigits());
diff --git a/ojluni/src/main/java/java/text/DecimalFormatSymbols.java b/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
index 9e82738..2acb128 100644
--- a/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -757,6 +757,10 @@
         cachedIcuDFS.setDigit(digit);
         cachedIcuDFS.setDecimalSeparator(decimalSeparator);
         cachedIcuDFS.setGroupingSeparator(groupingSeparator);
+        // {@link #setGroupingSeparator(char)} should set grouping separator for currency, but
+        // ICU has a separate API setMonetaryGroupingSeparator. Need to call it explicitly here.
+        // http://b/38021063
+        cachedIcuDFS.setMonetaryGroupingSeparator(groupingSeparator);
         cachedIcuDFS.setPatternSeparator(patternSeparator);
         cachedIcuDFS.setPercent(percent);
         cachedIcuDFS.setMonetaryDecimalSeparator(monetarySeparator);
diff --git a/ojluni/src/main/java/java/util/regex/Matcher.java b/ojluni/src/main/java/java/util/regex/Matcher.java
index 382bbfd..156b8bd 100644
--- a/ojluni/src/main/java/java/util/regex/Matcher.java
+++ b/ojluni/src/main/java/java/util/regex/Matcher.java
@@ -124,8 +124,9 @@
             Matcher.class.getClassLoader(), getNativeFinalizer(), nativeSize());
 
     /**
-     * Holds the original CharSequence for {@link #reset} only. Any reference to the content after
-     * {@link #reset} can direct to {@link #input}.
+     * Holds the original CharSequence for use in {@link #reset}. {@link #input} is used during
+     * matching. Note that CharSequence is mutable while String is not, so reset can cause the input
+     * to match to change.
      */
     private CharSequence originalInput;
 
diff --git a/ojluni/src/main/native/Adler32.c b/ojluni/src/main/native/Adler32.c
index b62b111..11ef08d 100644
--- a/ojluni/src/main/native/Adler32.c
+++ b/ojluni/src/main/native/Adler32.c
@@ -27,7 +27,7 @@
  * Native method support for java.util.zip.Adler32
  */
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include "jni.h"
 #include "jni_util.h"
 #include "jlong.h"
diff --git a/ojluni/src/main/native/Bits.c b/ojluni/src/main/native/Bits.c
index 18e5e59..50caf36 100644
--- a/ojluni/src/main/native/Bits.c
+++ b/ojluni/src/main/native/Bits.c
@@ -31,7 +31,7 @@
 #include "jlong.h"
 #include <string.h>
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 /*
  * WARNING:
diff --git a/ojluni/src/main/native/Character.cpp b/ojluni/src/main/native/Character.cpp
index 6a82fde..666184f 100644
--- a/ojluni/src/main/native/Character.cpp
+++ b/ojluni/src/main/native/Character.cpp
@@ -20,7 +20,7 @@
 
 #include "jni.h"
 #include "jvm.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include "nativehelper/jni_macros.h"
 #include "unicode/uchar.h"
 #include "unicode/uscript.h"
diff --git a/ojluni/src/main/native/Console_md.c b/ojluni/src/main/native/Console_md.c
index 73b4a97..13437be 100644
--- a/ojluni/src/main/native/Console_md.c
+++ b/ojluni/src/main/native/Console_md.c
@@ -31,7 +31,7 @@
 #include <unistd.h>
 #include <termios.h>
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_java_io_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/DatagramChannelImpl.c b/ojluni/src/main/native/DatagramChannelImpl.c
index 10d7170..925064f 100644
--- a/ojluni/src/main/native/DatagramChannelImpl.c
+++ b/ojluni/src/main/native/DatagramChannelImpl.c
@@ -45,7 +45,7 @@
 #include "nio_util.h"
 
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_sun_nio_ch_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/DatagramDispatcher.c b/ojluni/src/main/native/DatagramDispatcher.c
index 3143baf..36cc6cf 100644
--- a/ojluni/src/main/native/DatagramDispatcher.c
+++ b/ojluni/src/main/native/DatagramDispatcher.c
@@ -42,7 +42,7 @@
 #include <limits.h>
 
 #include "nio.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_sun_nio_ch_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/Double.c b/ojluni/src/main/native/Double.c
index 942f8c8..8382b88 100644
--- a/ojluni/src/main/native/Double.c
+++ b/ojluni/src/main/native/Double.c
@@ -28,7 +28,7 @@
 #include "jlong.h"
 #include "jvm.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/FileChannelImpl.c b/ojluni/src/main/native/FileChannelImpl.c
index 692a64c..5b428e9 100644
--- a/ojluni/src/main/native/FileChannelImpl.c
+++ b/ojluni/src/main/native/FileChannelImpl.c
@@ -35,7 +35,7 @@
 #include "nio.h"
 #include "nio_util.h"
 #include <dlfcn.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/FileDescriptor_md.c b/ojluni/src/main/native/FileDescriptor_md.c
index 17e63aa..0404263 100644
--- a/ojluni/src/main/native/FileDescriptor_md.c
+++ b/ojluni/src/main/native/FileDescriptor_md.c
@@ -29,7 +29,7 @@
 #include "jni_util.h"
 #include "jvm.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/FileDispatcherImpl.c b/ojluni/src/main/native/FileDispatcherImpl.c
index a723bfb..5a49a60 100644
--- a/ojluni/src/main/native/FileDispatcherImpl.c
+++ b/ojluni/src/main/native/FileDispatcherImpl.c
@@ -40,7 +40,7 @@
 #endif
 #include "nio.h"
 #include "nio_util.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/FileInputStream.c b/ojluni/src/main/native/FileInputStream.c
index a5a54f5..2418c5d 100644
--- a/ojluni/src/main/native/FileInputStream.c
+++ b/ojluni/src/main/native/FileInputStream.c
@@ -41,7 +41,7 @@
 #include <limits.h>
 
 #include "io_util_md.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/FileKey.c b/ojluni/src/main/native/FileKey.c
index 99df82c..b28fb56 100644
--- a/ojluni/src/main/native/FileKey.c
+++ b/ojluni/src/main/native/FileKey.c
@@ -28,7 +28,7 @@
 #include "jvm.h"
 #include "nio.h"
 #include "nio_util.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/FileOutputStream_md.c b/ojluni/src/main/native/FileOutputStream_md.c
index 615627a..73218d4 100644
--- a/ojluni/src/main/native/FileOutputStream_md.c
+++ b/ojluni/src/main/native/FileOutputStream_md.c
@@ -31,7 +31,7 @@
 #include "io_util_md.h"
 
 #include <fcntl.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/FileSystemPreferences.c b/ojluni/src/main/native/FileSystemPreferences.c
index 9f35dd5..8ab516a 100644
--- a/ojluni/src/main/native/FileSystemPreferences.c
+++ b/ojluni/src/main/native/FileSystemPreferences.c
@@ -35,7 +35,7 @@
 #include <utime.h>
 #include "jni_util.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_java_util_prefs_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/Float.c b/ojluni/src/main/native/Float.c
index 398914a..956048d 100644
--- a/ojluni/src/main/native/Float.c
+++ b/ojluni/src/main/native/Float.c
@@ -26,7 +26,7 @@
 #include "jni.h"
 #include "jvm.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/IOUtil.c b/ojluni/src/main/native/IOUtil.c
index 390c0e6..05949da 100644
--- a/ojluni/src/main/native/IOUtil.c
+++ b/ojluni/src/main/native/IOUtil.c
@@ -34,7 +34,7 @@
 #include "java_lang_Integer.h"
 #include "nio.h"
 #include "nio_util.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 
 #define NATIVE_METHOD(className, functionName, signature) \
diff --git a/ojluni/src/main/native/Inet4Address.c b/ojluni/src/main/native/Inet4Address.c
index 5c7df40..bccbe18 100644
--- a/ojluni/src/main/native/Inet4Address.c
+++ b/ojluni/src/main/native/Inet4Address.c
@@ -26,7 +26,7 @@
 #include <string.h>
 
 #include "net_util.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/Inet6Address.c b/ojluni/src/main/native/Inet6Address.c
index 6f0ac57..13c38ce 100644
--- a/ojluni/src/main/native/Inet6Address.c
+++ b/ojluni/src/main/native/Inet6Address.c
@@ -26,7 +26,7 @@
 #include <string.h>
 
 #include "net_util.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/InetAddress.c b/ojluni/src/main/native/InetAddress.c
index 0f0fefe..b3feca7 100644
--- a/ojluni/src/main/native/InetAddress.c
+++ b/ojluni/src/main/native/InetAddress.c
@@ -26,7 +26,7 @@
 #include <string.h>
 
 #include "net_util.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
@@ -41,6 +41,7 @@
 jfieldID iac_addressID;
 jfieldID iac_familyID;
 jfieldID iac_hostNameID;
+jfieldID iac_origHostNameID;
 
 static void InetAddress_init(JNIEnv *env) {
     jclass c = (*env)->FindClass(env,"java/net/InetAddress");
@@ -59,6 +60,8 @@
     CHECK_NULL(iac_familyID);
     iac_hostNameID = (*env)->GetFieldID(env, iac_class, "hostName", "Ljava/lang/String;");
     CHECK_NULL(iac_hostNameID);
+    iac_origHostNameID = (*env)->GetFieldID(env, iac_class, "originalHostName", "Ljava/lang/String;");
+    CHECK_NULL(iac_origHostNameID);
 }
 
 void register_java_net_InetAddress(JNIEnv* env) {
diff --git a/ojluni/src/main/native/MappedByteBuffer.c b/ojluni/src/main/native/MappedByteBuffer.c
index 3dbb96e..a5b0b04 100644
--- a/ojluni/src/main/native/MappedByteBuffer.c
+++ b/ojluni/src/main/native/MappedByteBuffer.c
@@ -31,7 +31,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_java_nio_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/Math.c b/ojluni/src/main/native/Math.c
index c5482ba..3191ade 100644
--- a/ojluni/src/main/native/Math.c
+++ b/ojluni/src/main/native/Math.c
@@ -19,7 +19,7 @@
  */
 
 #include "jni.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include "nativehelper/jni_macros.h"
 
 #include <stdlib.h>
diff --git a/ojluni/src/main/native/NativeThread.c b/ojluni/src/main/native/NativeThread.c
index 9147bc3..3a1c5c1 100644
--- a/ojluni/src/main/native/NativeThread.c
+++ b/ojluni/src/main/native/NativeThread.c
@@ -30,7 +30,7 @@
 #include "jvm.h"
 #include "jlong.h"
 #include "nio_util.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #ifdef __linux__
   #include <pthread.h>
diff --git a/ojluni/src/main/native/Net.c b/ojluni/src/main/native/Net.c
index e2962e6..01ea3f2 100644
--- a/ojluni/src/main/native/Net.c
+++ b/ojluni/src/main/native/Net.c
@@ -55,7 +55,7 @@
   #endif
 #endif
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_sun_nio_ch_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/ObjectInputStream.c b/ojluni/src/main/native/ObjectInputStream.c
index 95eeec4..6f65dca 100644
--- a/ojluni/src/main/native/ObjectInputStream.c
+++ b/ojluni/src/main/native/ObjectInputStream.c
@@ -28,7 +28,7 @@
 #include "jni_util.h"
 #include "jlong.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_java_io_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/ObjectOutputStream.c b/ojluni/src/main/native/ObjectOutputStream.c
index 25ee3bf..169a83f 100644
--- a/ojluni/src/main/native/ObjectOutputStream.c
+++ b/ojluni/src/main/native/ObjectOutputStream.c
@@ -28,7 +28,7 @@
 #include "jni_util.h"
 #include "jlong.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_java_io_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/ObjectStreamClass.c b/ojluni/src/main/native/ObjectStreamClass.c
index fc33fb7..95cd4f0 100644
--- a/ojluni/src/main/native/ObjectStreamClass.c
+++ b/ojluni/src/main/native/ObjectStreamClass.c
@@ -26,7 +26,7 @@
 #include "jni.h"
 #include "jvm.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/ProcessEnvironment_md.c b/ojluni/src/main/native/ProcessEnvironment_md.c
index 65003db..a59410b 100644
--- a/ojluni/src/main/native/ProcessEnvironment_md.c
+++ b/ojluni/src/main/native/ProcessEnvironment_md.c
@@ -32,7 +32,7 @@
 #include <crt_externs.h>
 #define environ (*_NSGetEnviron())
 #endif
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/Register.cpp b/ojluni/src/main/native/Register.cpp
index 588eedb..15ac1e4 100644
--- a/ojluni/src/main/native/Register.cpp
+++ b/ojluni/src/main/native/Register.cpp
@@ -29,8 +29,8 @@
 
 #include <log/log.h>
 
-#include "JniConstants.h"
-#include "ScopedLocalFrame.h"
+#include <nativehelper/JniConstants.h>
+#include <nativehelper/ScopedLocalFrame.h>
 
 extern "C" {
 
diff --git a/ojluni/src/main/native/Runtime.c b/ojluni/src/main/native/Runtime.c
index 61de356..f070249 100644
--- a/ojluni/src/main/native/Runtime.c
+++ b/ojluni/src/main/native/Runtime.c
@@ -39,7 +39,7 @@
 #include "jni_util.h"
 #include "jvm.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #include "nativehelper/jni_macros.h"
 
diff --git a/ojluni/src/main/native/ServerSocketChannelImpl.c b/ojluni/src/main/native/ServerSocketChannelImpl.c
index 63dd4ea..679811f 100644
--- a/ojluni/src/main/native/ServerSocketChannelImpl.c
+++ b/ojluni/src/main/native/ServerSocketChannelImpl.c
@@ -45,7 +45,7 @@
 #include "nio.h"
 #include "nio_util.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 
 #define NATIVE_METHOD(className, functionName, signature) \
diff --git a/ojluni/src/main/native/SocketChannelImpl.c b/ojluni/src/main/native/SocketChannelImpl.c
index 8cd3b85..9429165 100644
--- a/ojluni/src/main/native/SocketChannelImpl.c
+++ b/ojluni/src/main/native/SocketChannelImpl.c
@@ -43,7 +43,7 @@
 #include "nio_util.h"
 #include "nio.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(Java_sun_nio_ch_ ## className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/SocketInputStream.c b/ojluni/src/main/native/SocketInputStream.c
index 7be77a7..dcea334 100644
--- a/ojluni/src/main/native/SocketInputStream.c
+++ b/ojluni/src/main/native/SocketInputStream.c
@@ -33,7 +33,7 @@
 #include "jni_util.h"
 #include "net_util.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/SocketOutputStream.c b/ojluni/src/main/native/SocketOutputStream.c
index 5fcc7c3..bc3522b 100644
--- a/ojluni/src/main/native/SocketOutputStream.c
+++ b/ojluni/src/main/native/SocketOutputStream.c
@@ -33,7 +33,7 @@
 #include "jvm.h"
 #include "net_util.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/StrictMath.c b/ojluni/src/main/native/StrictMath.c
index c1efc50..7f9bbeb 100644
--- a/ojluni/src/main/native/StrictMath.c
+++ b/ojluni/src/main/native/StrictMath.c
@@ -26,7 +26,7 @@
 #include "jni.h"
 #include "../../external/fdlibm/fdlibm.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/String.c b/ojluni/src/main/native/String.c
index 80dc90b..011089d 100644
--- a/ojluni/src/main/native/String.c
+++ b/ojluni/src/main/native/String.c
@@ -24,7 +24,7 @@
  */
 
 #include "jvm.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/System.c b/ojluni/src/main/native/System.c
index 22c4d52..6cfee92 100644
--- a/ojluni/src/main/native/System.c
+++ b/ojluni/src/main/native/System.c
@@ -37,7 +37,7 @@
 
 #include "openssl/opensslv.h"
 #include "zlib.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #if defined(__ANDROID__)
 void android_get_LD_LIBRARY_PATH(char*, size_t);
 #endif
diff --git a/ojluni/src/main/native/Thread.c b/ojluni/src/main/native/Thread.c
index c099288..83b448f 100644
--- a/ojluni/src/main/native/Thread.c
+++ b/ojluni/src/main/native/Thread.c
@@ -36,7 +36,7 @@
 #define OBJ "Ljava/lang/Object;"
 #define STE "Ljava/lang/StackTraceElement;"
 #define STR "Ljava/lang/String;"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
 
diff --git a/ojluni/src/main/native/Throwable.c b/ojluni/src/main/native/Throwable.c
index b7868e8..805c80a 100644
--- a/ojluni/src/main/native/Throwable.c
+++ b/ojluni/src/main/native/Throwable.c
@@ -35,7 +35,7 @@
 #include "jni.h"
 #include "jvm.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/UNIXProcess_md.c b/ojluni/src/main/native/UNIXProcess_md.c
index 3c03221..f944c31 100644
--- a/ojluni/src/main/native/UNIXProcess_md.c
+++ b/ojluni/src/main/native/UNIXProcess_md.c
@@ -31,7 +31,7 @@
 #include "jvm_md.h"
 #include "jni_util.h"
 #include "io_util.h"
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #define NATIVE_METHOD(className, functionName, signature) \
 { #functionName, signature, (void*)(className ## _ ## functionName) }
diff --git a/ojluni/src/main/native/UnixFileSystem_md.c b/ojluni/src/main/native/UnixFileSystem_md.c
index 61f907c..0c53f09 100644
--- a/ojluni/src/main/native/UnixFileSystem_md.c
+++ b/ojluni/src/main/native/UnixFileSystem_md.c
@@ -42,7 +42,7 @@
 #include "java_io_FileSystem.h"
 #include "java_io_UnixFileSystem.h"
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 
 #if defined(_ALLBSD_SOURCE)
 #define dirent64 dirent
diff --git a/ojluni/src/main/native/java_util_zip_CRC32.c b/ojluni/src/main/native/java_util_zip_CRC32.c
index 4c2beae..cec99de 100644
--- a/ojluni/src/main/native/java_util_zip_CRC32.c
+++ b/ojluni/src/main/native/java_util_zip_CRC32.c
@@ -27,7 +27,7 @@
  * Native method support for java.util.zip.CRC32
  */
 
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include "jni.h"
 #include "jni_util.h"
 #include <zlib.h>
diff --git a/ojluni/src/main/native/java_util_zip_Deflater.c b/ojluni/src/main/native/java_util_zip_Deflater.c
index 8834171..9ee0326 100644
--- a/ojluni/src/main/native/java_util_zip_Deflater.c
+++ b/ojluni/src/main/native/java_util_zip_Deflater.c
@@ -29,7 +29,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include "jlong.h"
 #include "jni.h"
 #include "jni_util.h"
diff --git a/ojluni/src/main/native/java_util_zip_Inflater.c b/ojluni/src/main/native/java_util_zip_Inflater.c
index 16241f5..c4c24f0 100644
--- a/ojluni/src/main/native/java_util_zip_Inflater.c
+++ b/ojluni/src/main/native/java_util_zip_Inflater.c
@@ -31,7 +31,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include "jlong.h"
 #include "jni.h"
 #include "jvm.h"
diff --git a/ojluni/src/main/native/java_util_zip_ZipFile.c b/ojluni/src/main/native/java_util_zip_ZipFile.c
index d9d7a51..8444c42 100644
--- a/ojluni/src/main/native/java_util_zip_ZipFile.c
+++ b/ojluni/src/main/native/java_util_zip_ZipFile.c
@@ -33,7 +33,7 @@
 #include <errno.h>
 #include <ctype.h>
 #include <assert.h>
-#include "JNIHelp.h"
+#include <nativehelper/JNIHelp.h>
 #include "jlong.h"
 #include "jvm.h"
 #include "jni.h"
diff --git a/ojluni/src/main/native/linux_close.cpp b/ojluni/src/main/native/linux_close.cpp
index 6f88c93..e100035 100644
--- a/ojluni/src/main/native/linux_close.cpp
+++ b/ojluni/src/main/native/linux_close.cpp
@@ -38,7 +38,7 @@
 #include <sys/poll.h>
 
 
-#include "AsynchronousCloseMonitor.h"
+#include <nativehelper/AsynchronousCloseMonitor.h>
 
 extern "C" {
 
diff --git a/ojluni/src/main/native/net_util.c b/ojluni/src/main/native/net_util.c
index af6a893..006192e 100644
--- a/ojluni/src/main/native/net_util.c
+++ b/ojluni/src/main/native/net_util.c
@@ -177,6 +177,7 @@
     // Android-changed: initInetAddrs(env);
     holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
     (*env)->SetObjectField(env, holder, iac_hostNameID, host);
+    (*env)->SetObjectField(env, holder, iac_origHostNameID, host);
 }
 
 int getInetAddress_addr(JNIEnv *env, jobject iaObj) {
diff --git a/ojluni/src/main/native/net_util.h b/ojluni/src/main/native/net_util.h
index afd94ed..b7099bb 100644
--- a/ojluni/src/main/native/net_util.h
+++ b/ojluni/src/main/native/net_util.h
@@ -53,6 +53,7 @@
 extern jfieldID iac_addressID;
 extern jfieldID iac_familyID;
 extern jfieldID iac_hostNameID;
+extern jfieldID iac_origHostNameID;
 extern jfieldID ia_preferIPv6AddressID;
 
 /** (Inet6Address accessors)
diff --git a/ojluni/src/main/native/socket_tagger_util.cpp b/ojluni/src/main/native/socket_tagger_util.cpp
index b03d0aa..611b92e 100644
--- a/ojluni/src/main/native/socket_tagger_util.cpp
+++ b/ojluni/src/main/native/socket_tagger_util.cpp
@@ -18,8 +18,8 @@
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "JNIHelp.h"
-#include "JniConstants.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JniConstants.h>
 
 extern "C" {
 
diff --git a/ojluni/src/test/java/time/test/java/util/TestFormatter.java b/ojluni/src/test/java/time/test/java/util/TestFormatter.java
index 71d12f4..7b405ca 100644
--- a/ojluni/src/test/java/time/test/java/util/TestFormatter.java
+++ b/ojluni/src/test/java/time/test/java/util/TestFormatter.java
@@ -211,8 +211,8 @@
 
     private String toZoneOffsetStr(String expected) {
         // Android-changed: Android Matcher doesn't support named groups. Also GMT/Z is formatted as
-        // "GMT+00:00".
-        return expected.replaceAll("GMT(?:\\+00:00)|UTC|UT", "Z")
+        // "GMT+00:00" or "GMT".
+        return expected.replaceAll("GMT(?:\\+00:00)?(?=])|UTC|UT", "Z")
                 .replaceAll("(?:GMT|UTC)([+\\-]?[0-9]{2}:[0-9]{2})", "$1");
     }
 
diff --git a/support/src/test/java/libcore/java/security/CpuFeatures.java b/support/src/test/java/libcore/java/security/CpuFeatures.java
index 319056a..28b4321b 100644
--- a/support/src/test/java/libcore/java/security/CpuFeatures.java
+++ b/support/src/test/java/libcore/java/security/CpuFeatures.java
@@ -47,6 +47,7 @@
         try {
             Class<?> nativeCrypto = Class.forName("com.android.org.conscrypt.NativeCrypto");
             Method EVP_has_aes_hardware = nativeCrypto.getDeclaredMethod("EVP_has_aes_hardware");
+            EVP_has_aes_hardware.setAccessible(true);
             return ((Integer) EVP_has_aes_hardware.invoke(null)) == 1;
         } catch (ClassNotFoundException | NoSuchMethodException | SecurityException
                 | IllegalAccessException | IllegalArgumentException ignored) {
diff --git a/tools/upstream/Android.mk b/tools/upstream/Android.mk
new file mode 100644
index 0000000..bc56f5d
--- /dev/null
+++ b/tools/upstream/Android.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+##############################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcore-compare-upstreams
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
+LOCAL_JAR_MANIFEST := src/main/libcore-compare-upstreams.mf
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+##############################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcore-copy-upstream-files
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
+LOCAL_JAR_MANIFEST := src/main/libcore-copy-upstream-files.mf
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/upstream/oj_upstream_comparison.py b/tools/upstream/oj_upstream_comparison.py
deleted file mode 100755
index 76d63aa..0000000
--- a/tools/upstream/oj_upstream_comparison.py
+++ /dev/null
@@ -1,207 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Helps compare openjdk_java_files contents against upstream file contents.
-
-Outputs a tab-separated table comparing each openjdk_java_files entry
-against OpenJDK upstreams. This can help verify updates to later upstreams
-or focus attention towards files that may have been missed in a previous
-update (http://b/36461944) or are otherwise surprising (http://b/36429512).
-
- - Identifies each file as identical to, different from or missing from
-   each upstream; diffs are not produced.
- - Optionally, copies all openjdk_java_files from the default upstream
-   (eg. OpenJDK8u121-b13) to a new directory, for easy directory comparison
-   using e.g. kdiff3, which allows inspecting detailed diffs.
- - The ANDROID_BUILD_TOP environment variable must be set to point to the
-   AOSP root directory (parent of libcore).
- - Run with -h command line argument to get usage instructions.
-
-To check out upstreams OpenJDK 7u40, 8u60 and 8u121-b13, run:
-
-mkdir openjdk
-cd openjdk
-hg clone http://hg.openjdk.java.net/jdk7u/jdk7u40/ 7u40
-(cd !$ ; sh get_source.sh)
-hg clone http://hg.openjdk.java.net/jdk8u/jdk8u 8u121-b13
-(cd !$ ; hg update -r jdk8u121-b13 && sh get_source.sh)
-hg clone http://hg.openjdk.java.net/jdk8u/jdk8u60/ 8u60
-(cd !$ ; sh get_source.sh)
-
-The newly created openjdk directory is then a suitable argument for the
---upstream_root parameter.
-"""
-
-import argparse
-import csv
-import filecmp
-import os
-import re
-import shutil
-import sys
-
-def rel_paths_from_makefile(build_top):
-    """Returns the list of relative paths to .java files parsed from openjdk_java_files.mk"""
-    list_file = os.path.join(build_top, "libcore", "openjdk_java_files.mk")
-
-    result = []
-    with open(list_file, "r") as f:
-        for line in f:
-            match = re.match("\s+ojluni/src/main/java/(.+\.java)\s*\\\s*", line)
-            if match:
-                path = match.group(1)
-                # convert / to the appropriate separator (e.g. \ on Windows), just in case
-                path = os.path.normpath(path)
-                result.append(path)
-    return result
-
-def ojluni_path(build_top, rel_path):
-    """The full path of the file at the given rel_path in ojluni"""
-    return os.path.join(build_top, "libcore", "ojluni", "src", "main", "java", rel_path)
-
-def upstream_path(upstream_root, upstream, rel_path):
-    """The full path of the file at the given rel_path in the given upstream"""
-    source_dirs = [
-        "jdk/src/share/classes",
-        "jdk/src/solaris/classes"
-    ]
-    for source_dir in source_dirs:
-        source_dir = os.path.normpath(source_dir)
-        result = os.path.join(upstream_root, upstream, source_dir, rel_path)
-        if os.path.exists(result):
-            return result
-    return None
-
-# 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 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.
-    """
-    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
-        # a[:end_a-1] and b[:i].
-        # We now calculate cur_cost[end_b] as the edit distance between
-        # a[:end_a] and b[:end_b]
-        cur_cost = [end_a]
-        for end_b in range(1, len(b) + 1):
-            c = min(
-                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):
-    """
-    Prints tab-separated values comparing ojluni files vs. each
-    upstream, for each of the rel_paths, suitable for human
-    analysis in a spreadsheet.
-    This includes whether the corresponding upstream file is
-    missing, identical, or by how many lines it differs, and
-    a guess as to the correct upstream based on minimal line
-    difference (ties broken in favor of upstreams that occur
-    earlier in the list).
-    """
-    writer = csv.writer(out_file, delimiter='\t')
-    writer.writerow(["rel_path", "guessed_upstream"] + upstreams)
-    for rel_path in rel_paths:
-        ojluni_file = ojluni_path(build_top, rel_path)
-        upstream_comparisons = []
-        best_distance = sys.maxint
-        guessed_upstream = ""
-        for upstream in upstreams:
-            upstream_file = upstream_path(upstream_root, upstream, rel_path)
-            if upstream_file is None:
-                upstream_comparison = "missing"
-            else:
-                if filecmp.cmp(upstream_file, ojluni_file, shallow=False):
-                    distance = 0
-                    upstream_comparison = "identical"
-                else:
-                    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)
-
-def copy_files(rel_paths, upstream_root, upstream, output_dir):
-    """Copies files at the given rel_paths from upstream to output_dir"""
-    for rel_path in rel_paths:
-        upstream_file = upstream_path(upstream_root, upstream, rel_path)
-        if upstream_file is not None:
-            out_file = os.path.join(output_dir, rel_path)
-            out_dir = os.path.dirname(out_file)
-            if not os.path.exists(out_dir):
-                os.makedirs(out_dir)
-            shutil.copyfile(upstream_file, out_file)
-
-def main():
-    parser = argparse.ArgumentParser(
-    description="Check openjdk_java_files contents against upstream file contents.")
-    parser.add_argument("--upstream_root",
-        help="Path below where upstream sources are checked out. This should be a "
-            "directory with one child directory for each upstream (select the "
-            "upstreams to compare against via --upstreams).",
-        required=True,)
-    parser.add_argument("--upstreams", 
-        default="8u121-b13,8u60,7u40",
-        help="Comma separated list of subdirectory names of --upstream_root that "
-            "each hold one upstream.")
-    parser.add_argument("--output_dir",
-        help="(optional) path where default upstream sources should be copied to; "
-            "this path must not yet exist and will be created. "
-            "The default upstream is the one that occurs first in --upstreams.")
-    parser.add_argument("--build_top",
-        default=os.environ.get('ANDROID_BUILD_TOP'),
-        help="Path where Android sources are checked out (defaults to $ANDROID_BUILD_TOP).")
-    args = parser.parse_args()
-    if args.output_dir is not None and os.path.exists(args.output_dir):
-        raise Exception("Output dir already exists: " + args.output_dir)
-
-    upstreams = [upstream.strip() for upstream in args.upstreams.split(',')]
-    default_upstream = upstreams[0]
-    for upstream in upstreams:
-        upstream_path = os.path.join(args.upstream_root, upstream)
-        if not os.path.exists(upstream_path):
-            raise Exception("Upstream not found: " + upstream_path)
-
-    rel_paths = rel_paths_from_makefile(args.build_top)
-
-    compare_to_upstreams_and_save(
-        sys.stdout, args.build_top, args.upstream_root, upstreams, rel_paths)
-
-    if args.output_dir is not None:
-        copy_files(rel_paths, args.upstream_root, default_upstream, args.output_dir)
-
-if __name__ == '__main__':
-    main()
diff --git a/tools/upstream/src/main/java/libcore/CompareUpstreams.java b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
new file mode 100644
index 0000000..bd80b82
--- /dev/null
+++ b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore;
+
+import java.io.*;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helps compare openjdk_java_files contents against upstream file contents.
+ *
+ * Outputs a tab-separated table comparing each openjdk_java_files entry
+ * against OpenJDK upstreams. This can help verify updates to later upstreams
+ * or focus attention towards files that may have been missed in a previous
+ * update (http://b/36461944) or are otherwise surprising (http://b/36429512).
+ *
+ * - Identifies each file as identical to, different from or missing from
+ * each upstream; diffs are not produced.
+ * - Optionally, copies all openjdk_java_files from the default upstream
+ * (eg. OpenJDK8u121-b13) to a new directory, for easy directory comparison
+ * using e.g. kdiff3, which allows inspecting detailed diffs.
+ * - The ANDROID_BUILD_TOP environment variable must be set to point to the
+ * AOSP root directory (parent of libcore).
+ *
+ *  To check out upstreams OpenJDK 7u40, 8u60 and 8u121-b13, run:
+ *
+ *  mkdir ~/openjdk
+ *  cd ~/openjdk
+ *  export OPENJDK_HOME=$PWD
+ *  hg clone http://hg.openjdk.java.net/jdk7u/jdk7u40/ 7u40
+ *  (cd !$ ; sh get_source.sh)
+ *  hg clone http://hg.openjdk.java.net/jdk8u/jdk8u 8u121-b13
+ *  (cd !$ ; hg update -r jdk8u121-b13 && sh get_source.sh)
+ *  hg clone http://hg.openjdk.java.net/jdk8u/jdk8u60/ 8u60
+ *  (cd !$ ; sh get_source.sh)
+ *
+ *  To get the 9b113+ upstream, follow the instructions from the commit
+ *  message of AOSP libcore commit 29957558cf0db700bfaae360a80c42dc3871d0e5
+ *  at https://android-review.googlesource.com/c/304056/
+ */
+public class CompareUpstreams {
+
+    private final StandardRepositories standardRepositories;
+
+    public CompareUpstreams(StandardRepositories standardRepositories) {
+        this.standardRepositories = Objects.requireNonNull(standardRepositories);
+    }
+
+    private static Map<String, Integer> androidChangedComments(List<String> lines) {
+        List<String> problems = new ArrayList<>();
+        Map<String, Integer> result = new LinkedHashMap<>();
+        Pattern pattern = Pattern.compile(
+                "// (BEGIN |END |)Android-((?:changed|added|removed|note)(?:: )?.*)$");
+        for (String line : lines) {
+            Matcher matcher = pattern.matcher(line);
+            if (matcher.find()) {
+                String type = matcher.group(1);
+                if (type.equals("END")) {
+                    continue;
+                }
+                String match = matcher.group(2);
+                if (match.isEmpty()) {
+                    match = "[empty comment]";
+                }
+                Integer oldCount = result.get(match);
+                if (oldCount == null) {
+                    oldCount = 0;
+                }
+                result.put(match, oldCount + 1);
+            } else if (line.contains("Android-")) {
+                problems.add(line);
+            }
+        }
+        if (!problems.isEmpty()) {
+            throw new IllegalArgumentException(problems.toString());
+        }
+        return result;
+    }
+
+    private static String androidChangedCommentsSummary(List<String> lines) {
+        Map<String, Integer> map = androidChangedComments(lines);
+        List<String> comments = new ArrayList<>(map.keySet());
+        Collections.sort(comments, Comparator.comparing(map::get).reversed());
+        List<String> result = new ArrayList<>();
+        for (String comment : comments) {
+            int count = map.get(comment);
+            if (count == 1) {
+                result.add(comment);
+            } else {
+                result.add(comment + " (x" + count + ")");
+            }
+        }
+        return escapeTsv(String.join("\n", result));
+    }
+
+    /**
+     * Computes the edit distance of 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.
+     */
+    private <T> int editDistance(List<T> a, List<T> b) {
+        int numB = b.size();
+        int[] prevCost = new int[numB + 1];
+        for (int i = 0; i <= numB; i++) {
+            prevCost[i] = i;
+        }
+        int[] curCost = new int[numB + 1];
+        for (int endA = 1; endA <= a.size(); endA++) {
+            // For each valid index i, prevCost[i] is the edit distance between
+            // a.subList(0, endA-1) and b.sublist(0, i).
+            // We now calculate curCost[end_b] as the edit distance between
+            // a.subList(0, endA) and b.subList(0, endB)
+            curCost[0] = endA;
+            for (int endB = 1; endB <= numB; endB++) {
+                boolean endsMatch = a.get(endA - 1).equals(b.get(endB - 1));
+                curCost[endB] = min(
+                        curCost[endB - 1] + 1, // append item from b
+                        prevCost[endB] + 1, // append item from a
+                        prevCost[endB - 1] + (endsMatch ? 0 : 1)); // match or replace item
+            }
+            int[] tmp = curCost;
+            curCost = prevCost;
+            prevCost = tmp;
+        }
+        return prevCost[numB];
+    }
+
+    private static int min(int a, int b, int c) {
+        if (a < b) {
+            return a < c ? a : c;
+        } else {
+            return b < c ? b : c;
+        }
+    }
+
+    private static String escapeTsv(String value) {
+        if (value.contains("\t")) {
+            throw new IllegalArgumentException(value); // tsv doesn't support escaping tabs
+        }
+        return "\"" + value.replace("\"", "\"\"") + "\"";
+    }
+
+    private static void printTsv(PrintStream out, List<String> values) {
+        out.println(String.join("\t", values));
+    }
+
+    /**
+     * Prints tab-separated values comparing ojluni files vs. each
+     * upstream, for each of the rel_paths, suitable for human
+     * analysis in a spreadsheet.
+     * This includes whether the corresponding upstream file is
+     * missing, identical, or by how many lines it differs, and
+     * a guess as to the correct upstream based on minimal line
+     * difference (ties broken in favor of upstreams that occur
+     * earlier in the list).
+     */
+    private void run(PrintStream out, List<Path> relPaths) throws IOException {
+        // upstreams are in decreasing order of preference
+        List<String> headers = new ArrayList<>();
+        headers.addAll(Arrays.asList(
+                "rel_path", "expected_upstream", "guessed_upstream", "changes", "vs. expected"));
+        for (Repository upstream : standardRepositories.historicUpstreams()) {
+            headers.add(upstream.name());
+        }
+        headers.add("diff");
+        printTsv(out, headers);
+        for (Path relPath : relPaths) {
+            Repository expectedUpstream = standardRepositories.currentUpstream(relPath);
+            out.print(relPath + "\t");
+            Path ojluniFile = standardRepositories.ojluni().absolutePath(relPath);
+            List<String> linesB = Util.readLines(ojluniFile);
+            int bestDistance = Integer.MAX_VALUE;
+            Repository guessedUpstream = null;
+            List<Repository> upstreams = new ArrayList<>();
+            upstreams.add(expectedUpstream);
+            upstreams.addAll(standardRepositories.historicUpstreams());
+            List<String> comparisons = new ArrayList<>(upstreams.size());
+            for (Repository upstream : upstreams) {
+                final String comparison;
+                Path upstreamFile = upstream.absolutePath(relPath);
+                if (upstreamFile == null) {
+                    comparison = "missing";
+                } else {
+                    List<String> linesA = Util.readLines(upstreamFile);
+                    int distance = editDistance(linesA, linesB);
+                    if (distance == 0) {
+                        comparison = "identical";
+                    } else {
+                        double percentDifferent = 100.0 * distance / Math
+                                .max(linesA.size(), linesB.size());
+                        comparison = String
+                                .format(Locale.US, "%.1f%% different (%d lines)", percentDifferent,
+                                        distance);
+                    }
+                    if (distance < bestDistance) {
+                        bestDistance = distance;
+                        guessedUpstream = upstream;
+                    }
+                }
+                comparisons.add(comparison);
+            }
+            String changedCommentsSummary = androidChangedCommentsSummary(linesB);
+
+            String diffCommand = "";
+            if (!comparisons.get(0).equals("identical")) {
+                Path expectedUpstreamPath = expectedUpstream.pathFromRepository(relPath);
+                if (expectedUpstreamPath != null) {
+                    diffCommand = String.format(Locale.US, "meld \"%s\" \"%s\"",
+                            "${ANDROID_BUILD_TOP}/libcore/"
+                                    + standardRepositories.ojluni().pathFromRepository(relPath),
+                            "${OJLUNI_UPSTREAMS}/" + expectedUpstream.name() + "/" + relPath);
+                            //"${OPENJDK_HOME}/" + expectedUpstreamPath;
+                } else {
+                    diffCommand = "FILE MISSING";
+                }
+            }
+            List<String> values = new ArrayList<>();
+            values.add(expectedUpstream.name());
+            values.add(guessedUpstream == null ? "" : guessedUpstream.name());
+            values.add(changedCommentsSummary);
+            values.addAll(comparisons);
+            values.add(diffCommand);
+            printTsv(out, values);
+        }
+    }
+
+    public void run() throws IOException {
+        List<Path> relPaths = standardRepositories.ojluni().loadRelPathsFromMakefile();
+        run(System.out, relPaths);
+    }
+
+    public static void main(String[] args) throws IOException {
+        StandardRepositories standardRepositories = StandardRepositories.fromEnv();
+        CompareUpstreams action = new CompareUpstreams(standardRepositories);
+        action.run();
+    }
+}
diff --git a/tools/upstream/src/main/java/libcore/CopyUpstreamFiles.java b/tools/upstream/src/main/java/libcore/CopyUpstreamFiles.java
new file mode 100644
index 0000000..007914f
--- /dev/null
+++ b/tools/upstream/src/main/java/libcore/CopyUpstreamFiles.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public class CopyUpstreamFiles {
+
+    private final StandardRepositories standardRepositories;
+    private final Path outputDir;
+
+    private CopyUpstreamFiles(StandardRepositories standardRepositories, Path outputDir) {
+        this.standardRepositories = Objects.requireNonNull(standardRepositories);
+        this.outputDir = Objects.requireNonNull(outputDir);
+    }
+
+    public void run() throws IOException {
+        List<Path> relPaths = standardRepositories.ojluni().loadRelPathsFromMakefile();
+        if (outputDir.toFile().exists()) {
+            throw new IOException(outputDir + " already exists");
+        } else {
+            boolean success = outputDir.toFile().mkdir();
+            if (!success) {
+                throw new IOException("Failed to create directory " + outputDir);
+            }
+        }
+        for (Path relPath : relPaths) {
+            Repository expectedUpstream = standardRepositories.currentUpstream(relPath);
+            for (Repository upstream : standardRepositories.upstreams()) {
+                Path upstreamFile = upstream.absolutePath(relPath);
+                if (upstreamFile != null) {
+                    Path outputFile = outputDir
+                            .resolve(upstream.name())
+                            .resolve(relPath);
+                    copyFile(upstreamFile, outputFile);
+                    if (upstream.equals(expectedUpstream)) {
+                        copyFile(upstreamFile, outputDir.resolve("expected").resolve(relPath));
+                    }
+                }
+            }
+        }
+    }
+
+    private void copyFile(Path from, Path to) throws IOException {
+        if (!from.toFile().canRead()) {
+            throw new IOException("Error reading " + from);
+        }
+        Path toDir = to.getParent();
+        if (!toDir.toFile().exists()) {
+            boolean success = toDir.toFile().mkdirs();
+            if (!success) {
+                throw new IOException("Failed to create directory " + toDir);
+            }
+        }
+        Files.copy(from, to);
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (args.length != 1) {
+            throw new IllegalArgumentException(Arrays.asList(args).toString());
+        }
+        Path outputDir = new File(args[0]).toPath();
+        StandardRepositories standardRepositories = StandardRepositories.fromEnv();
+        new CopyUpstreamFiles(standardRepositories, outputDir).run();
+    }
+}
diff --git a/tools/upstream/src/main/java/libcore/Repository.java b/tools/upstream/src/main/java/libcore/Repository.java
new file mode 100644
index 0000000..7aac3e2
--- /dev/null
+++ b/tools/upstream/src/main/java/libcore/Repository.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A set of .java files (either from ojluni or from an upstream).
+ */
+abstract class Repository {
+
+    protected final Path rootPath;
+    protected final String name;
+
+    protected Repository(Path rootPath, String name) {
+        this.rootPath = Objects.requireNonNull(rootPath);
+        this.name = Objects.requireNonNull(name);
+        if (!rootPath.toFile().isDirectory()) {
+            throw new IllegalArgumentException("Missing or not a directory: " + rootPath);
+        }
+    }
+
+    /**
+     * @param relPath a relative path of a .java file in the repository, e.g.
+     *        "java/util/ArrayList.java".
+     * @return the path of the indicated file (either absolute, or relative to the current
+     *         working directory), or null if the file does not exist in this Repository.
+     */
+    public final Path absolutePath(Path relPath) {
+        Path p = pathFromRepository(relPath);
+        return p == null ? null : rootPath.resolve(p).toAbsolutePath();
+    }
+
+    public abstract Path pathFromRepository(Path relPath);
+
+    /**
+     * @return A human readable name to identify this repository, suitable for use as a
+     *         directory name.
+     */
+    public final String name() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return name() + " repository";
+    }
+
+    /**
+     * A checkout of the hg repository of OpenJDK 9 or higher, located in the
+     * subdirectory {@code upstreamName} under the directory {@code upstreamRoot}.
+     */
+    public static Repository openJdk9(Path upstreamRoot, String upstreamName) {
+        List<String> sourceDirs = Arrays.asList(
+                "jdk/src/java.base/share/classes",
+                "jdk/src/java.logging/share/classes",
+                "jdk/src/java.prefs/share/classes",
+                "jdk/src/java.sql/share/classes",
+                "jdk/src/java.desktop/share/classes",
+                "jdk/src/java.base/solaris/classes",
+                "jdk/src/java.base/unix/classes",
+                "jdk/src/java.prefs/unix/classes",
+                "jdk/src/jdk.unsupported/share/classes",
+                "jdk/src/jdk.net/share/classes",
+                "jdk/src/java.base/linux/classes"
+        );
+        return new OpenJdkRepository(upstreamRoot, upstreamName, sourceDirs);
+    }
+
+    /**
+     * A checkout of the hg repository of OpenJDK 8 or earlier, located in the
+     * subdirectory {@code upstreamName} under the directory {@code upstreamRoot}.
+     */
+    public static Repository openJdkLegacy(Path upstreamRoot, String upstreamName) {
+        List<String> sourceDirs = Arrays.asList("jdk/src/share/classes", "jdk/src/solaris/classes");
+        return new OpenJdkRepository(upstreamRoot, upstreamName, sourceDirs);
+    }
+
+    /**
+     * Checkouts of hg repositories of OpenJDK 8 or earlier, located in the
+     * respective {@code upstreamNames} subdirectories under the join parent
+     * directory {@code upstreamRoot}.
+     */
+    public static List<Repository> openJdkLegacy(Path upstreamRoot, List<String> upstreamNames) {
+        List<String> sourceDirs = Arrays.asList("jdk/src/share/classes", "jdk/src/solaris/classes");
+        List<Repository> result = new ArrayList<>();
+        for (String upstreamName : upstreamNames) {
+            result.add(new OpenJdkRepository(upstreamRoot, upstreamName, sourceDirs));
+        }
+        return Collections.unmodifiableList(result);
+    }
+
+    static class OjluniRepository extends Repository {
+
+        /**
+         * The repository of ojluni java files belonging to the Android sources under
+         * {@code buildTop}.
+         *
+         * @param buildTop The root path of an Android checkout, as identified by the
+         *        {@quote ANDROID_BUILD_TOP} environment variable.
+         */
+        public OjluniRepository(Path buildTop) {
+            super(buildTop.resolve("libcore"), "ojluni");
+        }
+
+
+        @Override
+        public Path pathFromRepository(Path relPath) {
+            return Paths.get("ojluni/src/main/java").resolve(relPath);
+        }
+
+        /**
+         * Returns the list of relative paths to .java files parsed from openjdk_java_files.mk
+         */
+        public List<Path> loadRelPathsFromMakefile() throws IOException {
+            List<Path> result = new ArrayList<>();
+            Path makefile = rootPath.resolve("openjdk_java_files.mk");
+            Pattern pattern = Pattern.compile("\\s+ojluni/src/main/java/(.+\\.java)\\s*\\\\\\s*");
+            for (String line : Util.readLines(makefile)) {
+                Matcher matcher = pattern.matcher(line);
+                if (matcher.matches()) {
+                    Path path = new File(matcher.group(1)).toPath();
+                    result.add(path);
+                }
+            }
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "libcore ojluni";
+        }
+    }
+
+    static class OpenJdkRepository extends Repository {
+        private final List<String> sourceDirs;
+
+        public OpenJdkRepository(Path upstreamRoot, String name, List<String> sourceDirs) {
+            super(upstreamRoot.resolve(name), name);
+            this.sourceDirs = Objects.requireNonNull(sourceDirs);
+        }
+
+        @Override
+        public Path pathFromRepository(Path relPath) {
+            for (String sourceDir : sourceDirs) {
+                Path repositoryRelativePath = Paths.get(sourceDir).resolve(relPath);
+                Path file = rootPath.resolve(repositoryRelativePath);
+                if (file.toFile().exists()) {
+                    return repositoryRelativePath;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            return "OpenJDK " + name;
+        }
+    }
+
+
+}
diff --git a/tools/upstream/src/main/java/libcore/StandardRepositories.java b/tools/upstream/src/main/java/libcore/StandardRepositories.java
new file mode 100644
index 0000000..36478dd
--- /dev/null
+++ b/tools/upstream/src/main/java/libcore/StandardRepositories.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import libcore.Repository.OjluniRepository;
+
+import static libcore.Repository.openJdk9;
+import static libcore.Repository.openJdkLegacy;
+
+public class StandardRepositories {
+
+    private final List<Repository> historicUpstreams;
+    private final Repository defaultUpstream;
+    private final Repository jsr166Upstream;
+    private final OjluniRepository ojluni;
+
+    private StandardRepositories(Path buildTop, Path upstreamRoot) {
+        this.historicUpstreams = openJdkLegacy(upstreamRoot, Arrays.asList("8u60", "7u40"));
+        this.defaultUpstream = openJdkLegacy(upstreamRoot, "8u121-b13");
+        this.jsr166Upstream = openJdk9(upstreamRoot, "9b113+");
+        this.ojluni = new OjluniRepository(buildTop);
+    }
+
+    public List<Repository> historicUpstreams() {
+        return historicUpstreams;
+    }
+
+    public OjluniRepository ojluni() {
+        return ojluni;
+    }
+
+    /**
+     * Returns all upstream repository snapshots, in order from latest to earliest.
+     */
+    public List<Repository> upstreams() {
+        List<Repository> upstreams = new ArrayList<>(Arrays.asList(
+                jsr166Upstream, defaultUpstream));
+        upstreams.addAll(historicUpstreams);
+        return Collections.unmodifiableList(upstreams);
+    }
+
+    public static StandardRepositories fromEnv() {
+        Path androidBuildTop = Paths.get(getEnvOrThrow("ANDROID_BUILD_TOP"));
+        Path upstreamRoot = Paths.get(getEnvOrThrow("OPENJDK_HOME"));
+        return new StandardRepositories(androidBuildTop, upstreamRoot);
+    }
+
+    private static String getEnvOrThrow(String name) {
+        String result = System.getenv(name);
+        if (result == null) {
+            throw new IllegalStateException("Environment variable undefined: " + name);
+        }
+        return result;
+    }
+
+    private static final Set<String> juFilesFromJsr166 = Collections.unmodifiableSet(
+            new HashSet<>(Arrays.asList(
+                    "AbstractQueue",
+                    "ArrayDeque",
+                    "ArrayPrefixHelpers",
+                    "Deque",
+                    "Map",
+                    "NavigableMap",
+                    "NavigableSet",
+                    "PriorityQueue",
+                    "Queue",
+                    "SplittableRandom"
+            )));
+
+    public Repository currentUpstream(Path relPath) {
+        boolean isJsr166 = relPath.toString().startsWith("java/util/concurrent");
+        String ju = "java/util/";
+        String suffix = ".java";
+        if (!isJsr166 && relPath.startsWith(ju)) {
+            String name = relPath.toString().substring(ju.length());
+            if (name.endsWith(suffix)) {
+                name = name.substring(0, name.length() - suffix.length());
+                isJsr166 = juFilesFromJsr166.contains(name);
+            }
+        }
+        return isJsr166 ? jsr166Upstream : defaultUpstream;
+    }
+
+}
diff --git a/tools/upstream/src/main/java/libcore/Util.java b/tools/upstream/src/main/java/libcore/Util.java
new file mode 100644
index 0000000..d213080
--- /dev/null
+++ b/tools/upstream/src/main/java/libcore/Util.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+class Util {
+    private Util() {
+    }
+
+    public static List<String> readLines(Path path) throws IOException {
+        List<String> result = new ArrayList<>();
+        try (BufferedReader reader = new BufferedReader(new FileReader(path.toFile()))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                result.add(line);
+            }
+        }
+        return result;
+    }
+
+}
diff --git a/tools/upstream/src/main/libcore-compare-upstreams.mf b/tools/upstream/src/main/libcore-compare-upstreams.mf
new file mode 100644
index 0000000..12db91e
--- /dev/null
+++ b/tools/upstream/src/main/libcore-compare-upstreams.mf
@@ -0,0 +1 @@
+Main-Class: libcore.CompareUpstreams
diff --git a/tools/upstream/src/main/libcore-copy-upstream-files.mf b/tools/upstream/src/main/libcore-copy-upstream-files.mf
new file mode 100644
index 0000000..7babdbc
--- /dev/null
+++ b/tools/upstream/src/main/libcore-copy-upstream-files.mf
@@ -0,0 +1 @@
+Main-Class: libcore.CopyUpstreamFiles
diff --git a/tools/upstream/upstream-tool.iml b/tools/upstream/upstream-tool.iml
new file mode 100644
index 0000000..f76df2b
--- /dev/null
+++ b/tools/upstream/upstream-tool.iml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file