Merge RP1A.200123.001

Change-Id: Ic5290bd388bc1414c066c5d823edc8dc72cb4a97
diff --git a/JavaLibrary.bp b/JavaLibrary.bp
index f3a5ead..84c9687 100644
--- a/JavaLibrary.bp
+++ b/JavaLibrary.bp
@@ -484,6 +484,7 @@
 java_library_static {
     name: "core-test-rules",
     visibility: [
+        "//art/build/sdk",
         "//external/conscrypt",
         "//frameworks/base/location/tests/locationtests",
         "//frameworks/base/core/tests/coretests",
@@ -504,6 +505,7 @@
 java_library_static {
     name: "core-compat-test-rules",
     visibility: [
+        "//art/build/sdk",
         "//frameworks/base/tests/PlatformCompatGating/test-rules",
     ],
     srcs: [
@@ -527,6 +529,7 @@
 java_library_static {
     name: "core-tests-support",
     visibility: [
+        "//art/build/sdk",
         "//cts/apps/CtsVerifier",
         "//cts/tests/tests/keystore",
         "//cts/tests/tests/net",
@@ -985,6 +988,7 @@
 java_library_host {
     name: "timezone-host",
     visibility: [
+        "//art/build/sdk",
         "//system/timezone/distro/core",
     ],
     srcs: [":timezone_host_files"],
diff --git a/NativeCode.bp b/NativeCode.bp
index 25c128b..9619420 100644
--- a/NativeCode.bp
+++ b/NativeCode.bp
@@ -97,6 +97,10 @@
     apex_available: [
         "com.android.art.release",
         "com.android.art.debug",
+        // TODO(b/147813447) remove this. This is currently due to the 'runtime_libs'
+        // dependency from libjavacrypto in the conscrypt APEX.
+        "com.android.conscrypt",
+        "test_com.android.conscrypt",
     ],
     defaults: [
         "core_native_default_flags",
@@ -202,6 +206,7 @@
 cc_library_shared {
     name: "libjavacoretests",
     visibility: [
+        "//art/build/sdk",
         "//cts/tests/libcore/luni",
     ],
     defaults: ["core_native_default_flags"],
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index 1993fd5..f5136a4 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -330,14 +330,7 @@
     }
 
     @Override public String toString() {
-        String sharedLibs = "";
-        if (sharedLibraryLoaders != null) {
-            for (Object obj : sharedLibraryLoaders) {
-                sharedLibs += obj + ",";
-            }
-        }
-        return getClass().getName() + "[" + pathList + "; parent=(" + getParent()
-                + "), shared-libs=(" + sharedLibs + ")]";
+        return getClass().getName() + "[" + pathList + "]";
     }
 
     /**
diff --git a/dalvik/src/main/java/dalvik/system/RuntimeHooks.java b/dalvik/src/main/java/dalvik/system/RuntimeHooks.java
index 320ea28..f1af867 100644
--- a/dalvik/src/main/java/dalvik/system/RuntimeHooks.java
+++ b/dalvik/src/main/java/dalvik/system/RuntimeHooks.java
@@ -16,10 +16,15 @@
 
 package dalvik.system;
 
+import dalvik.system.ThreadPrioritySetter;
+
 import java.util.Objects;
 import java.util.TimeZone;
 import java.util.function.Supplier;
 
+import libcore.util.NonNull;
+import libcore.util.Nullable;
+
 /**
  * Provides lifecycle methods and other hooks for an Android runtime "container" to call into the
  * runtime and core libraries during initialization. For example, from
@@ -35,6 +40,10 @@
 
     private static Supplier<String> zoneIdSupplier;
 
+    // BEGIN Android-added: Customize behavior of Thread.setPriority(). http://b/139521784
+    private static volatile ThreadPrioritySetter threadPrioritySetter;
+    // END Android-added: Customize behavior of Thread.setPriority(). http://b/139521784
+
     private RuntimeHooks() {
         // No need to construct an instance. All methods are static.
     }
@@ -77,4 +86,27 @@
             Thread.UncaughtExceptionHandler uncaughtExceptionHandler) {
         Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
     }
+
+    // BEGIN Android-added: Customize behavior of Thread.setPriority(). http://b/139521784
+    /**
+     * Sets a {@link ThreadPrioritySetter} that will be invoked instead of
+     * the default implementation during {@link Thread.setPriority(int)}.
+     * @hide
+     */
+    @libcore.api.CorePlatformApi
+    public static void setThreadPrioritySetter(@NonNull ThreadPrioritySetter threadPrioritySetter) {
+        RuntimeHooks.threadPrioritySetter = Objects.requireNonNull(threadPrioritySetter);
+    }
+
+    /**
+     * Returns the last {@code ThreadPrioritySetter} that has been
+     * {@code #setThreadPrioritySetter(ThreadPrioritySetter) set}, or
+     * null if the setter has not yet been called.
+     * @hide
+     */
+    @libcore.api.CorePlatformApi
+    public static @Nullable ThreadPrioritySetter getThreadPrioritySetter() {
+        return threadPrioritySetter;
+    }
+    // END Android-added: Customize behavior of Thread.setPriority(). http://b/139521784
 }
diff --git a/dalvik/src/main/java/dalvik/system/ThreadPrioritySetter.java b/dalvik/src/main/java/dalvik/system/ThreadPrioritySetter.java
new file mode 100644
index 0000000..484784b
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/ThreadPrioritySetter.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 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 dalvik.system;
+
+/**
+ * Interface for hooking to thread priority runtime setting
+ * @hide
+ */
+@libcore.api.CorePlatformApi
+@FunctionalInterface
+public interface ThreadPrioritySetter {
+    @libcore.api.CorePlatformApi
+    void setPriority(int nativeTid, int priority);
+}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/CharacterTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/CharacterTest.java
index a5007f0..2465071 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/CharacterTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/CharacterTest.java
@@ -747,8 +747,13 @@
         assertTrue(Character.getType((int) '$') == Character.CURRENCY_SYMBOL);
         assertTrue(Character.getType((int) '\u2029') == Character.PARAGRAPH_SEPARATOR);
 
+        // Unicode 13 defines a new range 0x30000–0x3134A
+        assertTrue(Character.getType(0x30000) == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR);
+        assertTrue(Character.getType(0x3134A) == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR);
+        assertTrue(Character.getType(0x2FFFF) == Character.UNASSIGNED);
+        assertTrue(Character.getType(0x3134B) == Character.UNASSIGNED);
+
         assertTrue(Character.getType(0x9FFF) == Character.UNASSIGNED);
-        assertTrue(Character.getType(0x30000) == Character.UNASSIGNED);
         assertTrue(Character.getType(0x110000) == Character.UNASSIGNED);
 
         assertTrue(Character.getType(0x0041) == Character.UPPERCASE_LETTER);
@@ -860,9 +865,14 @@
         assertTrue(Character.isDefined((int) '\u6039'));
         assertTrue(Character.isDefined(0x10300));
 
-        assertFalse(Character.isDefined(0x30000));
         assertFalse(Character.isDefined(0x3FFFF));
         assertFalse(Character.isDefined(0x110000));
+
+        // Unicode 13 adds a new range 0x30000–0x3134A
+        assertTrue(Character.isDefined(0x30000));
+        assertTrue(Character.isDefined(0x3134A));
+        assertFalse(Character.isDefined(0x2FFFF));
+        assertFalse(Character.isDefined(0x3134B));
     }
 
     /**
@@ -1557,10 +1567,15 @@
      */
     public void test_isDirectionaliy_I() {
         assertEquals(Character.DIRECTIONALITY_UNDEFINED, Character.getDirectionality(0xFFFE));
-        assertEquals(Character.DIRECTIONALITY_UNDEFINED, Character.getDirectionality(0x30000));
         assertEquals(Character.DIRECTIONALITY_UNDEFINED, Character.getDirectionality(0x110000));
         assertEquals(Character.DIRECTIONALITY_UNDEFINED, Character.getDirectionality(-1));
 
+        // Unicode 13 adds a new range 0x30000–0x3134A
+        assertEquals(Character.DIRECTIONALITY_LEFT_TO_RIGHT, Character.getDirectionality(0x30000));
+        assertEquals(Character.DIRECTIONALITY_LEFT_TO_RIGHT, Character.getDirectionality(0x3134A));
+        assertEquals(Character.DIRECTIONALITY_UNDEFINED, Character.getDirectionality(0x2FFFF));
+        assertEquals(Character.DIRECTIONALITY_UNDEFINED, Character.getDirectionality(0x3134B));
+
         assertEquals(Character.DIRECTIONALITY_LEFT_TO_RIGHT, Character.getDirectionality(0x0041));
         assertEquals(Character.DIRECTIONALITY_LEFT_TO_RIGHT, Character.getDirectionality(0x10000));
         assertEquals(Character.DIRECTIONALITY_LEFT_TO_RIGHT, Character.getDirectionality(0x104A9));
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 0f2f75d..a97d7fc 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -16,8 +16,12 @@
 
 package dalvik.system;
 
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 
+import dalvik.annotation.compat.VersionCodes;
+
 import java.lang.ref.FinalizerReference;
 import java.util.HashMap;
 import java.util.Map;
@@ -59,6 +63,16 @@
     }
 
     /**
+     * Remove meta-reflection workaround for hidden api usage for apps targeting R+. This allowed
+     * apps to obtain references to blacklisted fields and methods through an extra layer of
+     * reflection.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = VersionCodes.Q)
+    private static final long
+        PREVENT_META_REFLECTION_BLACKLIST_ACCESS = 142365358; // This is a bug id.
+
+    /**
      * Interface for logging hidden API usage events.
      */
     @libcore.api.CorePlatformApi
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java
index e2b191e..70fdce5 100644
--- a/luni/src/main/java/android/system/Os.java
+++ b/luni/src/main/java/android/system/Os.java
@@ -151,9 +151,10 @@
      */
     public static void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException { Libcore.os.fchown(fd, uid, gid); }
 
-    /** @hide */
-    @libcore.api.CorePlatformApi
-    public static int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException { return Libcore.os.fcntlInt(fd, cmd, arg); }
+    /**
+     * See <a href="http://man7.org/linux/man-pages/man2/fcntl.2.html">fcntl(2)</a>.
+     */
+    public static int fcntlInt(@NonNull FileDescriptor fd, int cmd, int arg) throws ErrnoException { return Libcore.os.fcntlInt(fd, cmd, arg); }
 
     /** @hide */
     public static int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException { return Libcore.os.fcntlVoid(fd, cmd); }
diff --git a/luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java b/luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java
index adb193d..49d71a0 100644
--- a/luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java
+++ b/luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java
@@ -18,11 +18,19 @@
 
 import android.compat.annotation.UnsupportedAppUsage;
 import java.io.FileDescriptor;
+import libcore.api.IntraCoreApi;
 
+/**
+ * Implements interruption of threads blocked in I/O system calls.
+ *
+ * @hide
+ */
+@IntraCoreApi
 public final class AsynchronousCloseMonitor {
     private AsynchronousCloseMonitor() {
     }
 
     @UnsupportedAppUsage
+    @IntraCoreApi
     public static native void signalBlockedThreads(FileDescriptor fd);
 }
diff --git a/luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java b/luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java
index d95ff50..b4c8976 100644
--- a/luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java
+++ b/luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java
@@ -55,6 +55,7 @@
         return System.getenv(ANDROID_DATA_ENV) + "/misc/zoneinfo/";
     }
 
+    // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797
     @libcore.api.CorePlatformApi
     public static String getDataTimeZoneFile(String fileName) {
         return getDataTimeZoneRootDir() + "current/" + fileName;
diff --git a/luni/src/main/java/libcore/timezone/TzDataSetVersion.java b/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
index c2e7d7b..a404551 100644
--- a/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
+++ b/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
@@ -102,13 +102,17 @@
                     + REVISION_PATTERN.pattern()
                     + ".*" /* ignore trailing */);
 
+    @libcore.api.CorePlatformApi
     public final int formatMajorVersion;
+
+    @libcore.api.CorePlatformApi
     public final int formatMinorVersion;
 
     // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797
     @libcore.api.CorePlatformApi
     public final String rulesVersion;
 
+    @libcore.api.CorePlatformApi
     public final int revision;
 
     @libcore.api.CorePlatformApi
@@ -155,6 +159,17 @@
         return fromBytes(versionBytes);
     }
 
+    /**
+     * Reads the version of time zone data supplied by the time zone data module.
+     */
+    @libcore.api.CorePlatformApi
+    public static TzDataSetVersion readTimeZoneModuleVersion()
+            throws IOException, TzDataSetException {
+        String tzVersionFileName =
+                TimeZoneDataFiles.getTimeZoneModuleTzFile(TzDataSetVersion.DEFAULT_FILE_NAME);
+        return readFromFile(new File(tzVersionFileName));
+    }
+
     // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797
     @libcore.api.CorePlatformApi
     public byte[] toBytes() {
diff --git a/luni/src/main/java/libcore/timezone/ZoneInfoDB.java b/luni/src/main/java/libcore/timezone/ZoneInfoDB.java
index 3e2e60e..dd9260b 100644
--- a/luni/src/main/java/libcore/timezone/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/timezone/ZoneInfoDB.java
@@ -38,382 +38,374 @@
  * @hide - used to implement TimeZone
  */
 @libcore.api.CorePlatformApi
-public final class ZoneInfoDB {
+public final class ZoneInfoDB implements AutoCloseable {
 
   // VisibleForTesting
   public static final String TZDATA_FILE_NAME = "tzdata";
 
-  private static final TzData DATA =
-          TzData.loadTzDataWithFallback(TimeZoneDataFiles.getTimeZoneFilePaths(TZDATA_FILE_NAME));
+  private static final ZoneInfoDB DATA = ZoneInfoDB.loadTzDataWithFallback(
+          TimeZoneDataFiles.getTimeZoneFilePaths(TZDATA_FILE_NAME));
 
-  /** @hide */
-  @libcore.api.CorePlatformApi
-  public static class TzData implements AutoCloseable {
+  // The database reserves 40 bytes for each id.
+  private static final int SIZEOF_TZNAME = 40;
 
-    // The database reserves 40 bytes for each id.
-    private static final int SIZEOF_TZNAME = 40;
+  // The database uses 32-bit (4 byte) integers.
+  private static final int SIZEOF_TZINT = 4;
 
-    // The database uses 32-bit (4 byte) integers.
-    private static final int SIZEOF_TZINT = 4;
+  // Each index entry takes up this number of bytes.
+  public static final int SIZEOF_INDEX_ENTRY = SIZEOF_TZNAME + 3 * SIZEOF_TZINT;
 
-    // Each index entry takes up this number of bytes.
-    public static final int SIZEOF_INDEX_ENTRY = SIZEOF_TZNAME + 3 * SIZEOF_TZINT;
+  /**
+   * {@code true} if {@link #close()} has been called meaning the instance cannot provide any
+   * data.
+   */
+  private boolean closed;
 
-    /**
-     * {@code true} if {@link #close()} has been called meaning the instance cannot provide any
-     * data.
-     */
-    private boolean closed;
+  /**
+   * Rather than open, read, and close the big data file each time we look up a time zone,
+   * we map the big data file during startup, and then just use the MemoryMappedFile.
+   *
+   * At the moment, this "big" data file is about 500 KiB. At some point, that will be small
+   * enough that we could just keep the byte[] in memory, but using mmap(2) like this has the
+   * nice property that even if someone replaces the file under us (because multiple gservices
+   * updates have gone out, say), we still get a consistent (if outdated) view of the world.
+   */
+  // Android-added: @ReachabilitySensitive
+  @ReachabilitySensitive
+  private MemoryMappedFile mappedFile;
 
-    /**
-     * Rather than open, read, and close the big data file each time we look up a time zone,
-     * we map the big data file during startup, and then just use the MemoryMappedFile.
-     *
-     * At the moment, this "big" data file is about 500 KiB. At some point, that will be small
-     * enough that we could just keep the byte[] in memory, but using mmap(2) like this has the
-     * nice property that even if someone replaces the file under us (because multiple gservices
-     * updates have gone out, say), we still get a consistent (if outdated) view of the world.
-     */
-    // Android-added: @ReachabilitySensitive
-    @ReachabilitySensitive
-    private MemoryMappedFile mappedFile;
+  private String version;
+  private String zoneTab;
 
-    private String version;
-    private String zoneTab;
+  /**
+   * The 'ids' array contains time zone ids sorted alphabetically, for binary searching.
+   * The other two arrays are in the same order. 'byteOffsets' gives the byte offset
+   * of each time zone, and 'rawUtcOffsetsCache' gives the time zone's raw UTC offset.
+   */
+  private String[] ids;
+  private int[] byteOffsets;
+  private int[] rawUtcOffsetsCache; // Access this via getRawUtcOffsets instead.
 
-    /**
-     * The 'ids' array contains time zone ids sorted alphabetically, for binary searching.
-     * The other two arrays are in the same order. 'byteOffsets' gives the byte offset
-     * of each time zone, and 'rawUtcOffsetsCache' gives the time zone's raw UTC offset.
-     */
-    private String[] ids;
-    private int[] byteOffsets;
-    private int[] rawUtcOffsetsCache; // Access this via getRawUtcOffsets instead.
-
-    /**
-     * ZoneInfo objects are worth caching because they are expensive to create.
-     * See http://b/8270865 for context.
-     */
-    private final static int CACHE_SIZE = 1;
-    private final BasicLruCache<String, ZoneInfo> cache =
-        new BasicLruCache<String, ZoneInfo>(CACHE_SIZE) {
-      @Override
-      protected ZoneInfo create(String id) {
-        try {
-          return makeTimeZoneUncached(id);
-        } catch (IOException e) {
-          throw new IllegalStateException("Unable to load timezone for ID=" + id, e);
-        }
+  /**
+   * ZoneInfo objects are worth caching because they are expensive to create.
+   * See http://b/8270865 for context.
+   */
+  private final static int CACHE_SIZE = 1;
+  private final BasicLruCache<String, ZoneInfo> cache =
+      new BasicLruCache<String, ZoneInfo>(CACHE_SIZE) {
+    @Override
+    protected ZoneInfo create(String id) {
+      try {
+        return makeTimeZoneUncached(id);
+      } catch (IOException e) {
+        throw new IllegalStateException("Unable to load timezone for ID=" + id, e);
       }
-    };
-
-    /**
-     * Loads the data at the specified paths in order, returning the first valid one as a
-     * {@link TzData} object. If there is no valid one found a basic fallback instance is created
-     * containing just GMT.
-     */
-    public static TzData loadTzDataWithFallback(String... paths) {
-      for (String path : paths) {
-        TzData tzData = new TzData();
-        if (tzData.loadData(path)) {
-          return tzData;
-        }
-      }
-
-      // We didn't find any usable tzdata on disk, so let's just hard-code knowledge of "GMT".
-      // This is actually implemented in TimeZone itself, so if this is the only time zone
-      // we report, we won't be asked any more questions.
-      System.logE("Couldn't find any " + TZDATA_FILE_NAME + " file!");
-      return TzData.createFallback();
     }
+  };
 
-    /**
-     * Loads the data at the specified path and returns the {@link TzData} object if it is valid,
-     * otherwise {@code null}.
-     */
-    @libcore.api.CorePlatformApi
-    public static TzData loadTzData(String path) {
-      TzData tzData = new TzData();
+  @libcore.api.CorePlatformApi
+  public static ZoneInfoDB getInstance() {
+    return DATA;
+  }
+
+  /**
+   * Loads the data at the specified paths in order, returning the first valid one as a
+   * {@link ZoneInfoDB} object. If there is no valid one found a basic fallback instance is created
+   * containing just GMT.
+   */
+  public static ZoneInfoDB loadTzDataWithFallback(String... paths) {
+    for (String path : paths) {
+      ZoneInfoDB tzData = new ZoneInfoDB();
       if (tzData.loadData(path)) {
         return tzData;
       }
-      return null;
     }
 
-    private static TzData createFallback() {
-      TzData tzData = new TzData();
-      tzData.populateFallback();
+    // We didn't find any usable tzdata on disk, so let's just hard-code knowledge of "GMT".
+    // This is actually implemented in TimeZone itself, so if this is the only time zone
+    // we report, we won't be asked any more questions.
+    System.logE("Couldn't find any " + TZDATA_FILE_NAME + " file!");
+    return ZoneInfoDB.createFallback();
+  }
+
+  /**
+   * Loads the data at the specified path and returns the {@link ZoneInfoDB} object if it is valid,
+   * otherwise {@code null}.
+   */
+  @libcore.api.CorePlatformApi
+  public static ZoneInfoDB loadTzData(String path) {
+    ZoneInfoDB tzData = new ZoneInfoDB();
+    if (tzData.loadData(path)) {
       return tzData;
     }
+    return null;
+  }
 
-    private TzData() {
-    }
-
-    /**
-     * Visible for testing.
-     */
-    public BufferIterator getBufferIterator(String id) {
-      checkNotClosed();
-
-      // Work out where in the big data file this time zone is.
-      int index = Arrays.binarySearch(ids, id);
-      if (index < 0) {
-        return null;
-      }
-
-      int byteOffset = byteOffsets[index];
-      BufferIterator it = mappedFile.bigEndianIterator();
-      it.skip(byteOffset);
-      return it;
-    }
-
-    private void populateFallback() {
-      version = "missing";
-      zoneTab = "# Emergency fallback data.\n";
-      ids = new String[] { "GMT" };
-      byteOffsets = rawUtcOffsetsCache = new int[1];
-    }
-
-    /**
-     * Loads the data file at the specified path. If the data is valid {@code true} will be
-     * returned and the {@link TzData} instance can be used. If {@code false} is returned then the
-     * TzData instance is left in a closed state and must be discarded.
-     */
-    private boolean loadData(String path) {
-      try {
-        mappedFile = MemoryMappedFile.mmapRO(path);
-      } catch (ErrnoException errnoException) {
-        return false;
-      }
-      try {
-        readHeader();
-        return true;
-      } catch (Exception ex) {
-        close();
-
-        // Something's wrong with the file.
-        // Log the problem and return false so we try the next choice.
-        System.logE(TZDATA_FILE_NAME + " file \"" + path + "\" was present but invalid!", ex);
-        return false;
-      }
-    }
-
-    private void readHeader() throws IOException {
-      // byte[12] tzdata_version  -- "tzdata2012f\0"
-      // int index_offset
-      // int data_offset
-      // int zonetab_offset
-      BufferIterator it = mappedFile.bigEndianIterator();
-
-      try {
-        byte[] tzdata_version = new byte[12];
-        it.readByteArray(tzdata_version, 0, tzdata_version.length);
-        String magic = new String(tzdata_version, 0, 6, StandardCharsets.US_ASCII);
-        if (!magic.equals("tzdata") || tzdata_version[11] != 0) {
-          throw new IOException("bad tzdata magic: " + Arrays.toString(tzdata_version));
-        }
-        version = new String(tzdata_version, 6, 5, StandardCharsets.US_ASCII);
-
-        final int fileSize = mappedFile.size();
-        int index_offset = it.readInt();
-        validateOffset(index_offset, fileSize);
-        int data_offset = it.readInt();
-        validateOffset(data_offset, fileSize);
-        int zonetab_offset = it.readInt();
-        validateOffset(zonetab_offset, fileSize);
-
-        if (index_offset >= data_offset || data_offset >= zonetab_offset) {
-          throw new IOException("Invalid offset: index_offset=" + index_offset
-                  + ", data_offset=" + data_offset + ", zonetab_offset=" + zonetab_offset
-                  + ", fileSize=" + fileSize);
-        }
-
-        readIndex(it, index_offset, data_offset);
-        readZoneTab(it, zonetab_offset, fileSize - zonetab_offset);
-      } catch (IndexOutOfBoundsException e) {
-        throw new IOException("Invalid read from data file", e);
-      }
-    }
-
-    private static void validateOffset(int offset, int size) throws IOException {
-      if (offset < 0 || offset >= size) {
-        throw new IOException("Invalid offset=" + offset + ", size=" + size);
-      }
-    }
-
-    private void readZoneTab(BufferIterator it, int zoneTabOffset, int zoneTabSize) {
-      byte[] bytes = new byte[zoneTabSize];
-      it.seek(zoneTabOffset);
-      it.readByteArray(bytes, 0, bytes.length);
-      zoneTab = new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
-    }
-
-    private void readIndex(BufferIterator it, int indexOffset, int dataOffset) throws IOException {
-      it.seek(indexOffset);
-
-      byte[] idBytes = new byte[SIZEOF_TZNAME];
-      int indexSize = (dataOffset - indexOffset);
-      if (indexSize % SIZEOF_INDEX_ENTRY != 0) {
-        throw new IOException("Index size is not divisible by " + SIZEOF_INDEX_ENTRY
-                + ", indexSize=" + indexSize);
-      }
-      int entryCount = indexSize / SIZEOF_INDEX_ENTRY;
-
-      byteOffsets = new int[entryCount];
-      ids = new String[entryCount];
-
-      for (int i = 0; i < entryCount; i++) {
-        // Read the fixed length timezone ID.
-        it.readByteArray(idBytes, 0, idBytes.length);
-
-        // Read the offset into the file where the data for ID can be found.
-        byteOffsets[i] = it.readInt();
-        byteOffsets[i] += dataOffset;
-
-        int length = it.readInt();
-        if (length < 44) {
-          throw new IOException("length in index file < sizeof(tzhead)");
-        }
-        it.skip(4); // Skip the unused 4 bytes that used to be the raw offset.
-
-        // Calculate the true length of the ID.
-        int len = 0;
-        while (idBytes[len] != 0 && len < idBytes.length) {
-          len++;
-        }
-        if (len == 0) {
-          throw new IOException("Invalid ID at index=" + i);
-        }
-        ids[i] = new String(idBytes, 0, len, StandardCharsets.US_ASCII);
-        if (i > 0) {
-          if (ids[i].compareTo(ids[i - 1]) <= 0) {
-            throw new IOException("Index not sorted or contains multiple entries with the same ID"
-                    + ", index=" + i + ", ids[i]=" + ids[i] + ", ids[i - 1]=" + ids[i - 1]);
-          }
-        }
-      }
-    }
-
-    @libcore.api.CorePlatformApi
-    public void validate() throws IOException {
-      checkNotClosed();
-      // Validate the data in the tzdata file by loading each and every zone.
-      for (String id : getAvailableIDs()) {
-        ZoneInfo zoneInfo = makeTimeZoneUncached(id);
-        if (zoneInfo == null) {
-          throw new IOException("Unable to find data for ID=" + id);
-        }
-      }
-    }
-
-    ZoneInfo makeTimeZoneUncached(String id) throws IOException {
-      BufferIterator it = getBufferIterator(id);
-      if (it == null) {
-        return null;
-      }
-
-      return ZoneInfo.readTimeZone(id, it, System.currentTimeMillis());
-    }
-
-    public String[] getAvailableIDs() {
-      checkNotClosed();
-      return ids.clone();
-    }
-
-    public String[] getAvailableIDs(int rawUtcOffset) {
-      checkNotClosed();
-      List<String> matches = new ArrayList<String>();
-      int[] rawUtcOffsets = getRawUtcOffsets();
-      for (int i = 0; i < rawUtcOffsets.length; ++i) {
-        if (rawUtcOffsets[i] == rawUtcOffset) {
-          matches.add(ids[i]);
-        }
-      }
-      return matches.toArray(new String[matches.size()]);
-    }
-
-    private synchronized int[] getRawUtcOffsets() {
-      if (rawUtcOffsetsCache != null) {
-        return rawUtcOffsetsCache;
-      }
-      rawUtcOffsetsCache = new int[ids.length];
-      for (int i = 0; i < ids.length; ++i) {
-        // This creates a TimeZone, which is quite expensive. Hence the cache.
-        // Note that icu4c does the same (without the cache), so if you're
-        // switching this code over to icu4j you should check its performance.
-        // Telephony shouldn't care, but someone converting a bunch of calendar
-        // events might.
-        rawUtcOffsetsCache[i] = cache.get(ids[i]).getRawOffset();
-      }
-      return rawUtcOffsetsCache;
-    }
-
-    @libcore.api.CorePlatformApi
-    public String getVersion() {
-      checkNotClosed();
-      return version;
-    }
-
-    public String getZoneTab() {
-      checkNotClosed();
-      return zoneTab;
-    }
-
-    @libcore.api.CorePlatformApi
-    public ZoneInfo makeTimeZone(String id) throws IOException {
-      checkNotClosed();
-      ZoneInfo zoneInfo = cache.get(id);
-      // The object from the cache is cloned because TimeZone / ZoneInfo are mutable.
-      return zoneInfo == null ? null : (ZoneInfo) zoneInfo.clone();
-    }
-
-    @libcore.api.CorePlatformApi
-    public boolean hasTimeZone(String id) throws IOException {
-      checkNotClosed();
-      return cache.get(id) != null;
-    }
-
-    public void close() {
-      if (!closed) {
-        closed = true;
-
-        // Clear state that takes up appreciable heap.
-        ids = null;
-        byteOffsets = null;
-        rawUtcOffsetsCache = null;
-        cache.evictAll();
-
-        // Remove the mapped file (if needed).
-        if (mappedFile != null) {
-          try {
-            mappedFile.close();
-          } catch (ErrnoException ignored) {
-          }
-          mappedFile = null;
-        }
-      }
-    }
-
-    private void checkNotClosed() throws IllegalStateException {
-      if (closed) {
-        throw new IllegalStateException("TzData is closed");
-      }
-    }
-
-    @Override protected void finalize() throws Throwable {
-      try {
-        close();
-      } finally {
-        super.finalize();
-      }
-    }
+  private static ZoneInfoDB createFallback() {
+    ZoneInfoDB tzData = new ZoneInfoDB();
+    tzData.populateFallback();
+    return tzData;
   }
 
   private ZoneInfoDB() {
   }
 
+  /**
+   * Visible for testing.
+   */
+  public BufferIterator getBufferIterator(String id) {
+    checkNotClosed();
+
+    // Work out where in the big data file this time zone is.
+    int index = Arrays.binarySearch(ids, id);
+    if (index < 0) {
+      return null;
+    }
+
+    int byteOffset = byteOffsets[index];
+    BufferIterator it = mappedFile.bigEndianIterator();
+    it.skip(byteOffset);
+    return it;
+  }
+
+  private void populateFallback() {
+    version = "missing";
+    zoneTab = "# Emergency fallback data.\n";
+    ids = new String[] { "GMT" };
+    byteOffsets = rawUtcOffsetsCache = new int[1];
+  }
+
+  /**
+   * Loads the data file at the specified path. If the data is valid {@code true} will be
+   * returned and the {@link ZoneInfoDB} instance can be used. If {@code false} is returned then the
+   * ZoneInfoDB instance is left in a closed state and must be discarded.
+   */
+  private boolean loadData(String path) {
+    try {
+      mappedFile = MemoryMappedFile.mmapRO(path);
+    } catch (ErrnoException errnoException) {
+      return false;
+    }
+    try {
+      readHeader();
+      return true;
+    } catch (Exception ex) {
+      close();
+
+      // Something's wrong with the file.
+      // Log the problem and return false so we try the next choice.
+      System.logE(TZDATA_FILE_NAME + " file \"" + path + "\" was present but invalid!", ex);
+      return false;
+    }
+  }
+
+  private void readHeader() throws IOException {
+    // byte[12] tzdata_version  -- "tzdata2012f\0"
+    // int index_offset
+    // int data_offset
+    // int zonetab_offset
+    BufferIterator it = mappedFile.bigEndianIterator();
+
+    try {
+      byte[] tzdata_version = new byte[12];
+      it.readByteArray(tzdata_version, 0, tzdata_version.length);
+      String magic = new String(tzdata_version, 0, 6, StandardCharsets.US_ASCII);
+      if (!magic.equals("tzdata") || tzdata_version[11] != 0) {
+        throw new IOException("bad tzdata magic: " + Arrays.toString(tzdata_version));
+      }
+      version = new String(tzdata_version, 6, 5, StandardCharsets.US_ASCII);
+
+      final int fileSize = mappedFile.size();
+      int index_offset = it.readInt();
+      validateOffset(index_offset, fileSize);
+      int data_offset = it.readInt();
+      validateOffset(data_offset, fileSize);
+      int zonetab_offset = it.readInt();
+      validateOffset(zonetab_offset, fileSize);
+
+      if (index_offset >= data_offset || data_offset >= zonetab_offset) {
+        throw new IOException("Invalid offset: index_offset=" + index_offset
+                + ", data_offset=" + data_offset + ", zonetab_offset=" + zonetab_offset
+                + ", fileSize=" + fileSize);
+      }
+
+      readIndex(it, index_offset, data_offset);
+      readZoneTab(it, zonetab_offset, fileSize - zonetab_offset);
+    } catch (IndexOutOfBoundsException e) {
+      throw new IOException("Invalid read from data file", e);
+    }
+  }
+
+  private static void validateOffset(int offset, int size) throws IOException {
+    if (offset < 0 || offset >= size) {
+      throw new IOException("Invalid offset=" + offset + ", size=" + size);
+    }
+  }
+
+  private void readZoneTab(BufferIterator it, int zoneTabOffset, int zoneTabSize) {
+    byte[] bytes = new byte[zoneTabSize];
+    it.seek(zoneTabOffset);
+    it.readByteArray(bytes, 0, bytes.length);
+    zoneTab = new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
+  }
+
+  private void readIndex(BufferIterator it, int indexOffset, int dataOffset) throws IOException {
+    it.seek(indexOffset);
+
+    byte[] idBytes = new byte[SIZEOF_TZNAME];
+    int indexSize = (dataOffset - indexOffset);
+    if (indexSize % SIZEOF_INDEX_ENTRY != 0) {
+      throw new IOException("Index size is not divisible by " + SIZEOF_INDEX_ENTRY
+              + ", indexSize=" + indexSize);
+    }
+    int entryCount = indexSize / SIZEOF_INDEX_ENTRY;
+
+    byteOffsets = new int[entryCount];
+    ids = new String[entryCount];
+
+    for (int i = 0; i < entryCount; i++) {
+      // Read the fixed length timezone ID.
+      it.readByteArray(idBytes, 0, idBytes.length);
+
+      // Read the offset into the file where the data for ID can be found.
+      byteOffsets[i] = it.readInt();
+      byteOffsets[i] += dataOffset;
+
+      int length = it.readInt();
+      if (length < 44) {
+        throw new IOException("length in index file < sizeof(tzhead)");
+      }
+      it.skip(4); // Skip the unused 4 bytes that used to be the raw offset.
+
+      // Calculate the true length of the ID.
+      int len = 0;
+      while (idBytes[len] != 0 && len < idBytes.length) {
+        len++;
+      }
+      if (len == 0) {
+        throw new IOException("Invalid ID at index=" + i);
+      }
+      ids[i] = new String(idBytes, 0, len, StandardCharsets.US_ASCII);
+      if (i > 0) {
+        if (ids[i].compareTo(ids[i - 1]) <= 0) {
+          throw new IOException("Index not sorted or contains multiple entries with the same ID"
+                  + ", index=" + i + ", ids[i]=" + ids[i] + ", ids[i - 1]=" + ids[i - 1]);
+        }
+      }
+    }
+  }
+
   @libcore.api.CorePlatformApi
-  public static TzData getInstance() {
-    return DATA;
+  public void validate() throws IOException {
+    checkNotClosed();
+    // Validate the data in the tzdata file by loading each and every zone.
+    for (String id : getAvailableIDs()) {
+      ZoneInfo zoneInfo = makeTimeZoneUncached(id);
+      if (zoneInfo == null) {
+        throw new IOException("Unable to find data for ID=" + id);
+      }
+    }
+  }
+
+  ZoneInfo makeTimeZoneUncached(String id) throws IOException {
+    BufferIterator it = getBufferIterator(id);
+    if (it == null) {
+      return null;
+    }
+
+    return ZoneInfo.readTimeZone(id, it, System.currentTimeMillis());
+  }
+
+  public String[] getAvailableIDs() {
+    checkNotClosed();
+    return ids.clone();
+  }
+
+  public String[] getAvailableIDs(int rawUtcOffset) {
+    checkNotClosed();
+    List<String> matches = new ArrayList<String>();
+    int[] rawUtcOffsets = getRawUtcOffsets();
+    for (int i = 0; i < rawUtcOffsets.length; ++i) {
+      if (rawUtcOffsets[i] == rawUtcOffset) {
+        matches.add(ids[i]);
+      }
+    }
+    return matches.toArray(new String[matches.size()]);
+  }
+
+  private synchronized int[] getRawUtcOffsets() {
+    if (rawUtcOffsetsCache != null) {
+      return rawUtcOffsetsCache;
+    }
+    rawUtcOffsetsCache = new int[ids.length];
+    for (int i = 0; i < ids.length; ++i) {
+      // This creates a TimeZone, which is quite expensive. Hence the cache.
+      // Note that icu4c does the same (without the cache), so if you're
+      // switching this code over to icu4j you should check its performance.
+      // Telephony shouldn't care, but someone converting a bunch of calendar
+      // events might.
+      rawUtcOffsetsCache[i] = cache.get(ids[i]).getRawOffset();
+    }
+    return rawUtcOffsetsCache;
+  }
+
+  @libcore.api.CorePlatformApi
+  public String getVersion() {
+    checkNotClosed();
+    return version;
+  }
+
+  public String getZoneTab() {
+    checkNotClosed();
+    return zoneTab;
+  }
+
+  @libcore.api.CorePlatformApi
+  public ZoneInfo makeTimeZone(String id) throws IOException {
+    checkNotClosed();
+    ZoneInfo zoneInfo = cache.get(id);
+    // The object from the cache is cloned because TimeZone / ZoneInfo are mutable.
+    return zoneInfo == null ? null : (ZoneInfo) zoneInfo.clone();
+  }
+
+  @libcore.api.CorePlatformApi
+  public boolean hasTimeZone(String id) throws IOException {
+    checkNotClosed();
+    return cache.get(id) != null;
+  }
+
+  public void close() {
+    if (!closed) {
+      closed = true;
+
+      // Clear state that takes up appreciable heap.
+      ids = null;
+      byteOffsets = null;
+      rawUtcOffsetsCache = null;
+      cache.evictAll();
+
+      // Remove the mapped file (if needed).
+      if (mappedFile != null) {
+        try {
+          mappedFile.close();
+        } catch (ErrnoException ignored) {
+        }
+        mappedFile = null;
+      }
+    }
+  }
+
+  private void checkNotClosed() throws IllegalStateException {
+    if (closed) {
+      throw new IllegalStateException("ZoneInfoDB instance is closed");
+    }
+  }
+
+  @Override protected void finalize() throws Throwable {
+    try {
+      close();
+    } finally {
+      super.finalize();
+    }
   }
 }
diff --git a/luni/src/main/java/libcore/util/CoreLibraryDebug.java b/luni/src/main/java/libcore/util/CoreLibraryDebug.java
index 8ba3853..dc1012f 100644
--- a/luni/src/main/java/libcore/util/CoreLibraryDebug.java
+++ b/luni/src/main/java/libcore/util/CoreLibraryDebug.java
@@ -17,6 +17,7 @@
 package libcore.util;
 
 import com.android.icu.util.Icu4cMetadata;
+
 import libcore.timezone.TimeZoneDataFiles;
 import libcore.timezone.TzDataSetVersion;
 import libcore.timezone.TzDataSetVersion.TzDataSetException;
diff --git a/luni/src/module/java/module-info.java b/luni/src/module/java/module-info.java
index 8a290d9..6c2bc12 100644
--- a/luni/src/module/java/module-info.java
+++ b/luni/src/module/java/module-info.java
@@ -69,6 +69,8 @@
     exports javax.security.auth.x500;
     exports javax.security.cert;
     exports javax.sql;
+    exports jdk.internal.util;
+    exports jdk.internal.vm.annotation;
     exports jdk.net;
     exports sun.invoke.util;
     exports sun.misc;
diff --git a/luni/src/test/java/libcore/android/system/OsTest.java b/luni/src/test/java/libcore/android/system/OsTest.java
index 25d56bc..b9ca0bf 100644
--- a/luni/src/test/java/libcore/android/system/OsTest.java
+++ b/luni/src/test/java/libcore/android/system/OsTest.java
@@ -87,6 +87,45 @@
         }
     }
 
+    public void testFcntlInt_udpSocket() throws Exception {
+        final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
+        try {
+            assertEquals(0, (Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK));
+
+            // Verify that we can set file descriptor flags on sockets
+            Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM | O_NONBLOCK);
+            assertTrue((Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK) != 0);
+
+            // Check that we can turn it off also.
+            Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM);
+            assertEquals(0, (Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK));
+        } finally {
+            Os.close(fd);
+        }
+    }
+
+    public void testFcntlInt_invalidCmd() throws Exception {
+        final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
+        try {
+            final int unknownCmd = -1;
+            Os.fcntlInt(fd, unknownCmd, 0);
+            fail("Expected failure due to invalid cmd");
+        } catch (ErrnoException expected) {
+            assertEquals(EINVAL, expected.errno);
+        } finally {
+            Os.close(fd);
+        }
+    }
+
+    public void testFcntlInt_nullFd() throws Exception {
+        try {
+            Os.fcntlInt(null, F_SETFL, O_NONBLOCK);
+            fail("Expected failure due to null file descriptor");
+        } catch (ErrnoException expected) {
+            assertEquals(EBADF, expected.errno);
+        }
+    }
+
     public void testUnixDomainSockets_in_file_system() throws Exception {
         String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
         new File(path).delete();
diff --git a/luni/src/test/java/libcore/java/net/InetAddressTest.java b/luni/src/test/java/libcore/java/net/InetAddressTest.java
index 88f03d4..6bbfe01 100644
--- a/luni/src/test/java/libcore/java/net/InetAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetAddressTest.java
@@ -282,10 +282,17 @@
     public void test_isReachable_by_ICMP() throws Exception {
         InetAddress[] inetAddresses = InetAddress.getAllByName("www.google.com");
         for (InetAddress ia : inetAddresses) {
-            // ICMP is not reliable, allow 5 attempts before failing.
-            assertTrue(ia.isReachableByICMP(5 * 1000 /* ICMP timeout */));
+            // ICMP is not reliable, allow 5 attempts to each IP address before failing.
+            // If any address is reachable then that's sufficient.
+            if (ia.isReachableByICMP(5 * 1000 /* ICMP timeout */)) {
+                return;
+            }
         }
+        fail();
+    }
 
+    @Test
+    public void test_inUnreachable() throws Exception {
         // IPv6 discard prefix. RFC 6666.
         final InetAddress blackholeAddress = InetAddress.getByName("100::1");
         assertFalse(blackholeAddress.isReachable(1000));
diff --git a/luni/src/test/java/libcore/java/util/AbstractListTest.java b/luni/src/test/java/libcore/java/util/AbstractListTest.java
new file mode 100644
index 0000000..e0c4db2
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/AbstractListTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2020 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.java.util;
+
+import junit.framework.AssertionFailedError;
+
+import org.junit.Test;
+
+import java.util.AbstractList;
+import java.util.AbstractSequentialList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.RandomAccess;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class AbstractListTest {
+    @Test public void sublist_outOfBounds() {
+        assertSubListOutOfBounds(new RandomAccessList(/* size */ 0), 0, 1);
+        assertSubListOutOfBounds(new RandomAccessList(/* size */ 10), 0, 11);
+        assertSubListOutOfBounds(new RandomAccessList(/* size */ 10), -1, 10);
+        assertSubListOutOfBounds(new RandomAccessList(/* size */ 10), -1, 11);
+
+        assertSubListOutOfBounds(new SequentialList(/* elements */), 0, 1);
+        assertSubListOutOfBounds(new SequentialList(/* elements */ 10, 20, 30), 0, 4);
+        assertSubListOutOfBounds(new SequentialList(/* elements */ 10, 20, 30), -1, 3);
+
+        // These ones work
+        new RandomAccessList(/* size */ 0).subList(0, 0);
+        new RandomAccessList(/* size */ 10).subList(0, 10);
+        new RandomAccessList(/* size */ 10).subList(2, 5);
+        new SequentialList(/* elements */).subList(0, 0);
+        new SequentialList(/* elements */ 10, 20, 30).subList(0, 3);
+    }
+
+    private static<T> void assertSubListOutOfBounds(List<T> list, int startIndex, int endIndex) {
+        try {
+            list.subList(startIndex, endIndex);
+            fail();
+        } catch (IndexOutOfBoundsException expected) {
+        }
+    }
+
+    /** Checks that list.spliterator() is late-binding. */
+    @Test public void spliterator_lateBinding() {
+        List<Integer> list = new RandomAccessList(50);
+        Spliterator<Integer> spliterator = list.spliterator();
+        Integer newFirstValue = list.get(0) + 3000;
+        list.add(0, newFirstValue); // prepend
+        AtomicReference<Integer> receivedValue = new AtomicReference<>(null);
+        // No ConcurrentModificationException because of late-binding Spliterator
+        boolean didAdvance = spliterator.tryAdvance(value -> receivedValue.set(value));
+        // Expect the values at index 0 from after the add(), not from after the spliterator().
+        assertEquals(newFirstValue, receivedValue.get());
+        assertTrue(didAdvance);
+    }
+
+    @Test public void spliterator_modification_failFast() {
+        List<Integer> list = new RandomAccessList(50);
+        Integer expectedValue = list.get(2);
+        Spliterator<Integer> spliterator = list.spliterator();
+        // We need to perform at least one action on the spliterator because only then does
+        // it initialize its internal expectedModCount.
+        assertTrue(spliterator.tryAdvance(value -> {}));
+        assertTrue(spliterator.tryAdvance(value -> {}));
+        list.add(42); // concurrent modification
+        AtomicReference<Integer> receivedValue = new AtomicReference<>(null);
+        try {
+            spliterator.tryAdvance(value -> receivedValue.set(value));
+            fail();
+        } catch (ConcurrentModificationException expected) {
+        }
+        // I believe it would also be within spec for this to remain unset (null),
+        // but the current implementation checks for concurrent modification only after
+        // delivering the value. We're asserting that so that we notice if the behavior
+        // ever changes in future.
+        assertEquals(expectedValue, receivedValue.get());
+    }
+
+    @Test public void spliteratorOfRandomAccessList_usesOnlyRandomAccess() {
+        checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(0);
+        checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(1);
+        checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(2);
+        checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(100);
+    }
+
+    private static void checkSpliteratorOfOnlyRandomAccessList_usesOnlyRandomAccess(int listSize) {
+        checkSpliteratorOfRandomAccessList(listSize,
+                () -> new OnlyRandomAccessList(listSize));
+        int subListSize = listSize / 2;
+        checkSpliteratorOfRandomAccessList(
+                subListSize,
+                () -> new OnlyRandomAccessList(listSize).subList(0, subListSize));
+    }
+
+    /**
+     * Checks basic operations on supplied RandomAccess Lists. If the supplied Lists are
+     * {@link OnlyRandomAccessList} or its sublists, then that has the side-effect of
+     * checking that only random-access operations are attempted.
+     */
+    // We're using a Supplier<List> to keep constructing new Lists because some of the testers
+    // have the side effect of sorting the List.
+    private static void checkSpliteratorOfRandomAccessList(int size,
+            Supplier<List<Integer>> listSupplier) {
+        assertTrue(listSupplier.get() instanceof RandomAccess);
+        assertEquals(size, listSupplier.get().size());
+
+        Supplier<Spliterator<Integer>> spliteratorSupplier = () -> listSupplier.get().spliterator();
+        List<Integer> expectedList = new ArrayList<>();
+        for (int index = 0; index < size; index++) {
+            expectedList.add(RandomAccessList.initialValue(index));
+        }
+
+        SpliteratorTester.runBasicIterationTests(spliteratorSupplier.get(), expectedList);
+        SpliteratorTester.runBasicSplitTests(spliteratorSupplier.get(), expectedList,
+                Comparator.naturalOrder());
+        SpliteratorTester.testSpliteratorNPE(spliteratorSupplier.get());
+
+        assertTrue(spliteratorSupplier.get().hasCharacteristics(
+                Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED));
+
+        SpliteratorTester.runSizedTests(spliteratorSupplier.get(), size /* expected size */);
+        if (spliteratorSupplier.get().trySplit() != null) {
+            SpliteratorTester.runSubSizedTests(spliteratorSupplier.get(), size);
+        } else {
+            assertTrue(size <= 1); // trySplit() should work for lists sized > 1.
+        }
+    }
+
+    static class SequentialList extends AbstractSequentialList<Integer> {
+        private final List<Integer> delegate;
+
+        public SequentialList(Integer... elements) {
+            this.delegate = Collections.unmodifiableList(Arrays.asList(elements));
+        }
+
+        @Override public ListIterator<Integer> listIterator(int index) {
+            return delegate.listIterator(index);
+        }
+
+        @Override public int size() { return delegate.size(); }
+    }
+
+    /**
+     * A simple list that allows random-access {@code get()} and modifications. This
+     * implementation increases {@link AbstractList#modCount} during {@code add()}
+     * and {@code remove()} to provide fail-fast Spliterators.
+     */
+    static class RandomAccessList extends AbstractList<Integer> implements RandomAccess {
+        protected final List<Integer> delegate;
+
+        public RandomAccessList(int size) {
+            this.delegate = new ArrayList<>(size);
+            for (int i = 0; i < size; i++) {
+                delegate.add(initialValue(i));
+            }
+        }
+
+        static Integer initialValue(int index) { return 31337 ^ index; }
+
+        @Override public Integer get(int index) { return delegate.get(index); }
+        @Override public int size() { return delegate.size(); }
+        @Override public Integer set(int index, Integer v) { return delegate.set(index, v); }
+        @Override public void add(int index, Integer element) {
+            modCount++;
+            delegate.add(index, element);
+        }
+        @Override public Integer remove(int index) {
+            modCount++;
+            return delegate.remove(index);
+        }
+    }
+
+    /**
+     * A {@link RandomAccessList} that throws if a caller attempts {@link #iterator()
+     * iterative access}.
+     */
+    static class OnlyRandomAccessList extends RandomAccessList {
+        public OnlyRandomAccessList(int size) {
+            super(size);
+        }
+        @Override public Iterator<Integer> iterator() {
+            throw new AssertionFailedError();
+        }
+
+        @Override public ListIterator<Integer> listIterator(int index) {
+            throw new AssertionFailedError();
+        }
+
+    }
+
+}
diff --git a/luni/src/test/java/libcore/java/util/ListOfTest.java b/luni/src/test/java/libcore/java/util/ListOfTest.java
new file mode 100644
index 0000000..04b787f
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/ListOfTest.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 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.java.util;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.RandomAccess;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import libcore.libcore.util.SerializationTester;
+import libcore.util.NonNull;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class ListOfTest {
+
+    @Test
+    public void serializationCompatibility_empty() {
+        String golden = "ACED00057372001F6A6176612E7574696C2E436F6C6C656374696F6E7324456D7074794C69"
+                + "73747AB817B43CA79EDE0200007870";
+        new SerializationTester<>(List.<String>of(), golden).test();
+    }
+
+    @Test public void serializationCompatibility_oneElement() {
+        String golden = "ACED0005737200266A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654C697374FC0F2531B5EC8E100200014C00046C6973747400104C6A6176612F7574696C"
+                + "2F4C6973743B7872002C6A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F64696669"
+                + "61626C65436F6C6C656374696F6E19420080CB5EF71E0200014C0001637400164C6A6176612F7574"
+                + "696C2F436F6C6C656374696F6E3B7870737200136A6176612E7574696C2E41727261794C69737478"
+                + "81D21D99C7619D03000149000473697A657870000000017704000000017400036F6E657871007E00"
+                + "06";
+        new SerializationTester<>(List.of("one"), golden).test();
+    }
+
+    @Test public void serializationCompatibility_manyElements() {
+        String golden = "ACED0005737200266A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654C697374FC0F2531B5EC8E100200014C00046C6973747400104C6A6176612F7574696C"
+                + "2F4C6973743B7872002C6A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F64696669"
+                + "61626C65436F6C6C656374696F6E19420080CB5EF71E0200014C0001637400164C6A6176612F7574"
+                + "696C2F436F6C6C656374696F6E3B7870737200136A6176612E7574696C2E41727261794C69737478"
+                + "81D21D99C7619D03000149000473697A6578700000000D77040000000D737200116A6176612E6C61"
+                + "6E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C61"
+                + "6E672E4E756D62657286AC951D0B94E08B02000078700000000C7371007E00070000000B7371007E"
+                + "00070000000A7371007E0007000000097371007E0007000000087371007E0007000000077371007E"
+                + "0007000000067371007E0007000000057371007E0007000000047371007E0007000000037371007E"
+                + "0007000000027371007E0007000000017371007E0007000000007871007E0006";
+        new SerializationTester<>(List.of(12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), golden).test();
+    }
+
+    @Test public void mixedTypes() {
+        List<?> list = List.of("element", 42);
+        assertEquals(asList("element", 42), list);
+
+        assertTrue(list.contains("element"));
+        assertTrue(list.contains(42));
+        assertFalse(list.contains(new Object()));
+        assertFalse(list.contains(31));
+    }
+
+    @Test public void duplicates_allowed() {
+        // duplicates values are allowed for List.of(), but not for Set.of()
+        check_nonEmpty(asList("duplicate", "duplicate"), List.of("duplicate", "duplicate"));
+    }
+
+    @Test public void empty() {
+        assertBehaviorCommonToAllOfInstances(
+                Collections.<String>emptyList(), List.<String>of(), "non-null example String");
+    }
+
+    @Test public void nonEmpty() {
+        check_nonEmpty(asList("one"), List.of("one"));
+        check_nonEmpty(asList("one", "two"), List.of("one", "two"));
+        check_nonEmpty(asList("one", "two", "three"), List.of("one", "two", "three"));
+        check_nonEmpty(asList("one", "two", "three", "four"),
+                List.of("one", "two", "three", "four"));
+        check_nonEmpty(asList("one", "two", "three", "four", "five"),
+                List.of("one", "two", "three", "four", "five"));
+        check_nonEmpty(asList("one", "two", "three", "four", "five", "six"),
+                List.of("one", "two", "three", "four", "five", "six"));
+        check_nonEmpty(asList("one", "two", "three", "four", "five", "six", "seven"),
+                List.of("one", "two", "three", "four", "five", "six", "seven"));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8), List.of(1, 2, 3, 4, 5, 6, 7, 8));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9), List.of(1, 2, 3, 4, 5, 6, 7, 8, 9));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
+                List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
+                List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
+                List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
+        check_nonEmpty(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+                List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13));
+    }
+
+    @Test public void null_examples() {
+        assertThrowsNpe(() -> List.<String>of((String) null)); // one-arg version
+        assertThrowsNpe(() -> List.<String[]>of((String[]) null)); // null var-args array
+        assertThrowsNpe(() -> List.<String>of(new String[] { "one", null, "three"})); // var-args
+
+        assertThrowsNpe(() -> List.of(null, "two"));
+        assertThrowsNpe(() -> List.of("one", null));
+        assertThrowsNpe(
+                () -> List.of(null, "two", "three", "four", "five", "six", "seven"));
+        assertThrowsNpe(
+                () -> List.of("one", "two", "three", "four", "five", "six", null));
+    }
+
+    @Test public void null_comprehensive() {
+        List<Integer> template = asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+        for (int i = 0; i < template.size(); i++) {
+            Integer[] l = template.toArray(new Integer[0]);
+            l[i] = null;
+            npe(i <= 0, () -> List.of(l[0]));
+            npe(i <= 1, () -> List.of(l[0], l[1]));
+            npe(i <= 2, () -> List.of(l[0], l[1], l[2]));
+            npe(i <= 3, () -> List.of(l[0], l[1], l[2], l[3]));
+            npe(i <= 4, () -> List.of(l[0], l[1], l[2], l[3], l[4]));
+            npe(i <= 5, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5]));
+            npe(i <= 6, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6]));
+            npe(i <= 7, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7]));
+            npe(i <= 8, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8]));
+            npe(i <= 9, () -> List.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9]));
+            npe(i <= 10, () -> List.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10]));
+            npe(i <= 11, () -> List.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10], l[11]));
+            npe(i <= 12, () -> List.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10], l[11], l[12])
+            );
+        }
+    }
+
+    /**
+     * Asserts that {@code runnable.run()} throws {@link NullPointerException} if
+     * any only if {@code expectedToThrowNpe}.
+     */
+    private static void npe(boolean expectedToThrowNpe, Runnable runnable) {
+        if (expectedToThrowNpe) {
+            assertThrowsNpe(runnable);
+        } else {
+            runnable.run(); // should not throw
+        }
+    }
+
+    private static<T extends Comparable<T>> void check_nonEmpty(List<T> expected, List<T> actual) {
+        T example = actual.iterator().next();
+        assertBehaviorCommonToAllOfInstances(expected, actual, example);
+    }
+
+    /** Checks assertions that hold for all List.of() instances. */
+    private static<T extends Comparable<T>> void assertBehaviorCommonToAllOfInstances(
+            List<T> expected, List<T> actual, @NonNull T example) {
+        assertNotNull(example);
+        assertEquals(expected, actual);
+        assertEquals(expected.size(), actual.size());
+        assertEquals(expected.hashCode(), actual.hashCode());
+        assertEquals(actual.isEmpty(), actual.isEmpty());
+        assertEquals(actual.size() == 0, actual.isEmpty());
+        SpliteratorTester.runBasicIterationTests(actual.spliterator(), expected);
+        if (expected.isEmpty()) {
+            assertEquals(expected, actual.subList(0, 0));
+        } else {
+            assertEquals(expected.subList(1, expected.size()), actual.subList(1, actual.size()));
+        }
+        assertEquals(expected.contains(example), actual.contains(example));
+        assertFalse(actual.contains("absent-element"));
+        assertFalse(actual.contains(new Object()));
+        assertThrowsNpe(() -> actual.contains(null));
+        assertEquals(expected.toString(), actual.toString());
+
+        assertUnmodifiable(actual, example);
+        assertEquals(actual, reserialize((Serializable) actual));
+        assertTrue(actual instanceof RandomAccess);
+    }
+
+    private static<T extends Comparable<T>> void assertUnmodifiable(List<T> list, T example) {
+        List<T> examples = Collections.singletonList(example);
+        assertThrowsUoe(() -> { list.add(example); } );
+        assertThrowsUoe(() -> { list.addAll(examples); } );
+        assertThrowsUoe(() -> { list.addAll(0, examples); } );
+        // List.of() documentation guarantees that the following operations throw
+        // UnsupportedOperationException, even though some other implementations don't
+        // do that in the case of isEmpty().
+        assertThrowsUoe(() -> { list.clear(); });
+        assertThrowsUoe(() -> { list.remove(example); } );
+        assertThrowsUoe(() -> { list.removeAll(examples); } );
+        assertThrowsUoe(() -> { list.removeIf(Predicate.isEqual(example)); } );
+        assertThrowsUoe(() -> { list.replaceAll(UnaryOperator.identity()); } );
+        assertThrowsUoe(() -> { list.retainAll(examples); } );
+        assertThrowsUoe(() -> { list.sort(Comparator.<T>naturalOrder()); } );
+    }
+
+    private static void assertThrowsUoe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    private static void assertThrowsNpe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+
+    private static <S extends Serializable> S reserialize(S value) {
+        try {
+            return (S) SerializationTester.reserialize(value);
+        } catch (IOException | ClassNotFoundException e) {
+            fail("Unexpected exception: " + e.getMessage());
+            throw new AssertionError(e); // unreachable
+        }
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/MapOfTest.java b/luni/src/test/java/libcore/java/util/MapOfTest.java
new file mode 100644
index 0000000..68e20a7
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/MapOfTest.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2020 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.java.util;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import libcore.libcore.util.SerializationTester;
+
+import static java.util.Map.entry;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@code Map.of()} overloads and {@code Map.ofEntries(...)}.
+ */
+@RunWith(Parameterized.class)
+public class MapOfTest {
+
+    @Test public void serializationCompatibility_empty() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654D6170F1A5A8FE74F507420200014C00016D74000F4C6A6176612F7574696C2F4D6170"
+                + "3B7870737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F"
+                + "6164466163746F724900097468726573686F6C6478703F4000000000000177080000000100000000"
+                + "78";
+        new SerializationTester<>(create(), golden).test();
+    }
+
+    @Test public void serializationCompatibility_oneElement() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654D6170F1A5A8FE74F507420200014C00016D74000F4C6A6176612F7574696C2F4D6170"
+                + "3B7870737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F"
+                + "6164466163746F724900097468726573686F6C6478703F4000000000000177080000000200000001"
+                + "7400036F6E65737200116A6176612E6C616E672E496E746567657212E2A0A4F78187380200014900"
+                + "0576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000"
+                + "00000178";
+        new SerializationTester<>(create(entry("one", 1)), golden).test();
+    }
+
+    @Test public void serializationCompatibility_manyElements() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C654D6170F1A5A8FE74F507420200014C00016D74000F4C6A6176612F7574696C2F4D6170"
+                + "3B7870737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F"
+                + "6164466163746F724900097468726573686F6C6478703F4000000000000C7708000000100000000A"
+                + "7400046E696E65737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149"
+                + "000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870"
+                + "000000097400037369787371007E000600000006740004666F75727371007E000600000004740003"
+                + "6F6E657371007E000600000001740005736576656E7371007E00060000000774000374656E737100"
+                + "7E00060000000A74000374776F7371007E00060000000274000574687265657371007E0006000000"
+                + "03740004666976657371007E00060000000574000565696768747371007E00060000000878";
+        new SerializationTester<>(
+                create(entry("one", 1), entry("two", 2), entry("three", 3),
+                entry("four", 4), entry("five", 5), entry("six", 6), entry("seven", 7),
+                entry("eight", 8), entry("nine", 9), entry("ten", 10)), golden).test();
+    }
+
+    @Test public void duplicates_sameKey() {
+        Map.Entry[] entries = { entry("duplicateKey", 23), entry("duplicateKey", 42) };
+        assertThrowsIae(() -> creator.create(entries));
+    }
+
+    @Test public void duplicates_sameEntry() {
+        Map.Entry[] entries = { entry("duplicateKey", 42), entry("duplicateKey", 42) };
+        assertThrowsIae(() -> creator.create(entries));
+    }
+
+    @Test public void duplicates_manyElements() {
+        Map.Entry[] entries = {
+                entry("key1", 1),
+                entry("duplicateKey", 23),
+                entry("key2", 2),
+                entry("duplicateKey", 42) };
+        assertThrowsIae(() -> creator.create(entries));
+    }
+
+    @Test public void empty() {
+        assertBehaviorCommonToAllOfInstances("exampleKey", 42);
+    }
+
+    @Test public void nullEntries() {
+        assertThrowsNpe(() -> Map.ofEntries((Map.Entry[]) null));
+        assertThrowsNpe(() -> Map.ofEntries((Map.Entry) null));
+        List<Map.Entry<String, Integer>> sampleEntries = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            sampleEntries.add(entry("key" + i, i));
+        }
+        for (int size = 0; size <= sampleEntries.size(); size++) {
+            for (int nullIndex = 0; nullIndex < size; nullIndex++) {
+                Map.Entry[] entries = sampleEntries.subList(0, size).toArray(
+                        (Map.Entry<String, Integer>[]) new Map.Entry[0]);
+                entries[nullIndex] = null;
+                assertThrowsNpe(() -> Map.ofEntries(entries));
+            }
+        }
+    }
+
+    @Test public void oneEntry() {
+        assertBehaviorCommonToAllOfInstances(
+                "exampleKey", 42, entry("key", "value"));
+    }
+
+    @Test public void twoEntries() {
+        assertBehaviorCommonToAllOfInstances(
+                "exampleKey", 42, entry("key1", "value1"), entry("key2", "value2"));
+    }
+
+    @Test public void manyEntries() {
+        List<Map.Entry<String, Integer>> sampleEntries = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            sampleEntries.add(entry("key" + i, i));
+        }
+        for (int size = 0; size <= sampleEntries.size(); size++) {
+            Map.Entry[] entries = sampleEntries.subList(0, size).toArray(
+                    (Map.Entry<String, Integer>[]) new Map.Entry[0]);
+            assertBehaviorCommonToAllOfInstances("key0", 42, entries);
+        }
+    }
+
+    @Test public void entry_nullKeyOrValue() {
+        assertThrowsNpe(() -> entry(null, "value"));
+        assertThrowsNpe(() -> entry("key", null));
+        assertThrowsNpe(() -> entry(null, null));
+
+        // This one works
+        entry("key", "value");
+    }
+
+    @Test public void of_nullKeyOrValue() {
+        assertThrowsNpe(() -> Map.of(null, "value"));
+        assertThrowsNpe(() -> Map.of("key", null));
+        assertThrowsNpe(() -> Map.of("k1", "v1", "k2", "v2", null, "v3", "k4", "v4"));
+        assertThrowsNpe(() -> Map.of("k1", "v1", "k2", "v2", "k3", null, "k4", "v4"));
+    }
+
+    @Test public void mixedEntryTypes() {
+        assertBehaviorCommonToAllOfInstances(
+                "onekey", "new value", entry("oneKey", 1), entry(2, "twoValue"));
+    }
+
+    private static<K, V> void assertUnmodifiable(Map<K, V> map, K exampleKey, V exampleValue) {
+        Map<K, V> exampleEntries = Collections.singletonMap(exampleKey, exampleValue);
+        assertThrowsUoe(() -> map.put(exampleKey, exampleValue));
+        assertThrowsUoe(() -> map.putAll(exampleEntries));
+        assertThrowsUoe(() -> map.remove(exampleKey));
+        assertThrowsUoe(() -> map.remove(exampleKey, exampleValue));
+        assertThrowsUoe(() -> map.clear());
+        assertThrowsUoe(() -> map.replace(exampleKey, exampleValue, null));
+        assertThrowsUoe(() -> map.putIfAbsent(exampleKey, exampleValue));
+        assertThrowsUoe(() -> map.entrySet().clear());
+        assertThrowsUoe(() -> map.keySet().clear());
+        assertThrowsUoe(() -> map.values().clear());
+
+        if (!map.isEmpty()) {
+            Map.Entry<K, V> firstEntry = map.entrySet().iterator().next();
+            assertThrowsUoe(() -> firstEntry.setValue(exampleValue));
+        }
+    }
+
+    /** Checks assertions that hold for all Map.of() / Map.ofEntries() instances. */
+    private <K, V> void assertBehaviorCommonToAllOfInstances(K exampleKey, V exampleValue,
+            Map.Entry<K, V>...entries) {
+        Map<K, V> expected = hashMapOf(entries);
+        Map<K, V> actual = creator.create(entries);
+        assertBehaviorCommonToAllOfInstances(expected, actual, exampleKey, exampleValue);
+    }
+
+    private static<K, V> void assertBehaviorCommonToAllOfInstances(Map<K, V> expected,
+            Map<K, V> actual, K exampleKey, V exampleValue) {
+        assertDoesNotSupportNull(actual);
+        assertMapEquals(expected, actual);
+        assertUnmodifiable(actual, exampleKey, exampleValue);
+    }
+
+    private static<K, V> void assertDoesNotSupportNull(Map<K, V> map) {
+        assertThrowsNpe(() -> map.containsKey(null));
+        assertThrowsNpe(() -> map.keySet().contains(null));
+        assertThrowsNpe(() -> map.values().contains(null));
+    }
+
+    private static<K, V> void assertMapEquals(Map<K, V> expected, Map<K, V> actual) {
+        assertEquals(expected, actual);
+        assertEquals(actual, expected);
+        assertEquals(expected.size(), actual.size());
+        assertEquals(expected.entrySet(), actual.entrySet());
+
+        assertSetEquals(expected.entrySet(), actual.entrySet());
+        assertSetEquals(expected.keySet(), actual.keySet());
+        assertCollectionEquals(new HashSet<>(expected.values()), new HashSet<>(actual.values()));
+    }
+
+    private static<T> void assertSetEquals(Set<T> expected, Set<T> actual) {
+        assertCollectionEquals(expected, actual);
+    }
+
+    private static<T> void assertCollectionEquals(Collection<T> expected, Collection<T> actual) {
+        assertEquals(expected, actual);
+        assertEquals(actual, expected);
+        assertEquals(expected.hashCode(), actual.hashCode());
+
+        assertEquals(expected.size(), actual.size());
+        assertTrue(expected.containsAll(actual));
+        assertTrue(actual.containsAll(expected));
+    }
+
+    private final Creator creator;
+
+    public MapOfTest(Creator creator) {
+        this.creator = Objects.requireNonNull(creator);
+    }
+
+    private<K, V> Map<K, V> create(Map.Entry<K, V>... entries) {
+        return creator.create(entries);
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Creator> getCreators() {
+        return Arrays.asList(Creator.OF, Creator.OF_ENTRIES);
+    }
+
+    private static<K, V> Map<K, V> hashMapOf(Map.Entry<K, V>... entries) {
+        HashMap<K, V> result = new HashMap<>();
+        for (Map.Entry<K, V> entry : entries) {
+            result.put(entry.getKey(), entry.getValue());
+        }
+        return result;
+    }
+
+    enum Creator {
+        OF {
+            private<K,V> K k(int index, Map.Entry<K, V>... entries) {
+                return entries[index].getKey();
+            }
+            private<K,V> V v(int index, Map.Entry<K, V>... entries) {
+                return entries[index].getValue();
+            }
+
+            @Override
+            <K, V> Map<K, V> create(Map.Entry<K, V>... e) {
+                switch (e.length) {
+                    case 0: return Map.of();
+                    case 1: return Map.of(k(0, e), v(0, e));
+                    case 2: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e));
+                    case 3: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e));
+                    case 4: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e));
+                    case 5: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e));
+                    case 6: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e));
+                    case 7: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e), k(6, e), v(6, e));
+                    case 8: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e), k(6, e), v(6, e), k(7, e), v(7, e));
+                    case 9: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e), k(6, e), v(6, e), k(7, e), v(7, e), k(8, e), v(8, e));
+                   case 10: return Map.of(k(0, e), v(0, e), k(1, e), v(1, e), k(2, e), v(2, e), k(3, e), v(3, e), k(4, e), v(4, e), k(5, e), v(5, e), k(6, e), v(6, e), k(7, e), v(7, e), k(8, e), v(8, e), k(9, e), v(9, e));
+                    default:
+                        fail(this + " requires 0 to 10 entries");
+                        throw new AssertionError("unreachable");
+                }
+
+            }
+        },
+        OF_ENTRIES {
+            @Override
+            <K, V> Map<K, V> create(Map.Entry<K, V>... entries) {
+                return Map.ofEntries(entries);
+            }
+        }
+        ;
+        abstract <K,V> Map<K, V> create(Map.Entry<K,V>... entries);
+    }
+
+    private static void assertThrowsIae(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    private static void assertThrowsUoe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    private static void assertThrowsNpe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+}
diff --git a/luni/src/test/java/libcore/java/util/ObjectsTest.java b/luni/src/test/java/libcore/java/util/ObjectsTest.java
index 735f6c5..6e118e9 100644
--- a/luni/src/test/java/libcore/java/util/ObjectsTest.java
+++ b/luni/src/test/java/libcore/java/util/ObjectsTest.java
@@ -25,6 +25,111 @@
     public String toString() { return "hello"; }
   }
 
+  public void test_checkFromIndexSize_valid() {
+    Objects.checkFromIndexSize(/* fromIndex */ 0, /* size */ 0, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 10, /* size */ 0, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 5, /* size */ 1, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 0, /* size */ 10, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 1, /* size */ 9, /* length */ 10);
+    Objects.checkFromIndexSize(/* fromIndex */ 0, /* size */ 9, /* length */ 10);
+  }
+
+  public void test_checkFromIndexSize_negativeSize() {
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ -1, /* size */ 10, /* length */ 100);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 5, /* size */ -1, /* length */ 100);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 0, /* size */ -1, /* length */ 100);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 0, /* size */ -1, /* length */ -1);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 0, /* size */ 0, /* length */ -1);
+  }
+
+  public void test_checkFromIndexSize_beyondEnd() {
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 0, /* size */ 10, /* length */ 9);
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ 1, /* size */ 10, /* length */ 10);
+
+    // Invalid, but fromIndex + size overflows and is < length.
+    assertFromIndexSizeOutOfBounds(/* fromIndex */ Integer.MAX_VALUE - 10, /* size */ 11,
+            /* length */ Integer.MAX_VALUE);
+  }
+
+  private static void assertFromIndexSizeOutOfBounds(int fromIndex, int size, int length) {
+    try {
+      Objects.checkFromIndexSize(fromIndex, size, length);
+      fail();
+    } catch (IndexOutOfBoundsException expected) {
+    }
+  }
+
+  public void test_checkFromToIndex_valid() {
+    Objects.checkFromToIndex(/* fromIndex */ 0, /* toIndex */ 0, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 10, /* toIndex */ 10, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 5, /* toIndex */ 6, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 0, /* toIndex */ 10, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 1, /* toIndex */ 10, /* length */ 10);
+    Objects.checkFromToIndex(/* fromIndex */ 0, /* toIndex */ 0, /* length */ 10);
+  }
+
+  public void test_checkFromToIndex_negativeSize() {
+    assertFromToIndexOutOfBounds(/* fromIndex */ -1, /* toIndex */ 9, /* length */ 100);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 5, /* toIndex */ 4, /* length */ 100);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 0, /* toIndex */ -1, /* length */ 100);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 0, /* toIndex */ -1, /* length */ -1);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 0, /* toIndex */ 0, /* length */ -1);
+  }
+
+  public void test_checkFromToIndex_beyondEnd() {
+    assertFromToIndexOutOfBounds(/* fromIndex */ 0, /* toIndex */ 10, /* length */ 9);
+    assertFromToIndexOutOfBounds(/* fromIndex */ 1, /* toIndex */ 11, /* length */ 10);
+    assertFromToIndexOutOfBounds(/* fromIndex */ Integer.MAX_VALUE - 10,
+            /* toIndex */ Integer.MIN_VALUE, /* length */ Integer.MAX_VALUE);
+  }
+
+  private static void assertFromToIndexOutOfBounds(int fromIndex, int toIndex, int length) {
+    try {
+      Objects.checkFromToIndex(fromIndex, toIndex, length);
+      fail();
+    } catch (IndexOutOfBoundsException expected) {
+    }
+  }
+
+  public void test_checkIndex_empty() {
+    assertIndexOutOfBounds(0, 0);
+    assertIndexOutOfBounds(1, 0);
+    assertIndexOutOfBounds(-1, 0);
+    assertIndexOutOfBounds(100, 0);
+    assertIndexOutOfBounds(-100, 0);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, 0);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, 0);
+  }
+
+  public void test_checkIndex_size1() {
+    Objects.checkIndex(0, 1);
+    assertIndexOutOfBounds(1, 1);
+    assertIndexOutOfBounds(-1, 1);
+    assertIndexOutOfBounds(100, 1);
+    assertIndexOutOfBounds(-100, 1);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, 1);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, 1);
+  }
+
+  public void test_checkIndex_largeSize() {
+    Objects.checkIndex(0, 100);
+    Objects.checkIndex(99, 100);
+    Objects.checkIndex(100, Integer.MAX_VALUE);
+    Objects.checkIndex(Integer.MAX_VALUE - 1, Integer.MAX_VALUE);
+    assertIndexOutOfBounds(-1, 100);
+    assertIndexOutOfBounds(100, 100);
+    assertIndexOutOfBounds(Integer.MAX_VALUE, Integer.MAX_VALUE);
+    assertIndexOutOfBounds(-1, Integer.MAX_VALUE);
+  }
+
+  private static void assertIndexOutOfBounds(int index, int length) {
+    try {
+      Objects.checkIndex(index, length);
+      fail();
+    } catch (IndexOutOfBoundsException expected) {
+    }
+  }
+
   public void test_compare() throws Exception {
     assertEquals(0, Objects.compare(null, null, String.CASE_INSENSITIVE_ORDER));
     assertEquals(0, Objects.compare("a", "A", String.CASE_INSENSITIVE_ORDER));
@@ -121,6 +226,10 @@
     } catch (NullPointerException expected) {
     }
 
+    // This does not currently throw. The presence of this test ensures that any
+    // future behavior change is deliberate.
+    assertEquals(h, Objects.requireNonNull(h, (Supplier<String>) null));
+
     // The message returned by the supplier is null.
     try {
       Objects.requireNonNull(null, () -> null);
@@ -130,6 +239,35 @@
     }
   }
 
+  public void test_requireNonNullElse() {
+    assertEquals("obj", Objects.requireNonNullElse("obj", "default"));
+    assertEquals("default", Objects.requireNonNullElse(null, "default"));
+    assertEquals("obj", Objects.requireNonNullElse("obj", null));
+    assertThrowsNpe(() -> Objects.requireNonNullElse(null, null));
+  }
+
+  public void test_requireNonNullElseGet_obj() {
+    assertEquals("obj", Objects.requireNonNullElseGet("obj", () -> "default"));
+    // null supplier / supplier that returns null is tolerated when obj != null.
+    assertEquals("obj", Objects.requireNonNullElseGet("obj", () -> null));
+    assertEquals("obj", Objects.requireNonNullElseGet("obj", null));
+  }
+
+  public void test_requireNonNullElseGet_nullObj() {
+    assertEquals("default", Objects.requireNonNullElseGet(null, () -> "default"));
+    // null supplier and supplier of null both throw.
+    assertThrowsNpe(() -> Objects.requireNonNullElseGet(null, (Supplier<?>) () -> null));
+    assertThrowsNpe(() -> Objects.requireNonNullElse(null, null));
+  }
+
+  private static void assertThrowsNpe(Runnable runnable) {
+    try {
+      runnable.run();
+      fail();
+    } catch (NullPointerException expected) {
+    }
+  }
+
   public void test_toString_Object() throws Exception {
     assertEquals("hello", Objects.toString(new Hello()));
     assertEquals("null", Objects.toString(null));
diff --git a/luni/src/test/java/libcore/java/util/SetOfTest.java b/luni/src/test/java/libcore/java/util/SetOfTest.java
new file mode 100644
index 0000000..86dfc74
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/SetOfTest.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2020 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.java.util;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+import libcore.libcore.util.SerializationTester;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class SetOfTest {
+
+    @Test public void of_serializationCompatibility_empty() {
+        String golden = "ACED00057372001E6A6176612E7574696C2E436F6C6C656374696F6E7324456D7074795365"
+                + "7415F5721DB403CB280200007870";
+        new SerializationTester<>(Set.<String>of(), golden).test();
+    }
+
+    @Test public void of_serializationCompatibility_oneElement() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C65536574801D92D18F9B80550200007872002C6A6176612E7574696C2E436F6C6C656374"
+                + "696F6E7324556E6D6F6469666961626C65436F6C6C656374696F6E19420080CB5EF71E0200014C00"
+                + "01637400164C6A6176612F7574696C2F436F6C6C656374696F6E3B7870737200116A6176612E7574"
+                + "696C2E48617368536574BA44859596B8B7340300007870770C000000023F40000000000001740003"
+                + "6F6E6578";
+        new SerializationTester<>(Set.of("one"), golden).test();
+    }
+
+    @Test public void of_serializationCompatibility_manyElements() {
+        String golden = "ACED0005737200256A6176612E7574696C2E436F6C6C656374696F6E7324556E6D6F646966"
+                + "6961626C65536574801D92D18F9B80550200007872002C6A6176612E7574696C2E436F6C6C656374"
+                + "696F6E7324556E6D6F6469666961626C65436F6C6C656374696F6E19420080CB5EF71E0200014C00"
+                + "01637400164C6A6176612F7574696C2F436F6C6C656374696F6E3B7870737200116A6176612E7574"
+                + "696C2E48617368536574BA44859596B8B7340300007870770C000000203F4000000000000D737200"
+                + "116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200"
+                + "106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000000007371007E0006"
+                + "000000017371007E0006000000027371007E0006000000037371007E0006000000047371007E0006"
+                + "000000057371007E0006000000067371007E0006000000077371007E0006000000087371007E0006"
+                + "000000097371007E00060000000A7371007E00060000000B7371007E00060000000C78";
+        new SerializationTester<>(Set.of(12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), golden).test();
+    }
+
+    @Test public void mixedTypes() {
+        Set<?> list = Set.of("element", 42);
+        assertEquals(asSet("element", 42), list);
+
+        assertTrue(list.contains("element"));
+        assertTrue(list.contains(42));
+        assertFalse(list.contains(new Object()));
+        assertFalse(list.contains(31));
+    }
+
+    @Test public void duplicate() {
+        assertThrowsIae(() -> { Set.of("duplicate", "duplicate"); });
+        assertThrowsIae(() -> { Set.of("duplicate", "duplicate", "duplicate"); });
+        assertThrowsIae(() -> { Set.of("a", "duplicate", "duplicate"); });
+        assertThrowsIae(() -> {
+            Set.of("a", "duplicate", "b", "c", "d", "e", "f", "g", "duplicate");
+        });
+        assertThrowsIae(() -> { Set.of("a", "duplicate", "b", "c", "d", "e", "f", "g",
+                "duplicate", "h", "i", "j", "k", "l"); });
+    }
+
+    /**
+     * Checks that when there is both a duplicate and null, the exception that is thrown
+     * depends on which occurs first.
+     */
+    @Test public void duplicateAndNull() {
+        assertThrowsNpe(() -> { Set.of("duplicate", null, "duplicate"); }); // null first
+        assertThrowsIae(() -> { Set.of("duplicate", "duplicate", null); }); // duplicate first
+    }
+
+    @Test public void empty() {
+        check_commonBehavior(Collections.<String>emptySet(), Set.<String>of(), "non-null example");
+    }
+
+    @Test public void nonEmpty() {
+        check_nonEmpty(asSet("one"), Set.of("one"));
+        check_nonEmpty(asSet("one", "two"), Set.of("one", "two"));
+        check_nonEmpty(asSet("one", "two", "three"), Set.of("one", "two", "three"));
+        check_nonEmpty(asSet("one", "two", "three", "four"),
+                Set.of("one", "two", "three", "four"));
+        check_nonEmpty(asSet("one", "two", "three", "four", "five"),
+                Set.of("one", "two", "three", "four", "five"));
+        check_nonEmpty(asSet("one", "two", "three", "four", "five", "six"),
+                Set.of("one", "two", "three", "four", "five", "six"));
+        check_nonEmpty(asSet("one", "two", "three", "four", "five", "six", "seven"),
+                Set.of("one", "two", "three", "four", "five", "six", "seven"));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8), Set.of(1, 2, 3, 4, 5, 6, 7, 8));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9), Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
+                Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
+                Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
+                Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
+        check_nonEmpty(asSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
+                Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13));
+    }
+
+    @Test public void null_examples() {
+        assertThrowsNpe(() -> List.<String>of((String) null)); // one-arg version
+        assertThrowsNpe(() -> List.<String[]>of((String[]) null)); // null var-args array
+        assertThrowsNpe(() -> List.<String>of(new String[] { "one", null, "three"})); // var-args
+
+        assertThrowsNpe(() -> Set.of(null, "two"));
+        assertThrowsNpe(() -> Set.of("one", null));
+        assertThrowsNpe(
+                () -> Set.of(null, "two", "three", "four", "five", "six", "seven"));
+        assertThrowsNpe(
+                () -> Set.of("one", "two", "three", "four", "five", "six", null));
+    }
+
+    @Test public void null_comprehensive() {
+        Set<Integer> template = asSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+        for (int i = 0; i < template.size(); i++) {
+            Integer[] l = template.toArray(new Integer[0]);
+            l[i] = null;
+            npe(i <= 0, () -> Set.of(l[0]));
+            npe(i <= 1, () -> Set.of(l[0], l[1]));
+            npe(i <= 2, () -> Set.of(l[0], l[1], l[2]));
+            npe(i <= 3, () -> Set.of(l[0], l[1], l[2], l[3]));
+            npe(i <= 4, () -> Set.of(l[0], l[1], l[2], l[3], l[4]));
+            npe(i <= 5, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5]));
+            npe(i <= 6, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6]));
+            npe(i <= 7, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7]));
+            npe(i <= 8, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8]));
+            npe(i <= 9, () -> Set.of(l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9]));
+            npe(i <= 10, () -> Set.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10]));
+            npe(i <= 11, () -> Set.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10], l[11]));
+            npe(i <= 12, () -> Set.of(
+                    l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7], l[8], l[9], l[10], l[11], l[12])
+            );
+        }
+    }
+
+    /**
+     * Asserts that {@code runnable.run()} throws {@link NullPointerException} if
+     * any only if {@code expectedToThrowNpe}.
+     */
+    private static void npe(boolean expectedToThrowNpe, Runnable runnable) {
+        if (expectedToThrowNpe) {
+            assertThrowsNpe(runnable);
+        } else {
+            runnable.run(); // should not throw
+        }
+    }
+
+    private static<T extends Comparable<T>> void check_nonEmpty(Set<T> expected, Set<T> actual) {
+        T example = actual.iterator().next();
+        check_commonBehavior(expected, actual, example);
+    }
+
+    /** Checks assertions that hold for all Set.of() instances. */
+    private static<T extends Comparable<T>> void check_commonBehavior(
+            Set<T> expected, Set<T> actual, T nonNullExample) {
+        assertNotNull(nonNullExample);
+        assertEquals(expected, actual);
+        assertEquals(expected.size(), actual.size());
+        assertEquals(expected.hashCode(), actual.hashCode());
+        assertEquals(actual.isEmpty(), actual.isEmpty());
+        assertEquals(actual.size() == 0, actual.isEmpty());
+        assertEquals(expected.contains(nonNullExample), actual.contains(nonNullExample));
+        assertFalse(actual.contains("absent-element"));
+        assertFalse(actual.contains(new Object()));
+        assertThrowsNpe(() -> actual.contains(null));
+
+        assertUnmodifiable(actual, nonNullExample);
+        assertEquals(actual, reserialize((Serializable) actual));
+    }
+
+    private static<T extends Comparable<T>> void assertUnmodifiable(Set<T> set, T example) {
+        Set<T> examples = Collections.singleton(example);
+        assertTrue(throwsUoe(() -> { set.add(example); } ));
+        assertTrue(throwsUoe(() -> { set.addAll(examples); } ));
+        // List.of() documentation guarantees that the following operations throw
+        // UnsupportedOperationException, even though some other implementations don't
+        // do that in the case of isEmpty().
+        assertTrue(throwsUoe(() -> { set.clear(); }));
+        assertTrue(throwsUoe(() -> { set.remove(example); } ));
+        assertTrue(throwsUoe(() -> { set.removeAll(examples); } ));
+        assertTrue(throwsUoe(() -> { set.removeIf(Predicate.isEqual(example)); } ));
+        assertTrue(throwsUoe(() -> { set.retainAll(examples); } ));
+    }
+
+    private static boolean throwsUoe(Runnable runnable) {
+        try {
+            runnable.run();
+            return false;
+        } catch (UnsupportedOperationException tolerated) {
+            return  true;
+        }
+    }
+
+    private static void assertThrowsIae(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    private static void assertThrowsNpe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+
+    private static <S extends Serializable> S reserialize(S value) {
+        try {
+            return (S) SerializationTester.reserialize(value);
+        } catch (IOException | ClassNotFoundException e) {
+            fail("Unexpected exception: " + e.getMessage());
+            throw new AssertionError(e); // unreachable
+        }
+    }
+
+    private static<T> Set<T> asSet(T... values) {
+        return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(values)));
+    }
+
+}
diff --git a/luni/src/test/java/libcore/libcore/timezone/TimeZoneDataFilesTest.java b/luni/src/test/java/libcore/libcore/timezone/TimeZoneDataFilesTest.java
index 282b18e..a74ba30 100644
--- a/luni/src/test/java/libcore/libcore/timezone/TimeZoneDataFilesTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/TimeZoneDataFilesTest.java
@@ -28,10 +28,12 @@
 
     private static final String ANDROID_TZDATA_ROOT_ENV = "ANDROID_TZDATA_ROOT";
     private static final String ANDROID_I18N_ROOT_ENV = "ANDROID_I18N_ROOT";
+    private static final String ANDROID_DATA_ENV = "ANDROID_DATA";
 
     @Test
     public void expectedEnvironmentVariables() {
         // These environment variables are required to locate data files used by libcore / ICU.
+        assertNotNull(System.getenv(ANDROID_DATA_ENV));
         assertNotNull(System.getenv(ANDROID_TZDATA_ROOT_ENV));
         assertNotNull(System.getenv(ANDROID_I18N_ROOT_ENV));
     }
@@ -41,6 +43,7 @@
         String[] paths = TimeZoneDataFiles.getTimeZoneFilePaths("foo");
         assertEquals(2, paths.length);
 
+        assertTrue(paths[0].startsWith(System.getenv(ANDROID_DATA_ENV)));
         assertTrue(paths[0].contains("/misc/zoneinfo/current/"));
         assertTrue(paths[0].endsWith("/foo"));
 
@@ -58,6 +61,7 @@
         assertEquals(3, paths.length);
 
         String dataDirPath = paths[0];
+        assertTrue(dataDirPath.startsWith(System.getenv(ANDROID_DATA_ENV)));
         assertTrue(dataDirPath + " invalid", dataDirPath.contains("/misc/zoneinfo/current/icu"));
 
         String tzdataModulePath = paths[1];
diff --git a/luni/src/test/java/libcore/libcore/timezone/ZoneInfoDBTest.java b/luni/src/test/java/libcore/libcore/timezone/ZoneInfoDBTest.java
index 966df56..1e869fa 100644
--- a/luni/src/test/java/libcore/libcore/timezone/ZoneInfoDBTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/ZoneInfoDBTest.java
@@ -25,7 +25,7 @@
 import libcore.util.ZoneInfo;
 import libcore.timezone.ZoneInfoDB;
 
-import static libcore.timezone.ZoneInfoDB.TzData.SIZEOF_INDEX_ENTRY;
+import static libcore.timezone.ZoneInfoDB.SIZEOF_INDEX_ENTRY;
 
 public class ZoneInfoDBTest extends junit.framework.TestCase {
 
@@ -36,9 +36,9 @@
   // An empty override file should fall back to the default file.
   public void testLoadTzDataWithFallback_emptyOverrideFile() throws Exception {
     String emptyFilePath = makeEmptyFile().getPath();
-    try (ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_FILE);
-         ZoneInfoDB.TzData dataWithEmptyOverride =
-                 ZoneInfoDB.TzData.loadTzDataWithFallback(emptyFilePath, TZDATA_FILE)) {
+    try (ZoneInfoDB data = ZoneInfoDB.loadTzData(TZDATA_FILE);
+         ZoneInfoDB dataWithEmptyOverride =
+                 ZoneInfoDB.loadTzDataWithFallback(emptyFilePath, TZDATA_FILE)) {
       assertEquals(data.getVersion(), dataWithEmptyOverride.getVersion());
       assertEquals(data.getAvailableIDs().length, dataWithEmptyOverride.getAvailableIDs().length);
     }
@@ -47,9 +47,9 @@
   // A corrupt override file should fall back to the default file.
   public void testLoadTzDataWithFallback_corruptOverrideFile() throws Exception {
     String corruptFilePath = makeCorruptFile().getPath();
-    try (ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_FILE);
-         ZoneInfoDB.TzData dataWithCorruptOverride =
-                 ZoneInfoDB.TzData.loadTzDataWithFallback(corruptFilePath, TZDATA_FILE)) {
+    try (ZoneInfoDB data = ZoneInfoDB.loadTzData(TZDATA_FILE);
+         ZoneInfoDB dataWithCorruptOverride =
+                 ZoneInfoDB.loadTzDataWithFallback(corruptFilePath, TZDATA_FILE)) {
       assertEquals(data.getVersion(), dataWithCorruptOverride.getVersion());
       assertEquals(data.getAvailableIDs().length, dataWithCorruptOverride.getAvailableIDs().length);
     }
@@ -58,7 +58,7 @@
   // Given no tzdata files we can use, we should fall back to built-in "GMT".
   public void testLoadTzDataWithFallback_noGoodFile() throws Exception {
     String emptyFilePath = makeEmptyFile().getPath();
-    try (ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzDataWithFallback(emptyFilePath)) {
+    try (ZoneInfoDB data = ZoneInfoDB.loadTzDataWithFallback(emptyFilePath)) {
       assertEquals("missing", data.getVersion());
       assertEquals(1, data.getAvailableIDs().length);
       assertEquals("GMT", data.getAvailableIDs()[0]);
@@ -80,9 +80,9 @@
     content[10] = 'z';
 
     File goodFile = makeTemporaryFile(content);
-    try (ZoneInfoDB.TzData dataWithOverride =
-              ZoneInfoDB.TzData.loadTzDataWithFallback(goodFile.getPath(), TZDATA_FILE);
-         ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_FILE)) {
+    try (ZoneInfoDB dataWithOverride =
+              ZoneInfoDB.loadTzDataWithFallback(goodFile.getPath(), TZDATA_FILE);
+         ZoneInfoDB data = ZoneInfoDB.loadTzData(TZDATA_FILE)) {
 
       assertEquals("9999z", dataWithOverride.getVersion());
       assertEquals(data.getAvailableIDs().length, dataWithOverride.getAvailableIDs().length);
@@ -106,7 +106,7 @@
     byte[] data = new ZoneInfoTestHelper.TzDataBuilder().initializeToValid().build();
     File testFile = makeTemporaryFile(data);
     try {
-      assertNotNull(ZoneInfoDB.TzData.loadTzData(testFile.getPath()));
+      assertNotNull(ZoneInfoDB.loadTzData(testFile.getPath()));
     } finally {
       testFile.delete();
     }
@@ -149,7 +149,7 @@
     // Sections must be in the correct order: section sizing is calculated using them.
     int indexOffset = 10;
     builder.setIndexOffsetOverride(indexOffset);
-    int dataOffset = indexOffset + ZoneInfoDB.TzData.SIZEOF_INDEX_ENTRY - 1;
+    int dataOffset = indexOffset + ZoneInfoDB.SIZEOF_INDEX_ENTRY - 1;
     builder.setDataOffsetOverride(dataOffset);
     builder.setZoneTabOffsetOverride(dataOffset + 40);
 
@@ -207,7 +207,7 @@
   private static void checkInvalidDataDetected(byte[] data) throws Exception {
     File testFile = makeTemporaryFile(data);
     try {
-      assertNull(ZoneInfoDB.TzData.loadTzData(testFile.getPath()));
+      assertNull(ZoneInfoDB.loadTzData(testFile.getPath()));
     } finally {
       testFile.delete();
     }
@@ -215,7 +215,7 @@
 
   // Confirms any caching that exists correctly handles TimeZone mutability.
   public void testMakeTimeZone_timeZoneMutability() throws Exception {
-    try (ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_FILE)) {
+    try (ZoneInfoDB data = ZoneInfoDB.loadTzData(TZDATA_FILE)) {
       String tzId = "Europe/London";
       ZoneInfo first = data.makeTimeZone(tzId);
       ZoneInfo second = data.makeTimeZone(tzId);
@@ -233,14 +233,14 @@
   }
 
   public void testMakeTimeZone_notFound() throws Exception {
-    try (ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_FILE)) {
+    try (ZoneInfoDB data = ZoneInfoDB.loadTzData(TZDATA_FILE)) {
       assertNull(data.makeTimeZone("THIS_TZ_DOES_NOT_EXIST"));
       assertFalse(data.hasTimeZone("THIS_TZ_DOES_NOT_EXIST"));
     }
   }
 
   public void testMakeTimeZone_found() throws Exception {
-    try (ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(TZDATA_FILE)) {
+    try (ZoneInfoDB data = ZoneInfoDB.loadTzData(TZDATA_FILE)) {
       assertNotNull(data.makeTimeZone("Europe/London"));
       assertTrue(data.hasTimeZone("Europe/London"));
     }
diff --git a/luni/src/test/java/libcore/libcore/util/ZoneInfoTest.java b/luni/src/test/java/libcore/libcore/util/ZoneInfoTest.java
index fba0b47..6a54af1 100644
--- a/luni/src/test/java/libcore/libcore/util/ZoneInfoTest.java
+++ b/luni/src/test/java/libcore/libcore/util/ZoneInfoTest.java
@@ -470,7 +470,7 @@
    * creates the {@link ZoneInfo} instances does not prevent any of the time zones being loaded.
    */
   public void testReadTimeZone_All() throws Exception {
-    ZoneInfoDB.TzData instance = ZoneInfoDB.getInstance();
+    ZoneInfoDB instance = ZoneInfoDB.getInstance();
     String[] availableIDs = instance.getAvailableIDs();
     Arrays.sort(availableIDs);
     for (String id : availableIDs) {
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index 8abb9be..8a984ce 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -44,7 +44,6 @@
   public final class Os {
     method public static android.system.StructCapUserData[] capget(android.system.StructCapUserHeader) throws android.system.ErrnoException;
     method public static void capset(android.system.StructCapUserHeader, android.system.StructCapUserData[]) throws android.system.ErrnoException;
-    method public static int fcntlInt(java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
     method public static int getpgid(int) throws android.system.ErrnoException;
     method public static android.system.StructRlimit getrlimit(int) throws android.system.ErrnoException;
     method public static int getsockoptInt(java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
@@ -627,6 +626,8 @@
   }
 
   public final class RuntimeHooks {
+    method @Nullable public static dalvik.system.ThreadPrioritySetter getThreadPrioritySetter();
+    method public static void setThreadPrioritySetter(@NonNull dalvik.system.ThreadPrioritySetter);
     method public static void setTimeZoneIdSupplier(java.util.function.Supplier<java.lang.String>);
     method public static void setUncaughtExceptionPreHandler(java.lang.Thread.UncaughtExceptionHandler);
   }
@@ -643,6 +644,10 @@
     method public final void untag(java.net.DatagramSocket) throws java.net.SocketException;
   }
 
+  @java.lang.FunctionalInterface public interface ThreadPrioritySetter {
+    method public void setPriority(int, int);
+  }
+
   public final class VMDebug {
     method public static void attachAgent(String, ClassLoader) throws java.io.IOException;
     method public static boolean cacheRegisterMap(String);
@@ -926,6 +931,14 @@
 
 }
 
+package javax.net.ssl {
+
+  public abstract class HttpsURLConnection extends java.net.HttpURLConnection {
+    method public static javax.net.ssl.HostnameVerifier getStrictHostnameVerifier();
+  }
+
+}
+
 package libcore.content.type {
 
   public final class MimeMap {
@@ -1164,8 +1177,12 @@
     method public static int currentFormatMinorVersion();
     method public static boolean isCompatibleWithThisDevice(libcore.timezone.TzDataSetVersion);
     method public static libcore.timezone.TzDataSetVersion readFromFile(java.io.File) throws java.io.IOException, libcore.timezone.TzDataSetVersion.TzDataSetException;
+    method public static libcore.timezone.TzDataSetVersion readTimeZoneModuleVersion() throws java.io.IOException, libcore.timezone.TzDataSetVersion.TzDataSetException;
     method public byte[] toBytes();
     field public static final String DEFAULT_FILE_NAME = "tz_version";
+    field public final int formatMajorVersion;
+    field public final int formatMinorVersion;
+    field public final int revision;
     field public final String rulesVersion;
   }
 
@@ -1174,14 +1191,11 @@
     ctor public TzDataSetVersion.TzDataSetException(String, Throwable);
   }
 
-  public final class ZoneInfoDB {
-    method public static libcore.timezone.ZoneInfoDB.TzData getInstance();
-  }
-
-  public static class ZoneInfoDB.TzData implements java.lang.AutoCloseable {
+  public final class ZoneInfoDB implements java.lang.AutoCloseable {
+    method public static libcore.timezone.ZoneInfoDB getInstance();
     method public String getVersion();
     method public boolean hasTimeZone(String) throws java.io.IOException;
-    method public static libcore.timezone.ZoneInfoDB.TzData loadTzData(String);
+    method public static libcore.timezone.ZoneInfoDB loadTzData(String);
     method public libcore.util.ZoneInfo makeTimeZone(String) throws java.io.IOException;
     method public void validate() throws java.io.IOException;
   }
diff --git a/mmodules/intracoreapi/api/intra/current-api.txt b/mmodules/intracoreapi/api/intra/current-api.txt
index df28b02..fc27923 100644
--- a/mmodules/intracoreapi/api/intra/current-api.txt
+++ b/mmodules/intracoreapi/api/intra/current-api.txt
@@ -111,6 +111,14 @@
 
 }
 
+package libcore.io {
+
+  @libcore.api.IntraCoreApi public final class AsynchronousCloseMonitor {
+    method @libcore.api.IntraCoreApi public static void signalBlockedThreads(java.io.FileDescriptor);
+  }
+
+}
+
 package libcore.net {
 
   @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public abstract class NetworkSecurityPolicy {
diff --git a/mmodules/intracoreapi/api/intra/last-api.txt b/mmodules/intracoreapi/api/intra/last-api.txt
index e69de29..a62bfb6 100644
--- a/mmodules/intracoreapi/api/intra/last-api.txt
+++ b/mmodules/intracoreapi/api/intra/last-api.txt
@@ -0,0 +1,88 @@
+// Signature format: 2.0
+package dalvik.annotation.compat {
+
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public class VersionCodes {
+    field @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static final int Q = 29; // 0x1d
+  }
+
+}
+
+package dalvik.system {
+
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public final class BlockGuard {
+    method @NonNull @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static dalvik.system.BlockGuard.Policy getThreadPolicy();
+  }
+
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static interface BlockGuard.Policy {
+    method @libcore.api.IntraCoreApi public void onNetwork();
+  }
+
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public final class CloseGuard {
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public void close();
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static dalvik.system.CloseGuard get();
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public void open(String);
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public void warnIfOpen();
+  }
+
+}
+
+package java.net {
+
+  public class Socket implements java.io.Closeable {
+    method public java.io.FileDescriptor getFileDescriptor$();
+  }
+
+}
+
+package java.security.spec {
+
+  public class ECParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public String getCurveName();
+    method public void setCurveName(String);
+  }
+
+}
+
+package libcore.api {
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.ANNOTATION_TYPE}) @libcore.api.IntraCoreApi public @interface CorePlatformApi {
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.ANNOTATION_TYPE}) @libcore.api.IntraCoreApi public @interface IntraCoreApi {
+  }
+
+}
+
+package libcore.io {
+
+  @libcore.api.IntraCoreApi public final class AsynchronousCloseMonitor {
+    method @libcore.api.IntraCoreApi public static void signalBlockedThreads(java.io.FileDescriptor);
+  }
+
+}
+
+package libcore.net {
+
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public abstract class NetworkSecurityPolicy {
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static libcore.net.NetworkSecurityPolicy getInstance();
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public abstract boolean isCertificateTransparencyVerificationRequired(String);
+  }
+
+}
+
+package libcore.util {
+
+  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @libcore.api.IntraCoreApi public @interface NonNull {
+  }
+
+}
+
+package sun.security.x509 {
+
+  public class AlgorithmId implements java.io.Serializable {
+    method public static sun.security.x509.AlgorithmId get(String) throws java.security.NoSuchAlgorithmException;
+    method public String getName();
+  }
+
+}
+
diff --git a/non_openjdk_java_files.bp b/non_openjdk_java_files.bp
index afc8de8..e76142d 100644
--- a/non_openjdk_java_files.bp
+++ b/non_openjdk_java_files.bp
@@ -49,6 +49,7 @@
         "dalvik/src/main/java/dalvik/system/RuntimeHooks.java",
         "dalvik/src/main/java/dalvik/system/SocketTagger.java",
         "dalvik/src/main/java/dalvik/system/TemporaryDirectory.java",
+        "dalvik/src/main/java/dalvik/system/ThreadPrioritySetter.java",
         "dalvik/src/main/java/dalvik/system/VMDebug.java",
         "dalvik/src/main/java/dalvik/system/ZygoteHooks.java",
         "dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java",
@@ -238,6 +239,7 @@
         "luni/src/main/java/libcore/icu/RelativeDateTimeFormatter.java",
         "luni/src/main/java/libcore/icu/TimeZoneNames.java",
         "luni/src/main/java/libcore/internal/StringPool.java",
+        "luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java",
         "luni/src/main/java/libcore/io/ForwardingOs.java",
         "luni/src/main/java/libcore/io/IoBridge.java",
         "luni/src/main/java/libcore/io/IoUtils.java",
@@ -376,7 +378,6 @@
         "luni/src/main/java/libcore/icu/DateTimeFormat.java",
         "luni/src/main/java/libcore/icu/DateUtilsBridge.java",
         "luni/src/main/java/libcore/internal/Java9LanguageFeatures.java",
-        "luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java",
         "luni/src/main/java/libcore/io/ClassPathURLStreamHandler.java",
         "luni/src/main/java/libcore/io/BlockGuardOs.java",
         "luni/src/main/java/libcore/io/BufferIterator.java",
@@ -446,6 +447,7 @@
     srcs: [
         "luni/src/main/java/libcore/api/CorePlatformApi.java",
         "luni/src/main/java/libcore/api/IntraCoreApi.java",
+        "luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java",
         "luni/src/main/java/libcore/timezone/TzDataSetVersion.java",
     ],
 }
diff --git a/ojluni/annotations/sdk/nullability/java/util/List.annotated.java b/ojluni/annotations/sdk/nullability/java/util/List.annotated.java
index 958b335..2ef4a6f 100644
--- a/ojluni/annotations/sdk/nullability/java/util/List.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/List.annotated.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -86,4 +86,29 @@
 @libcore.util.NonNull public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex);
 
 @libcore.util.NonNull public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9, @libcore.util.NonNull E e10) { throw new RuntimeException("Stub!"); }
+
+@java.lang.SafeVarargs
+@libcore.util.NonNull public static <E> java.util.List<@libcore.util.NonNull E> of(E @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
 }
diff --git a/ojluni/annotations/sdk/nullability/java/util/Map.annotated.java b/ojluni/annotations/sdk/nullability/java/util/Map.annotated.java
index 4008996..c19add2 100644
--- a/ojluni/annotations/sdk/nullability/java/util/Map.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/Map.annotated.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,6 +80,33 @@
 @libcore.util.Nullable public default V compute(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.Nullable V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
 
 @libcore.util.Nullable public default V merge(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8, @libcore.util.NonNull K k9, @libcore.util.NonNull V v9) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8, @libcore.util.NonNull K k9, @libcore.util.NonNull V v9, @libcore.util.NonNull K k10, @libcore.util.NonNull V v10) { throw new RuntimeException("Stub!"); }
+
+@java.lang.SafeVarargs
+@libcore.util.NonNull public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> ofEntries(@libcore.util.NonNull java.util.Map.Entry<? extends @libcore.util.NonNull K,? extends @libcore.util.NonNull V>... entries) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <K, V>  java.util.Map.Entry<@libcore.util.NonNull K, @libcore.util.NonNull V> entry(@libcore.util.NonNull K k, @libcore.util.NonNull V v) { throw new RuntimeException("Stub!"); }
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public static interface Entry<K, V> {
 
diff --git a/ojluni/annotations/sdk/nullability/java/util/Objects.annotated.java b/ojluni/annotations/sdk/nullability/java/util/Objects.annotated.java
index 591a022..ee1b692 100644
--- a/ojluni/annotations/sdk/nullability/java/util/Objects.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/Objects.annotated.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -55,5 +55,9 @@
 
 public static boolean nonNull(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
 
+@libcore.util.NonNull public static <T> T requireNonNullElse(@libcore.util.Nullable T obj, @libcore.util.NonNull T defaultObj) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <T> T requireNonNullElseGet(@libcore.util.Nullable T obj, @libcore.util.NonNull java.util.function.Supplier<? extends @libcore.util.NonNull T> supplier) { throw new RuntimeException("Stub!"); }
+
 @libcore.util.NonNull public static <T> T requireNonNull(@libcore.util.Nullable T obj, @libcore.util.NonNull java.util.function.Supplier<@libcore.util.NonNull java.lang.String> messageSupplier) { throw new RuntimeException("Stub!"); }
 }
diff --git a/ojluni/annotations/sdk/nullability/java/util/Set.annotated.java b/ojluni/annotations/sdk/nullability/java/util/Set.annotated.java
index 1257b5c..bae8bdd 100644
--- a/ojluni/annotations/sdk/nullability/java/util/Set.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/Set.annotated.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -62,4 +62,29 @@
 public int hashCode();
 
 @libcore.util.NonNull public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of() { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9) { throw new RuntimeException("Stub!"); }
+
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9, @libcore.util.NonNull E e10) { throw new RuntimeException("Stub!"); }
+
+@java.lang.SafeVarargs
+@libcore.util.NonNull public static <E> java.util.Set<@libcore.util.NonNull E> of(E @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
 }
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index 2e2af6a..699a1ac 100644
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -40,6 +40,8 @@
 import java.util.concurrent.locks.LockSupport;
 import sun.nio.ch.Interruptible;
 import sun.reflect.CallerSensitive;
+import dalvik.system.RuntimeHooks;
+import dalvik.system.ThreadPrioritySetter;
 import dalvik.system.VMStack;
 import libcore.util.EmptyArray;
 
@@ -1244,7 +1246,18 @@
             synchronized(this) {
                 this.priority = newPriority;
                 if (isAlive()) {
-                    setPriority0(newPriority);
+                    // BEGIN Android-added: Customize behavior of Thread.setPriority().
+                    // http://b/139521784
+                    // setPriority0(newPriority);
+                    ThreadPrioritySetter threadPrioritySetter =
+                        RuntimeHooks.getThreadPrioritySetter();
+                    int nativeTid = this.getNativeTid();
+                    if (threadPrioritySetter != null && nativeTid != 0) {
+                        threadPrioritySetter.setPriority(nativeTid, newPriority);
+                    } else {
+                        setPriority0(newPriority);
+                    }
+                    // END Android-added: Customize behavior of Thread.setPriority().
                 }
             }
         }
@@ -2327,4 +2340,14 @@
 
     // Android-added: Android specific nativeGetStatus() method.
     private native int nativeGetStatus(boolean hasBeenStarted);
+
+    // BEGIN Android-added: Customize behavior of Thread.setPriority(). http://b/139521784
+    /**
+     * Returns the thread ID of the underlying native thread -- which is different from
+     * the {@link #getId() managed thread ID} -- or 0 if the native thread is not
+     * started or has stopped.
+     */
+    @FastNative
+    private native int getNativeTid();
+    // END Android-added: Customize behavior of Thread.setPriority(). http://b/139521784
 }
diff --git a/ojluni/src/main/java/java/net/NetworkInterface.java b/ojluni/src/main/java/java/net/NetworkInterface.java
index e5b5632..eab09ab 100644
--- a/ojluni/src/main/java/java/net/NetworkInterface.java
+++ b/ojluni/src/main/java/java/net/NetworkInterface.java
@@ -63,7 +63,7 @@
 public final class NetworkInterface {
     // BEGIN Android-added: Return anonymized device address to non-system processes.
     /**
-     * Gates whether calls to {@link getHardwareAddress()} made by non-system processes
+     * Gates whether calls to {@link #getHardwareAddress()} made by non-system processes
      * to return the actual MAC address (pre-change behavior) or an anonymized MAC address
      * (post-change behavior). Future versions of Android will enforce the post-change
      * behavior through SELinux.
diff --git a/ojluni/src/main/java/java/util/AbstractList.java b/ojluni/src/main/java/java/util/AbstractList.java
index a183624..c8c160d 100644
--- a/ojluni/src/main/java/java/util/AbstractList.java
+++ b/ojluni/src/main/java/java/util/AbstractList.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package java.util;
 
+import java.util.function.Consumer;
+
 /**
  * This class provides a skeletal implementation of the {@link List}
  * interface to minimize the effort required to implement this interface
@@ -87,7 +89,8 @@
      * classes should clearly specify in their documentation any restrictions
      * on what elements may be added.
      *
-     * <p>This implementation calls {@code add(size(), e)}.
+     * @implSpec
+     * This implementation calls {@code add(size(), e)}.
      *
      * <p>Note that this implementation throws an
      * {@code UnsupportedOperationException} unless
@@ -114,12 +117,13 @@
      *
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
-    abstract public E get(int index);
+    public abstract E get(int index);
 
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation always throws an
+     * @implSpec
+     * This implementation always throws an
      * {@code UnsupportedOperationException}.
      *
      * @throws UnsupportedOperationException {@inheritDoc}
@@ -135,7 +139,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation always throws an
+     * @implSpec
+     * This implementation always throws an
      * {@code UnsupportedOperationException}.
      *
      * @throws UnsupportedOperationException {@inheritDoc}
@@ -151,7 +156,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation always throws an
+     * @implSpec
+     * This implementation always throws an
      * {@code UnsupportedOperationException}.
      *
      * @throws UnsupportedOperationException {@inheritDoc}
@@ -167,7 +173,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation first gets a list iterator (with
+     * @implSpec
+     * This implementation first gets a list iterator (with
      * {@code listIterator()}).  Then, it iterates over the list until the
      * specified element is found or the end of the list is reached.
      *
@@ -191,7 +198,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation first gets a list iterator that points to the end
+     * @implSpec
+     * This implementation first gets a list iterator that points to the end
      * of the list (with {@code listIterator(size())}).  Then, it iterates
      * backwards over the list until the specified element is found, or the
      * beginning of the list is reached.
@@ -220,7 +228,8 @@
      * Removes all of the elements from this list (optional operation).
      * The list will be empty after this call returns.
      *
-     * <p>This implementation calls {@code removeRange(0, size())}.
+     * @implSpec
+     * This implementation calls {@code removeRange(0, size())}.
      *
      * <p>Note that this implementation throws an
      * {@code UnsupportedOperationException} unless {@code remove(int
@@ -237,7 +246,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation gets an iterator over the specified collection
+     * @implSpec
+     * This implementation gets an iterator over the specified collection
      * and iterates over it, inserting the elements obtained from the
      * iterator into this list at the appropriate position, one at a time,
      * using {@code add(int, E)}.
@@ -269,7 +279,8 @@
     /**
      * Returns an iterator over the elements in this list in proper sequence.
      *
-     * <p>This implementation returns a straightforward implementation of the
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
      * iterator interface, relying on the backing list's {@code size()},
      * {@code get(int)}, and {@code remove(int)} methods.
      *
@@ -291,7 +302,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation returns {@code listIterator(0)}.
+     * @implSpec
+     * This implementation returns {@code listIterator(0)}.
      *
      * @see #listIterator(int)
      */
@@ -302,7 +314,8 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation returns a straightforward implementation of the
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
      * {@code ListIterator} interface that extends the implementation of the
      * {@code Iterator} interface returned by the {@code iterator()} method.
      * The {@code ListIterator} implementation relies on the backing list's
@@ -448,12 +461,12 @@
     /**
      * {@inheritDoc}
      *
-     * <p>This implementation returns a list that subclasses
+     * @implSpec
+     * This implementation returns a list that subclasses
      * {@code AbstractList}.  The subclass stores, in private fields, the
-     * offset of the subList within the backing list, the size of the subList
-     * (which can change over its lifetime), and the expected
-     * {@code modCount} value of the backing list.  There are two variants
-     * of the subclass, one of which implements {@code RandomAccess}.
+     * size of the subList (which can change over its lifetime), and the
+     * expected {@code modCount} value of the backing list.  There are two
+     * variants of the subclass, one of which implements {@code RandomAccess}.
      * If this list implements {@code RandomAccess} the returned list will
      * be an instance of the subclass that implements {@code RandomAccess}.
      *
@@ -481,11 +494,22 @@
      *         {@code (fromIndex > toIndex)}
      */
     public List<E> subList(int fromIndex, int toIndex) {
+        subListRangeCheck(fromIndex, toIndex, size());
         return (this instanceof RandomAccess ?
                 new RandomAccessSubList<>(this, fromIndex, toIndex) :
                 new SubList<>(this, fromIndex, toIndex));
     }
 
+    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        if (toIndex > size)
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                               ") > toIndex(" + toIndex + ")");
+    }
+
     // Comparison and hashing
 
     /**
@@ -495,8 +519,9 @@
      * the two lists are <i>equal</i>.  (Two elements {@code e1} and
      * {@code e2} are <i>equal</i> if {@code (e1==null ? e2==null :
      * e1.equals(e2))}.)  In other words, two lists are defined to be
-     * equal if they contain the same elements in the same order.<p>
+     * equal if they contain the same elements in the same order.
      *
+     * @implSpec
      * This implementation first checks if the specified object is this
      * list. If so, it returns {@code true}; if not, it checks if the
      * specified object is a list. If not, it returns {@code false}; if so,
@@ -529,7 +554,8 @@
     /**
      * Returns the hash code value for this list.
      *
-     * <p>This implementation uses exactly the code that is used to define the
+     * @implSpec
+     * This implementation uses exactly the code that is used to define the
      * list hash function in the documentation for the {@link List#hashCode}
      * method.
      *
@@ -555,7 +581,8 @@
      * improve the performance of the {@code clear} operation on this list
      * and its subLists.
      *
-     * <p>This implementation gets a list iterator positioned before
+     * @implSpec
+     * This implementation gets a list iterator positioned before
      * {@code fromIndex}, and repeatedly calls {@code ListIterator.next}
      * followed by {@code ListIterator.remove} until the entire range has
      * been removed.  <b>Note: if {@code ListIterator.remove} requires linear
@@ -608,174 +635,308 @@
     private String outOfBoundsMsg(int index) {
         return "Index: "+index+", Size: "+size();
     }
-}
 
-class SubList<E> extends AbstractList<E> {
-    private final AbstractList<E> l;
-    private final int offset;
-    private int size;
+    /**
+     * An index-based split-by-two, lazily initialized Spliterator covering
+     * a List that access elements via {@link List#get}.
+     *
+     * If access results in an IndexOutOfBoundsException then a
+     * ConcurrentModificationException is thrown instead (since the list has
+     * been structurally modified while traversing).
+     *
+     * If the List is an instance of AbstractList then concurrent modification
+     * checking is performed using the AbstractList's modCount field.
+     */
+    static final class RandomAccessSpliterator<E> implements Spliterator<E> {
 
-    SubList(AbstractList<E> list, int fromIndex, int toIndex) {
-        if (fromIndex < 0)
-            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
-        if (toIndex > list.size())
-            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
-        if (fromIndex > toIndex)
-            throw new IllegalArgumentException("fromIndex(" + fromIndex +
-                                               ") > toIndex(" + toIndex + ")");
-        l = list;
-        offset = fromIndex;
-        size = toIndex - fromIndex;
-        this.modCount = l.modCount;
-    }
+        private final List<E> list;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
 
-    public E set(int index, E element) {
-        rangeCheck(index);
-        checkForComodification();
-        return l.set(index+offset, element);
-    }
+        // The following fields are valid if covering an AbstractList
+        private final AbstractList<E> alist;
+        private int expectedModCount; // initialized when fence set
 
-    public E get(int index) {
-        rangeCheck(index);
-        checkForComodification();
-        return l.get(index+offset);
-    }
+        RandomAccessSpliterator(List<E> list) {
+            assert list instanceof RandomAccess;
 
-    public int size() {
-        checkForComodification();
-        return size;
-    }
+            this.list = list;
+            this.index = 0;
+            this.fence = -1;
 
-    public void add(int index, E element) {
-        rangeCheckForAdd(index);
-        checkForComodification();
-        l.add(index+offset, element);
-        this.modCount = l.modCount;
-        size++;
-    }
+            this.alist = list instanceof AbstractList ? (AbstractList<E>) list : null;
+            this.expectedModCount = alist != null ? alist.modCount : 0;
+        }
 
-    public E remove(int index) {
-        rangeCheck(index);
-        checkForComodification();
-        E result = l.remove(index+offset);
-        this.modCount = l.modCount;
-        size--;
-        return result;
-    }
+        /** Create new spliterator covering the given  range */
+        private RandomAccessSpliterator(RandomAccessSpliterator<E> parent,
+                                int origin, int fence) {
+            this.list = parent.list;
+            this.index = origin;
+            this.fence = fence;
 
-    protected void removeRange(int fromIndex, int toIndex) {
-        checkForComodification();
-        l.removeRange(fromIndex+offset, toIndex+offset);
-        this.modCount = l.modCount;
-        size -= (toIndex-fromIndex);
-    }
+            this.alist = parent.alist;
+            this.expectedModCount = parent.expectedModCount;
+        }
 
-    public boolean addAll(Collection<? extends E> c) {
-        return addAll(size, c);
-    }
+        private int getFence() { // initialize fence to size on first use
+            int hi;
+            List<E> lst = list;
+            if ((hi = fence) < 0) {
+                if (alist != null) {
+                    expectedModCount = alist.modCount;
+                }
+                hi = fence = lst.size();
+            }
+            return hi;
+        }
 
-    public boolean addAll(int index, Collection<? extends E> c) {
-        rangeCheckForAdd(index);
-        int cSize = c.size();
-        if (cSize==0)
+        public Spliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null : // divide range in half unless too small
+                    new RandomAccessSpliterator<>(this, lo, index = mid);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), i = index;
+            if (i < hi) {
+                index = i + 1;
+                action.accept(get(list, i));
+                checkAbstractListModCount(alist, expectedModCount);
+                return true;
+            }
             return false;
+        }
 
-        checkForComodification();
-        l.addAll(offset+index, c);
-        this.modCount = l.modCount;
-        size += cSize;
-        return true;
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            List<E> lst = list;
+            int hi = getFence();
+            int i = index;
+            index = hi;
+            for (; i < hi; i++) {
+                action.accept(get(lst, i));
+            }
+            checkAbstractListModCount(alist, expectedModCount);
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        private static <E> E get(List<E> list, int i) {
+            try {
+                return list.get(i);
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        static void checkAbstractListModCount(AbstractList<?> alist, int expectedModCount) {
+            if (alist != null && alist.modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
     }
 
-    public Iterator<E> iterator() {
-        return listIterator();
+    private static class SubList<E> extends AbstractList<E> {
+        private final AbstractList<E> root;
+        private final SubList<E> parent;
+        private final int offset;
+        protected int size;
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a SubList itself.
+         */
+        public SubList(AbstractList<E> root, int fromIndex, int toIndex) {
+            this.root = root;
+            this.parent = null;
+            this.offset = fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        /**
+         * Constructs a sublist of another SubList.
+         */
+        protected SubList(SubList<E> parent, int fromIndex, int toIndex) {
+            this.root = parent.root;
+            this.parent = parent;
+            this.offset = parent.offset + fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        public E set(int index, E element) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.set(offset + index, element);
+        }
+
+        public E get(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.get(offset + index);
+        }
+
+        public int size() {
+            checkForComodification();
+            return size;
+        }
+
+        public void add(int index, E element) {
+            rangeCheckForAdd(index);
+            checkForComodification();
+            root.add(offset + index, element);
+            updateSizeAndModCount(1);
+        }
+
+        public E remove(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            E result = root.remove(offset + index);
+            updateSizeAndModCount(-1);
+            return result;
+        }
+
+        protected void removeRange(int fromIndex, int toIndex) {
+            checkForComodification();
+            root.removeRange(offset + fromIndex, offset + toIndex);
+            updateSizeAndModCount(fromIndex - toIndex);
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return addAll(size, c);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            rangeCheckForAdd(index);
+            int cSize = c.size();
+            if (cSize==0)
+                return false;
+            checkForComodification();
+            root.addAll(offset + index, c);
+            updateSizeAndModCount(cSize);
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator();
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            checkForComodification();
+            rangeCheckForAdd(index);
+
+            return new ListIterator<E>() {
+                private final ListIterator<E> i =
+                        root.listIterator(offset + index);
+
+                public boolean hasNext() {
+                    return nextIndex() < size;
+                }
+
+                public E next() {
+                    if (hasNext())
+                        return i.next();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public boolean hasPrevious() {
+                    return previousIndex() >= 0;
+                }
+
+                public E previous() {
+                    if (hasPrevious())
+                        return i.previous();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public int nextIndex() {
+                    return i.nextIndex() - offset;
+                }
+
+                public int previousIndex() {
+                    return i.previousIndex() - offset;
+                }
+
+                public void remove() {
+                    i.remove();
+                    updateSizeAndModCount(-1);
+                }
+
+                public void set(E e) {
+                    i.set(e);
+                }
+
+                public void add(E e) {
+                    i.add(e);
+                    updateSizeAndModCount(1);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new SubList<>(this, fromIndex, toIndex);
+        }
+
+        private void rangeCheckForAdd(int index) {
+            if (index < 0 || index > size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+        }
+
+        private String outOfBoundsMsg(int index) {
+            return "Index: "+index+", Size: "+size;
+        }
+
+        private void checkForComodification() {
+            if (root.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+        }
+
+        private void updateSizeAndModCount(int sizeChange) {
+            SubList<E> slist = this;
+            do {
+                slist.size += sizeChange;
+                slist.modCount = root.modCount;
+                slist = slist.parent;
+            } while (slist != null);
+        }
     }
 
-    public ListIterator<E> listIterator(final int index) {
-        checkForComodification();
-        rangeCheckForAdd(index);
+    private static class RandomAccessSubList<E>
+            extends SubList<E> implements RandomAccess {
 
-        return new ListIterator<E>() {
-            private final ListIterator<E> i = l.listIterator(index+offset);
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a RandomAccessSubList itself.
+         */
+        RandomAccessSubList(AbstractList<E> root,
+                int fromIndex, int toIndex) {
+            super(root, fromIndex, toIndex);
+        }
 
-            public boolean hasNext() {
-                return nextIndex() < size;
-            }
+        /**
+         * Constructs a sublist of another RandomAccessSubList.
+         */
+        RandomAccessSubList(RandomAccessSubList<E> parent,
+                int fromIndex, int toIndex) {
+            super(parent, fromIndex, toIndex);
+        }
 
-            public E next() {
-                if (hasNext())
-                    return i.next();
-                else
-                    throw new NoSuchElementException();
-            }
-
-            public boolean hasPrevious() {
-                return previousIndex() >= 0;
-            }
-
-            public E previous() {
-                if (hasPrevious())
-                    return i.previous();
-                else
-                    throw new NoSuchElementException();
-            }
-
-            public int nextIndex() {
-                return i.nextIndex() - offset;
-            }
-
-            public int previousIndex() {
-                return i.previousIndex() - offset;
-            }
-
-            public void remove() {
-                i.remove();
-                SubList.this.modCount = l.modCount;
-                size--;
-            }
-
-            public void set(E e) {
-                i.set(e);
-            }
-
-            public void add(E e) {
-                i.add(e);
-                SubList.this.modCount = l.modCount;
-                size++;
-            }
-        };
-    }
-
-    public List<E> subList(int fromIndex, int toIndex) {
-        return new SubList<>(this, fromIndex, toIndex);
-    }
-
-    private void rangeCheck(int index) {
-        if (index < 0 || index >= size)
-            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
-    }
-
-    private void rangeCheckForAdd(int index) {
-        if (index < 0 || index > size)
-            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
-    }
-
-    private String outOfBoundsMsg(int index) {
-        return "Index: "+index+", Size: "+size;
-    }
-
-    private void checkForComodification() {
-        if (this.modCount != l.modCount)
-            throw new ConcurrentModificationException();
-    }
-}
-
-class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
-    RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
-        super(list, fromIndex, toIndex);
-    }
-
-    public List<E> subList(int fromIndex, int toIndex) {
-        return new RandomAccessSubList<>(this, fromIndex, toIndex);
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new RandomAccessSubList<>(this, fromIndex, toIndex);
+        }
     }
 }
diff --git a/ojluni/src/main/java/java/util/ImmutableCollections.java b/ojluni/src/main/java/java/util/ImmutableCollections.java
new file mode 100644
index 0000000..2bc0cc1
--- /dev/null
+++ b/ojluni/src/main/java/java/util/ImmutableCollections.java
@@ -0,0 +1,964 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * Container class for immutable collections. Not part of the public API.
+ * Mainly for namespace management and shared infrastructure.
+ *
+ * Serial warnings are suppressed throughout because all implementation
+ * classes use a serial proxy and thus have no need to declare serialVersionUID.
+ */
+@SuppressWarnings("serial")
+class ImmutableCollections {
+    /**
+     * A "salt" value used for randomizing iteration order. This is initialized once
+     * and stays constant for the lifetime of the JVM. It need not be truly random, but
+     * it needs to vary sufficiently from one run to the next so that iteration order
+     * will vary between JVM runs.
+     */
+    static final int SALT;
+    static {
+        long nt = System.nanoTime();
+        SALT = (int)((nt >>> 32) ^ nt);
+    }
+
+    /** No instances. */
+    private ImmutableCollections() { }
+
+    /**
+     * The reciprocal of load factor. Given a number of elements
+     * to store, multiply by this factor to get the table size.
+     */
+    static final int EXPAND_FACTOR = 2;
+
+    static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
+
+    // ---------- List Implementations ----------
+
+    abstract static class AbstractImmutableList<E> extends AbstractList<E>
+                                                implements RandomAccess, Serializable {
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+        @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
+    }
+
+    static final class List0<E> extends AbstractImmutableList<E> {
+        private static final List0<?> INSTANCE = new List0<>();
+
+        @SuppressWarnings("unchecked")
+        static <T> List0<T> instance() {
+            return (List0<T>) INSTANCE;
+        }
+
+        private List0() { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
+            return null;                  // but the compiler doesn't know this
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST);
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> o) {
+            return o.isEmpty(); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return 1;
+        }
+    }
+
+    static final class List1<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E e0;
+
+        List1(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 1);
+            return e0;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, e0);
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 + e0.hashCode();
+        }
+    }
+
+    static final class List2<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E e0;
+        @Stable
+        private final E e1;
+
+        List2(E e0, E e1) {
+            this.e0 = Objects.requireNonNull(e0);
+            this.e1 = Objects.requireNonNull(e1);
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 2);
+            if (index == 0) {
+                return e0;
+            } else { // index == 1
+                return e1;
+            }
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 31 + e0.hashCode();
+            return 31 * hash + e1.hashCode();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, e0, e1);
+        }
+    }
+
+    static final class ListN<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E[] elements;
+
+        @SafeVarargs
+        ListN(E... input) {
+            // copy and check manually to avoid TOCTOU
+            @SuppressWarnings("unchecked")
+            E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
+            for (int i = 0; i < input.length; i++) {
+                tmp[i] = Objects.requireNonNull(input[i]);
+            }
+            this.elements = tmp;
+        }
+
+        @Override
+        public int size() {
+            return elements.length;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, elements.length);
+            return elements[index];
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            for (E e : elements) {
+                if (o.equals(e)) { // implicit nullcheck of o
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 1;
+            for (E e : elements) {
+                hash = 31 * hash + e.hashCode();
+            }
+            return hash;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, elements);
+        }
+    }
+
+    // ---------- Set Implementations ----------
+
+    abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+    }
+
+    static final class Set0<E> extends AbstractImmutableSet<E> {
+        private static final Set0<?> INSTANCE = new Set0<>();
+
+        @SuppressWarnings("unchecked")
+        static <T> Set0<T> instance() {
+            return (Set0<T>) INSTANCE;
+        }
+
+        private Set0() { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> o) {
+            return o.isEmpty(); // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    static final class Set1<E> extends AbstractImmutableSet<E> {
+        @Stable
+        private final E e0;
+
+        Set1(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0); // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.singletonIterator(e0);
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET, e0);
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode();
+        }
+    }
+
+    static final class Set2<E> extends AbstractImmutableSet<E> {
+        @Stable
+        final E e0;
+        @Stable
+        final E e1;
+
+        Set2(E e0, E e1) {
+            if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
+                throw new IllegalArgumentException("duplicate element: " + e0);
+            }
+
+            if (SALT >= 0) {
+                this.e0 = e0;
+                this.e1 = e1;
+            } else {
+                this.e0 = e1;
+                this.e1 = e0;
+            }
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode() + e1.hashCode();
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private int idx = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return idx < 2;
+                }
+
+                @Override
+                public E next() {
+                    if (idx == 0) {
+                        idx = 1;
+                        return e0;
+                    } else if (idx == 1) {
+                        idx = 2;
+                        return e1;
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET, e0, e1);
+        }
+    }
+
+    /**
+     * An array-based Set implementation. The element array must be strictly
+     * larger than the size (the number of contained elements) so that at
+     * least one null is always present.
+     * @param <E> the element type
+     */
+    static final class SetN<E> extends AbstractImmutableSet<E> {
+        @Stable
+        final E[] elements;
+        @Stable
+        final int size;
+
+        @SafeVarargs
+        @SuppressWarnings("unchecked")
+        SetN(E... input) {
+            size = input.length; // implicit nullcheck of input
+
+            elements = (E[])new Object[EXPAND_FACTOR * input.length];
+            for (int i = 0; i < input.length; i++) {
+                E e = input[i];
+                int idx = probe(e); // implicit nullcheck of e
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate element: " + e);
+                } else {
+                    elements[-(idx + 1)] = e;
+                }
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return probe(o) >= 0; // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private int idx = 0;
+
+                @Override
+                public boolean hasNext() {
+                    while (idx < elements.length) {
+                        if (elements[idx] != null)
+                            return true;
+                        idx++;
+                    }
+                    return false;
+                }
+
+                @Override
+                public E next() {
+                    if (! hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+                    return elements[idx++];
+                }
+            };
+        }
+
+        @Override
+        public int hashCode() {
+            int h = 0;
+            for (E e : elements) {
+                if (e != null) {
+                    h += e.hashCode();
+                }
+            }
+            return h;
+        }
+
+        // returns index at which element is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pe
+        private int probe(Object pe) {
+            int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length);
+            while (true) {
+                E ee = elements[idx];
+                if (ee == null) {
+                    return -idx - 1;
+                } else if (pe.equals(ee)) {
+                    return idx;
+                } else if (++idx == elements.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            Object[] array = new Object[size];
+            int dest = 0;
+            for (Object o : elements) {
+                if (o != null) {
+                    array[dest++] = o;
+                }
+            }
+            return new CollSer(CollSer.IMM_SET, array);
+        }
+    }
+
+    // ---------- Map Implementations ----------
+
+    abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
+        @Override public void clear() { throw uoe(); }
+        @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
+        @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V put(K key, V value) { throw uoe(); }
+        @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
+        @Override public V putIfAbsent(K key, V value) { throw uoe(); }
+        @Override public V remove(Object key) { throw uoe(); }
+        @Override public boolean remove(Object key, Object value) { throw uoe(); }
+        @Override public V replace(K key, V value) { throw uoe(); }
+        @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
+        @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
+    }
+
+    static final class Map0<K,V> extends AbstractImmutableMap<K,V> {
+        private static final Map0<?,?> INSTANCE = new Map0<>();
+
+        @SuppressWarnings("unchecked")
+        static <K,V> Map0<K,V> instance() {
+            return (Map0<K,V>) INSTANCE;
+        }
+
+        private Map0() { }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of();
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        private final K k0;
+        @Stable
+        private final V v0;
+
+        Map1(K k0, V v0) {
+            this.k0 = Objects.requireNonNull(k0);
+            this.v0 = Objects.requireNonNull(v0);
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of(new KeyValueHolder<>(k0, v0));
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return o.equals(k0); // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            return o.equals(v0); // implicit nullcheck of o
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP, k0, v0);
+        }
+
+        @Override
+        public int hashCode() {
+            return k0.hashCode() ^ v0.hashCode();
+        }
+    }
+
+    /**
+     * An array-based Map implementation. There is a single array "table" that
+     * contains keys and values interleaved: table[0] is kA, table[1] is vA,
+     * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
+     * also be strictly larger than the size (the number of key-value pairs contained
+     * in the map) so that at least one null key is always present.
+     * @param <K> the key type
+     * @param <V> the value type
+     */
+    static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        final Object[] table; // pairs of key, value
+        @Stable
+        final int size; // number of pairs
+
+        MapN(Object... input) {
+            if ((input.length & 1) != 0) { // implicit nullcheck of input
+                throw new InternalError("length is odd");
+            }
+            size = input.length >> 1;
+
+            int len = EXPAND_FACTOR * input.length;
+            len = (len + 1) & ~1; // ensure table is even length
+            table = new Object[len];
+
+            for (int i = 0; i < input.length; i += 2) {
+                @SuppressWarnings("unchecked")
+                    K k = Objects.requireNonNull((K)input[i]);
+                @SuppressWarnings("unchecked")
+                    V v = Objects.requireNonNull((V)input[i+1]);
+                int idx = probe(k);
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate key: " + k);
+                } else {
+                    int dest = -(idx + 1);
+                    table[dest] = k;
+                    table[dest+1] = v;
+                }
+            }
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return probe(o) >= 0; // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            for (int i = 1; i < table.length; i += 2) {
+                Object v = table[i];
+                if (v != null && o.equals(v)) { // implicit nullcheck of o
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 0;
+            for (int i = 0; i < table.length; i += 2) {
+                Object k = table[i];
+                if (k != null) {
+                    hash += k.hashCode() ^ table[i + 1].hashCode();
+                }
+            }
+            return hash;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public V get(Object o) {
+            int i = probe(o);
+            if (i >= 0) {
+                return (V)table[i+1];
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return new AbstractSet<Map.Entry<K,V>>() {
+                @Override
+                public int size() {
+                    return MapN.this.size;
+                }
+
+                @Override
+                public Iterator<Map.Entry<K,V>> iterator() {
+                    return new Iterator<Map.Entry<K,V>>() {
+                        int idx = 0;
+
+                        @Override
+                        public boolean hasNext() {
+                            while (idx < table.length) {
+                                if (table[idx] != null)
+                                    return true;
+                                idx += 2;
+                            }
+                            return false;
+                        }
+
+                        @Override
+                        public Map.Entry<K,V> next() {
+                            if (hasNext()) {
+                                @SuppressWarnings("unchecked")
+                                Map.Entry<K,V> e =
+                                    new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
+                                idx += 2;
+                                return e;
+                            } else {
+                                throw new NoSuchElementException();
+                            }
+                        }
+                    };
+                }
+            };
+        }
+
+        // returns index at which the probe key is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pk.
+        private int probe(Object pk) {
+            int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1;
+            while (true) {
+                @SuppressWarnings("unchecked")
+                K ek = (K)table[idx];
+                if (ek == null) {
+                    return -idx - 1;
+                } else if (pk.equals(ek)) {
+                    return idx;
+                } else if ((idx += 2) == table.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            Object[] array = new Object[2 * size];
+            int len = table.length;
+            int dest = 0;
+            for (int i = 0; i < len; i += 2) {
+                if (table[i] != null) {
+                    array[dest++] = table[i];
+                    array[dest++] = table[i+1];
+                }
+            }
+            return new CollSer(CollSer.IMM_MAP, array);
+        }
+    }
+}
+
+// ---------- Serialization Proxy ----------
+
+/**
+ * A unified serialization proxy class for the immutable collections.
+ *
+ * @serial
+ * @since 9
+ */
+final class CollSer implements Serializable {
+    private static final long serialVersionUID = 6309168927139932177L;
+
+    static final int IMM_LIST = 1;
+    static final int IMM_SET = 2;
+    static final int IMM_MAP = 3;
+
+    /**
+     * Indicates the type of collection that is serialized.
+     * The low order 8 bits have the value 1 for an immutable
+     * {@code List}, 2 for an immutable {@code Set}, and 3 for
+     * an immutable {@code Map}. Any other value causes an
+     * {@link InvalidObjectException} to be thrown. The high
+     * order 24 bits are zero when an instance is serialized,
+     * and they are ignored when an instance is deserialized.
+     * They can thus be used by future implementations without
+     * causing compatibility issues.
+     *
+     * <p>The tag value also determines the interpretation of the
+     * transient {@code Object[] array} field.
+     * For {@code List} and {@code Set}, the array's length is the size
+     * of the collection, and the array contains the elements of the collection.
+     * Null elements are not allowed. For {@code Set}, duplicate elements
+     * are not allowed.
+     *
+     * <p>For {@code Map}, the array's length is twice the number of mappings
+     * present in the map. The array length is necessarily even.
+     * The array contains a succession of key and value pairs:
+     * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
+     * and duplicate keys are not allowed.
+     *
+     * @serial
+     * @since 9
+     */
+    private final int tag;
+
+    /**
+     * @serial
+     * @since 9
+     */
+    private transient Object[] array;
+
+    CollSer(int t, Object... a) {
+        tag = t;
+        array = a;
+    }
+
+    /**
+     * Reads objects from the stream and stores them
+     * in the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param ois the ObjectInputStream from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     * @throws InvalidObjectException if the count is negative
+     * @since 9
+     */
+    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+        ois.defaultReadObject();
+        int len = ois.readInt();
+
+        if (len < 0) {
+            throw new InvalidObjectException("negative length " + len);
+        }
+
+        Object[] a = new Object[len];
+        for (int i = 0; i < len; i++) {
+            a[i] = ois.readObject();
+        }
+
+        array = a;
+    }
+
+    /**
+     * Writes objects to the stream from
+     * the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param oos the ObjectOutputStream to which data is written
+     * @throws IOException if an I/O error occurs
+     * @since 9
+     */
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+        oos.writeInt(array.length);
+        for (int i = 0; i < array.length; i++) {
+            oos.writeObject(array[i]);
+        }
+    }
+
+    /**
+     * Creates and returns an immutable collection from this proxy class.
+     * The instance returned is created as if by calling one of the
+     * static factory methods for
+     * <a href="List.html#immutable">List</a>,
+     * <a href="Map.html#immutable">Map</a>, or
+     * <a href="Set.html#immutable">Set</a>.
+     * This proxy class is the serial form for all immutable collection instances,
+     * regardless of implementation type. This is necessary to ensure that the
+     * existence of any particular implementation type is kept out of the
+     * serialized form.
+     *
+     * @return a collection created from this proxy object
+     * @throws InvalidObjectException if the tag value is illegal or if an exception
+     *         is thrown during creation of the collection
+     * @throws ObjectStreamException if another serialization error has occurred
+     * @since 9
+     */
+    private Object readResolve() throws ObjectStreamException {
+        try {
+            if (array == null) {
+                throw new InvalidObjectException("null array");
+            }
+
+            // use low order 8 bits to indicate "kind"
+            // ignore high order 24 bits
+            switch (tag & 0xff) {
+                case IMM_LIST:
+                    return List.of(array);
+                case IMM_SET:
+                    return Set.of(array);
+                case IMM_MAP:
+                    if (array.length == 0) {
+                        return ImmutableCollections.Map0.instance();
+                    } else if (array.length == 2) {
+                        return new ImmutableCollections.Map1<>(array[0], array[1]);
+                    } else {
+                        return new ImmutableCollections.MapN<>(array);
+                    }
+                default:
+                    throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
+            }
+        } catch (NullPointerException|IllegalArgumentException ex) {
+            InvalidObjectException ioe = new InvalidObjectException("invalid object");
+            ioe.initCause(ex);
+            throw ioe;
+        }
+    }
+}
diff --git a/ojluni/src/main/java/java/util/KeyValueHolder.java b/ojluni/src/main/java/java/util/KeyValueHolder.java
new file mode 100644
index 0000000..3b7250e
--- /dev/null
+++ b/ojluni/src/main/java/java/util/KeyValueHolder.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * An immutable container for a key and a value, suitable for use
+ * in creating and populating {@code Map} instances.
+ *
+ * <p>This is a <a href="../lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code KeyValueHolder} may have unpredictable results and should be avoided.
+ *
+ * @apiNote
+ * This class is not public. Instances can be created using the
+ * {@link Map#entry Map.entry(k, v)} factory method, which is public.
+ *
+ * <p>This class differs from AbstractMap.SimpleImmutableEntry in the following ways:
+ * it is not serializable, it is final, and its key and value must be non-null.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ *
+ * @see Map#ofEntries Map.ofEntries()
+ * @since 9
+ */
+final class KeyValueHolder<K,V> implements Map.Entry<K,V> {
+    @Stable
+    final K key;
+    @Stable
+    final V value;
+
+    KeyValueHolder(K k, V v) {
+        key = Objects.requireNonNull(k);
+        value = Objects.requireNonNull(v);
+    }
+
+    /**
+     * Gets the key from this holder.
+     *
+     * @return the key
+     */
+    @Override
+    public K getKey() {
+        return key;
+    }
+
+    /**
+     * Gets the value from this holder.
+     *
+     * @return the value
+     */
+    @Override
+    public V getValue() {
+        return value;
+    }
+
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @param value ignored
+     * @return never returns normally
+     */
+    @Override
+    public V setValue(V value) {
+        throw new UnsupportedOperationException("not supported");
+    }
+
+    /**
+     * Compares the specified object with this entry for equality.
+     * Returns {@code true} if the given object is also a map entry and
+     * the two entries' keys and values are equal. Note that key and
+     * value are non-null, so equals() can be called safely on them.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Map.Entry))
+            return false;
+        Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+        return key.equals(e.getKey()) && value.equals(e.getValue());
+    }
+
+    /**
+     * Returns the hash code value for this map entry. The hash code
+     * is {@code key.hashCode() ^ value.hashCode()}. Note that key and
+     * value are non-null, so hashCode() can be called safely on them.
+     */
+    @Override
+    public int hashCode() {
+        return key.hashCode() ^ value.hashCode();
+    }
+
+    /**
+     * Returns a String representation of this map entry.  This
+     * implementation returns the string representation of this
+     * entry's key followed by the equals character ("{@code =}")
+     * followed by the string representation of this entry's value.
+     *
+     * @return a String representation of this map entry
+     */
+    @Override
+    public String toString() {
+        return key + "=" + value;
+    }
+}
diff --git a/ojluni/src/main/java/java/util/List.java b/ojluni/src/main/java/java/util/List.java
index c15a522..1b9deb3 100644
--- a/ojluni/src/main/java/java/util/List.java
+++ b/ojluni/src/main/java/java/util/List.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 
 import java.util.function.UnaryOperator;
 
+// Android-removed: removed link to collections framework docs
 /**
  * An ordered collection (also known as a <i>sequence</i>).  The user of this
  * interface has precise control over where in the list each element is
@@ -34,50 +35,50 @@
  * the list), and search for elements in the list.<p>
  *
  * Unlike sets, lists typically allow duplicate elements.  More formally,
- * lists typically allow pairs of elements <tt>e1</tt> and <tt>e2</tt>
- * such that <tt>e1.equals(e2)</tt>, and they typically allow multiple
+ * lists typically allow pairs of elements {@code e1} and {@code e2}
+ * such that {@code e1.equals(e2)}, and they typically allow multiple
  * null elements if they allow null elements at all.  It is not inconceivable
  * that someone might wish to implement a list that prohibits duplicates, by
  * throwing runtime exceptions when the user attempts to insert them, but we
  * expect this usage to be rare.<p>
  *
- * The <tt>List</tt> interface places additional stipulations, beyond those
- * specified in the <tt>Collection</tt> interface, on the contracts of the
- * <tt>iterator</tt>, <tt>add</tt>, <tt>remove</tt>, <tt>equals</tt>, and
- * <tt>hashCode</tt> methods.  Declarations for other inherited methods are
+ * The {@code List} interface places additional stipulations, beyond those
+ * specified in the {@code Collection} interface, on the contracts of the
+ * {@code iterator}, {@code add}, {@code remove}, {@code equals}, and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
  * also included here for convenience.<p>
  *
- * The <tt>List</tt> interface provides four methods for positional (indexed)
+ * The {@code List} interface provides four methods for positional (indexed)
  * access to list elements.  Lists (like Java arrays) are zero based.  Note
  * that these operations may execute in time proportional to the index value
- * for some implementations (the <tt>LinkedList</tt> class, for
+ * for some implementations (the {@code LinkedList} class, for
  * example). Thus, iterating over the elements in a list is typically
  * preferable to indexing through it if the caller does not know the
  * implementation.<p>
  *
- * The <tt>List</tt> interface provides a special iterator, called a
- * <tt>ListIterator</tt>, that allows element insertion and replacement, and
+ * The {@code List} interface provides a special iterator, called a
+ * {@code ListIterator}, that allows element insertion and replacement, and
  * bidirectional access in addition to the normal operations that the
- * <tt>Iterator</tt> interface provides.  A method is provided to obtain a
+ * {@code Iterator} interface provides.  A method is provided to obtain a
  * list iterator that starts at a specified position in the list.<p>
  *
- * The <tt>List</tt> interface provides two methods to search for a specified
+ * The {@code List} interface provides two methods to search for a specified
  * object.  From a performance standpoint, these methods should be used with
  * caution.  In many implementations they will perform costly linear
  * searches.<p>
  *
- * The <tt>List</tt> interface provides two methods to efficiently insert and
+ * The {@code List} interface provides two methods to efficiently insert and
  * remove multiple elements at an arbitrary point in the list.<p>
  *
  * Note: While it is permissible for lists to contain themselves as elements,
- * extreme caution is advised: the <tt>equals</tt> and <tt>hashCode</tt>
+ * extreme caution is advised: the {@code equals} and {@code hashCode}
  * methods are no longer well defined on such a list.
  *
  * <p>Some list implementations have restrictions on the elements that
  * they may contain.  For example, some implementations prohibit null elements,
  * and some have restrictions on the types of their elements.  Attempting to
  * add an ineligible element throws an unchecked exception, typically
- * <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.  Attempting
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
  * to query the presence of an ineligible element may throw an exception,
  * or it may simply return false; some implementations will exhibit the former
  * behavior and some will exhibit the latter.  More generally, attempting an
@@ -87,9 +88,31 @@
  * Such exceptions are marked as "optional" in the specification for this
  * interface.
  *
- * <p>This interface is a member of the
- * <a href="{@docRoot}/../technotes/guides/collections/index.html">
- * Java Collections Framework</a>.
+ * <h2><a id="immutable">Immutable List Static Factory Methods</a></h2>
+ * <p>The {@link List#of(Object...) List.of()} static factory methods
+ * provide a convenient way to create immutable lists. The {@code List}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Elements cannot be added, removed,
+ * or replaced. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable,
+ * this may cause the List's contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>The order of elements in the list is the same as the order of the
+ * provided arguments, or of the elements in the provided array.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
  *
  * @param <E> the type of elements in this list
  *
@@ -113,28 +136,28 @@
 
     /**
      * Returns the number of elements in this list.  If this list contains
-     * more than <tt>Integer.MAX_VALUE</tt> elements, returns
-     * <tt>Integer.MAX_VALUE</tt>.
+     * more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
      *
      * @return the number of elements in this list
      */
     int size();
 
     /**
-     * Returns <tt>true</tt> if this list contains no elements.
+     * Returns {@code true} if this list contains no elements.
      *
-     * @return <tt>true</tt> if this list contains no elements
+     * @return {@code true} if this list contains no elements
      */
     boolean isEmpty();
 
     /**
-     * Returns <tt>true</tt> if this list contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this list contains
-     * at least one element <tt>e</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that
+     * {@code Objects.equals(o, e)}.
      *
      * @param o element whose presence in this list is to be tested
-     * @return <tt>true</tt> if this list contains the specified element
+     * @return {@code true} if this list contains the specified element
      * @throws ClassCastException if the type of the specified element
      *         is incompatible with this list
      * (<a href="Collection.html#optional-restrictions">optional</a>)
@@ -179,7 +202,7 @@
      *
      * <p>If the list fits in the specified array with room to spare (i.e.,
      * the array has more elements than the list), the element in the array
-     * immediately following the end of the list is set to <tt>null</tt>.
+     * immediately following the end of the list is set to {@code null}.
      * (This is useful in determining the length of the list <i>only</i> if
      * the caller knows that the list does not contain any null elements.)
      *
@@ -188,16 +211,16 @@
      * precise control over the runtime type of the output array, and may,
      * under certain circumstances, be used to save allocation costs.
      *
-     * <p>Suppose <tt>x</tt> is a list known to contain only strings.
+     * <p>Suppose {@code x} is a list known to contain only strings.
      * The following code can be used to dump the list into a newly
-     * allocated array of <tt>String</tt>:
+     * allocated array of {@code String}:
      *
      * <pre>{@code
      *     String[] y = x.toArray(new String[0]);
      * }</pre>
      *
-     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
-     * <tt>toArray()</tt>.
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
      *
      * @param a the array into which the elements of this list are to
      *          be stored, if it is big enough; otherwise, a new array of the
@@ -225,8 +248,8 @@
      * on what elements may be added.
      *
      * @param e element to be appended to this list
-     * @return <tt>true</tt> (as specified by {@link Collection#add})
-     * @throws UnsupportedOperationException if the <tt>add</tt> operation
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws UnsupportedOperationException if the {@code add} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this list
@@ -241,21 +264,21 @@
      * Removes the first occurrence of the specified element from this list,
      * if it is present (optional operation).  If this list does not contain
      * the element, it is unchanged.  More formally, removes the element with
-     * the lowest index <tt>i</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
-     * (if such an element exists).  Returns <tt>true</tt> if this list
+     * the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))}
+     * (if such an element exists).  Returns {@code true} if this list
      * contained the specified element (or equivalently, if this list changed
      * as a result of the call).
      *
      * @param o element to be removed from this list, if present
-     * @return <tt>true</tt> if this list contained the specified element
+     * @return {@code true} if this list contained the specified element
      * @throws ClassCastException if the type of the specified element
      *         is incompatible with this list
      * (<a href="Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null and this
      *         list does not permit null elements
      * (<a href="Collection.html#optional-restrictions">optional</a>)
-     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     * @throws UnsupportedOperationException if the {@code remove} operation
      *         is not supported by this list
      */
     boolean remove(Object o);
@@ -264,11 +287,11 @@
     // Bulk Modification Operations
 
     /**
-     * Returns <tt>true</tt> if this list contains all of the elements of the
+     * Returns {@code true} if this list contains all of the elements of the
      * specified collection.
      *
      * @param  c collection to be checked for containment in this list
-     * @return <tt>true</tt> if this list contains all of the elements of the
+     * @return {@code true} if this list contains all of the elements of the
      *         specified collection
      * @throws ClassCastException if the types of one or more elements
      *         in the specified collection are incompatible with this
@@ -292,8 +315,8 @@
      * specified collection is this list, and it's nonempty.)
      *
      * @param c collection containing elements to be added to this list
-     * @return <tt>true</tt> if this list changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of an element of the specified
      *         collection prevents it from being added to this list
@@ -320,8 +343,8 @@
      * @param index index at which to insert the first element from the
      *              specified collection
      * @param c collection containing elements to be added to this list
-     * @return <tt>true</tt> if this list changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of an element of the specified
      *         collection prevents it from being added to this list
@@ -331,7 +354,7 @@
      * @throws IllegalArgumentException if some property of an element of the
      *         specified collection prevents it from being added to this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt; size()</tt>)
+     *         ({@code index < 0 || index > size()})
      */
     boolean addAll(int index, Collection<? extends E> c);
 
@@ -340,8 +363,8 @@
      * specified collection (optional operation).
      *
      * @param c collection containing elements to be removed from this list
-     * @return <tt>true</tt> if this list changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
@@ -362,8 +385,8 @@
      * specified collection.
      *
      * @param c collection containing elements to be retained in this list
-     * @return <tt>true</tt> if this list changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>retainAll</tt> operation
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
@@ -443,12 +466,12 @@
      * &#064;Override
      * public void sort(Comparator&lt;? super E&gt; c) {
      *   Object[] elements = toArray();
-     *    Arrays.sort(elements, c);
-     *    ListIterator&lt;E&gt; iterator = (ListIterator&lt;Object&gt;) listIterator();
-     *    for (Object element : elements) {
-     *      iterator.next();
-     *      iterator.set((E) element);
-     *    }
+     *   Arrays.sort(elements, c);
+     *   ListIterator&lt;E&gt; iterator = (ListIterator&lt;Object&gt;) listIterator();
+     *   for (Object element : elements) {
+     *     iterator.next();
+     *     iterator.set((E) element);
+     *   }
      * }
      * </pre>
      *
@@ -510,7 +533,7 @@
      * Removes all of the elements from this list (optional operation).
      * The list will be empty after this call returns.
      *
-     * @throws UnsupportedOperationException if the <tt>clear</tt> operation
+     * @throws UnsupportedOperationException if the {@code clear} operation
      *         is not supported by this list
      */
     void clear();
@@ -520,17 +543,17 @@
 
     /**
      * Compares the specified object with this list for equality.  Returns
-     * <tt>true</tt> if and only if the specified object is also a list, both
+     * {@code true} if and only if the specified object is also a list, both
      * lists have the same size, and all corresponding pairs of elements in
-     * the two lists are <i>equal</i>.  (Two elements <tt>e1</tt> and
-     * <tt>e2</tt> are <i>equal</i> if <tt>(e1==null ? e2==null :
-     * e1.equals(e2))</tt>.)  In other words, two lists are defined to be
+     * the two lists are <i>equal</i>.  (Two elements {@code e1} and
+     * {@code e2} are <i>equal</i> if {@code Objects.equals(e1, e2)}.)
+     * In other words, two lists are defined to be
      * equal if they contain the same elements in the same order.  This
      * definition ensures that the equals method works properly across
-     * different implementations of the <tt>List</tt> interface.
+     * different implementations of the {@code List} interface.
      *
      * @param o the object to be compared for equality with this list
-     * @return <tt>true</tt> if the specified object is equal to this list
+     * @return {@code true} if the specified object is equal to this list
      */
     boolean equals(Object o);
 
@@ -542,9 +565,9 @@
      *     for (E e : list)
      *         hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
      * }</pre>
-     * This ensures that <tt>list1.equals(list2)</tt> implies that
-     * <tt>list1.hashCode()==list2.hashCode()</tt> for any two lists,
-     * <tt>list1</tt> and <tt>list2</tt>, as required by the general
+     * This ensures that {@code list1.equals(list2)} implies that
+     * {@code list1.hashCode()==list2.hashCode()} for any two lists,
+     * {@code list1} and {@code list2}, as required by the general
      * contract of {@link Object#hashCode}.
      *
      * @return the hash code value for this list
@@ -562,7 +585,7 @@
      * @param index index of the element to return
      * @return the element at the specified position in this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
+     *         ({@code index < 0 || index >= size()})
      */
     E get(int index);
 
@@ -573,7 +596,7 @@
      * @param index index of the element to replace
      * @param element element to be stored at the specified position
      * @return the element previously at the specified position
-     * @throws UnsupportedOperationException if the <tt>set</tt> operation
+     * @throws UnsupportedOperationException if the {@code set} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this list
@@ -582,7 +605,7 @@
      * @throws IllegalArgumentException if some property of the specified
      *         element prevents it from being added to this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
+     *         ({@code index < 0 || index >= size()})
      */
     E set(int index, E element);
 
@@ -594,7 +617,7 @@
      *
      * @param index index at which the specified element is to be inserted
      * @param element element to be inserted
-     * @throws UnsupportedOperationException if the <tt>add</tt> operation
+     * @throws UnsupportedOperationException if the {@code add} operation
      *         is not supported by this list
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this list
@@ -603,7 +626,7 @@
      * @throws IllegalArgumentException if some property of the specified
      *         element prevents it from being added to this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt; size()</tt>)
+     *         ({@code index < 0 || index > size()})
      */
     void add(int index, E element);
 
@@ -615,10 +638,10 @@
      *
      * @param index the index of the element to be removed
      * @return the element previously at the specified position
-     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     * @throws UnsupportedOperationException if the {@code remove} operation
      *         is not supported by this list
      * @throws IndexOutOfBoundsException if the index is out of range
-     *         (<tt>index &lt; 0 || index &gt;= size()</tt>)
+     *         ({@code index < 0 || index >= size()})
      */
     E remove(int index);
 
@@ -628,8 +651,8 @@
     /**
      * Returns the index of the first occurrence of the specified element
      * in this list, or -1 if this list does not contain the element.
-     * More formally, returns the lowest index <tt>i</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * More formally, returns the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
      * or -1 if there is no such index.
      *
      * @param o element to search for
@@ -647,8 +670,8 @@
     /**
      * Returns the index of the last occurrence of the specified element
      * in this list, or -1 if this list does not contain the element.
-     * More formally, returns the highest index <tt>i</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * More formally, returns the highest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
      * or -1 if there is no such index.
      *
      * @param o element to search for
@@ -696,8 +719,8 @@
 
     /**
      * Returns a view of the portion of this list between the specified
-     * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.  (If
-     * <tt>fromIndex</tt> and <tt>toIndex</tt> are equal, the returned list is
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
+     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
      * empty.)  The returned list is backed by this list, so non-structural
      * changes in the returned list are reflected in this list, and vice-versa.
      * The returned list supports all of the optional list operations supported
@@ -711,9 +734,9 @@
      * <pre>{@code
      *      list.subList(from, to).clear();
      * }</pre>
-     * Similar idioms may be constructed for <tt>indexOf</tt> and
-     * <tt>lastIndexOf</tt>, and all of the algorithms in the
-     * <tt>Collections</tt> class can be applied to a subList.<p>
+     * Similar idioms may be constructed for {@code indexOf} and
+     * {@code lastIndexOf}, and all of the algorithms in the
+     * {@code Collections} class can be applied to a subList.<p>
      *
      * The semantics of the list returned by this method become undefined if
      * the backing list (i.e., this list) is <i>structurally modified</i> in
@@ -725,8 +748,8 @@
      * @param toIndex high endpoint (exclusive) of the subList
      * @return a view of the specified range within this list
      * @throws IndexOutOfBoundsException for an illegal endpoint index value
-     *         (<tt>fromIndex &lt; 0 || toIndex &gt; size ||
-     *         fromIndex &gt; toIndex</tt>)
+     *         ({@code fromIndex < 0 || toIndex > size ||
+     *         fromIndex > toIndex})
      */
     List<E> subList(int fromIndex, int toIndex);
 
@@ -739,9 +762,22 @@
      *
      * @implSpec
      * The default implementation creates a
-     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
-     * from the list's {@code Iterator}.  The spliterator inherits the
-     * <em>fail-fast</em> properties of the list's iterator.
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * spliterator as follows:
+     * <ul>
+     * <li>If the list is an instance of {@link RandomAccess} then the default
+     *     implementation creates a spliterator that traverses elements by
+     *     invoking the method {@link List#get}.  If such invocation results or
+     *     would result in an {@code IndexOutOfBoundsException} then the
+     *     spliterator will <em>fail-fast</em> and throw a
+     *     {@code ConcurrentModificationException}.
+     *     If the list is also an instance of {@link AbstractList} then the
+     *     spliterator will use the list's {@link AbstractList#modCount modCount}
+     *     field to provide additional <em>fail-fast</em> behavior.
+     * <li>Otherwise, the default implementation creates a spliterator from the
+     *     list's {@code Iterator}.  The spliterator inherits the
+     *     <em>fail-fast</em> of the list's iterator.
+     * </ul>
      *
      * @implNote
      * The created {@code Spliterator} additionally reports
@@ -752,6 +788,274 @@
      */
     @Override
     default Spliterator<E> spliterator() {
-        return Spliterators.spliterator(this, Spliterator.ORDERED);
+        if (this instanceof RandomAccess) {
+            return new AbstractList.RandomAccessSpliterator<>(this);
+        } else {
+            return Spliterators.spliterator(this, Spliterator.ORDERED);
+        }
+    }
+
+    /**
+     * Returns an immutable list containing zero elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @return an empty {@code List}
+     *
+     * @since 9
+     */
+    static <E> List<E> of() {
+        return ImmutableCollections.List0.instance();
+    }
+
+    /**
+     * Returns an immutable list containing one element.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the single element
+     * @return a {@code List} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1) {
+        return new ImmutableCollections.List1<>(e1);
+    }
+
+    /**
+     * Returns an immutable list containing two elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2) {
+        return new ImmutableCollections.List2<>(e1, e2);
+    }
+
+    /**
+     * Returns an immutable list containing three elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an immutable list containing four elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an immutable list containing five elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an immutable list containing six elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6);
+    }
+
+    /**
+     * Returns an immutable list containing seven elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7);
+    }
+
+    /**
+     * Returns an immutable list containing eight elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8);
+    }
+
+    /**
+     * Returns an immutable list containing nine elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an immutable list containing ten elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an immutable list containing an arbitrary number of elements.
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting list will be the component type of the array, and the size of
+     * the list will be equal to the length of the array. To create a list with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     List<String[]> list = List.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link List#of(Object) List.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param elements the elements to be contained in the list
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> List<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                return ImmutableCollections.List0.instance();
+            case 1:
+                return new ImmutableCollections.List1<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.List2<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.ListN<>(elements);
+        }
     }
 }
diff --git a/ojluni/src/main/java/java/util/Map.java b/ojluni/src/main/java/java/util/Map.java
index 2715b15..ed365ec 100644
--- a/ojluni/src/main/java/java/util/Map.java
+++ b/ojluni/src/main/java/java/util/Map.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@
 import java.util.function.Function;
 import java.io.Serializable;
 
-// Android-changed: removed docs for removed OpenJDK 9 Immutable Map static methods
 // Android-changed: removed link to collections framework docs
 /**
  * An object that maps keys to values.  A map cannot contain duplicate keys;
@@ -112,6 +111,35 @@
  * Implementations may optionally handle the self-referential scenario, however
  * most current implementations do not do so.
  *
+ * <h2><a id="immutable">Immutable Map Static Factory Methods</a></h2>
+ * <p>The {@link Map#of() Map.of()} and
+ * {@link Map#ofEntries(Map.Entry...) Map.ofEntries()}
+ * static factory methods provide a convenient way to create immutable maps.
+ * The {@code Map}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Keys and values cannot be added,
+ * removed, or updated. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained keys or values are themselves mutable, this may cause the
+ * Map to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} keys and values. Attempts to create them with
+ * {@code null} keys or values result in {@code NullPointerException}.
+ * <li>They are serializable if all keys and values are serializable.
+ * <li>They reject duplicate keys at creation time. Duplicate keys
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of mappings is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
  *
@@ -1245,5 +1273,384 @@
         return newValue;
     }
 
-    // Android-removed: OpenJDK 9 Immutable Map static methods
+    /**
+     * Returns an immutable map containing zero mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @return an empty {@code Map}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of() {
+        return ImmutableCollections.Map0.instance();
+    }
+
+    /**
+     * Returns an immutable map containing a single mapping.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the mapping's key
+     * @param v1 the mapping's value
+     * @return a {@code Map} containing the specified mapping
+     * @throws NullPointerException if the key or the value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1) {
+        return new ImmutableCollections.Map1<>(k1, v1);
+    }
+
+    /**
+     * Returns an immutable map containing two mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if the keys are duplicates
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
+    }
+
+    /**
+     * Returns an immutable map containing three mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
+    }
+
+    /**
+     * Returns an immutable map containing four mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
+    }
+
+    /**
+     * Returns an immutable map containing five mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
+    }
+
+    /**
+     * Returns an immutable map containing six mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6);
+    }
+
+    /**
+     * Returns an immutable map containing seven mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7);
+    }
+
+    /**
+     * Returns an immutable map containing eight mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8);
+    }
+
+    /**
+     * Returns an immutable map containing nine mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9);
+    }
+
+    /**
+     * Returns an immutable map containing ten mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @param k10 the tenth mapping's key
+     * @param v10 the tenth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
+    }
+
+    /**
+     * Returns an immutable map containing keys and values extracted from the given entries.
+     * The entries themselves are not stored in the map.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
+     * For example,
+     *
+     * <pre>{@code
+     *     import static java.util.Map.entry;
+     *
+     *     Map<Integer,String> map = Map.ofEntries(
+     *         entry(1, "a"),
+     *         entry(2, "b"),
+     *         entry(3, "c"),
+     *         ...
+     *         entry(26, "z"));
+     * }</pre>
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param entries {@code Map.Entry}s containing the keys and values from which the map is populated
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any entry, key, or value is {@code null}, or if
+     *         the {@code entries} array is {@code null}
+     *
+     * @see Map#entry Map.entry()
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
+        if (entries.length == 0) { // implicit null check of entries
+            return ImmutableCollections.Map0.instance();
+        } else if (entries.length == 1) {
+            return new ImmutableCollections.Map1<>(entries[0].getKey(),
+                                                   entries[0].getValue());
+        } else {
+            Object[] kva = new Object[entries.length << 1];
+            int a = 0;
+            for (Entry<? extends K, ? extends V> entry : entries) {
+                kva[a++] = entry.getKey();
+                kva[a++] = entry.getValue();
+            }
+            return new ImmutableCollections.MapN<>(kva);
+        }
+    }
+
+    /**
+     * Returns an immutable {@link Entry} containing the given key and value.
+     * These entries are suitable for populating {@code Map} instances using the
+     * {@link Map#ofEntries Map.ofEntries()} method.
+     * The {@code Entry} instances created by this method have the following characteristics:
+     *
+     * <ul>
+     * <li>They disallow {@code null} keys and values. Attempts to create them using a {@code null}
+     * key or value result in {@code NullPointerException}.
+     * <li>They are immutable. Calls to {@link Entry#setValue Entry.setValue()}
+     * on a returned {@code Entry} result in {@code UnsupportedOperationException}.
+     * <li>They are not serializable.
+     * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+     * Callers should make no assumptions about the identity of the returned instances.
+     * This method is free to create new instances or reuse existing ones. Therefore,
+     * identity-sensitive operations on these instances (reference equality ({@code ==}),
+     * identity hash code, and synchronization) are unreliable and should be avoided.
+     * </ul>
+     *
+     * @apiNote
+     * For a serializable {@code Entry}, see {@link AbstractMap.SimpleEntry} or
+     * {@link AbstractMap.SimpleImmutableEntry}.
+     *
+     * @param <K> the key's type
+     * @param <V> the value's type
+     * @param k the key
+     * @param v the value
+     * @return an {@code Entry} containing the specified key and value
+     * @throws NullPointerException if the key or value is {@code null}
+     *
+     * @see Map#ofEntries Map.ofEntries()
+     * @since 9
+     */
+    static <K, V> Entry<K, V> entry(K k, V v) {
+        // KeyValueHolder checks for nulls
+        return new KeyValueHolder<>(k, v);
+    }
 }
diff --git a/ojluni/src/main/java/java/util/Objects.java b/ojluni/src/main/java/java/util/Objects.java
index e526079..1f76487 100644
--- a/ojluni/src/main/java/java/util/Objects.java
+++ b/ojluni/src/main/java/java/util/Objects.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,30 @@
 
 package java.util;
 
+import jdk.internal.util.Preconditions;
+
 import java.util.function.Supplier;
 
 /**
  * This class consists of {@code static} utility methods for operating
- * on objects.  These utilities include {@code null}-safe or {@code
- * null}-tolerant methods for computing the hash code of an object,
- * returning a string for an object, and comparing two objects.
+ * on objects, or checking certain conditions before operation.  These utilities
+ * include {@code null}-safe or {@code null}-tolerant methods for computing the
+ * hash code of an object, returning a string for an object, comparing two
+ * objects, and checking if indexes or sub-range values are out-of-bounds.
+ *
+ * @apiNote
+ * Static methods such as {@link Objects#checkIndex},
+ * {@link Objects#checkFromToIndex}, and {@link Objects#checkFromIndexSize} are
+ * provided for the convenience of checking if values corresponding to indexes
+ * and sub-ranges are out-of-bounds.
+ * Variations of these static methods support customization of the runtime
+ * exception, and corresponding exception detail message, that is thrown when
+ * values are out-of-bounds.  Such methods accept a functional interface
+ * argument, instances of {@code BiFunction}, that maps out-of-bound values to a
+ * runtime exception.  Care should be taken when using such methods in
+ * combination with an argument that is a lambda expression, method reference or
+ * class that capture values.  In such cases the cost of capture, related to
+ * functional interface allocation, may exceed the cost of checking bounds.
  *
  * @since 1.7
  */
@@ -266,6 +283,44 @@
     }
 
     /**
+     * Returns the first argument if it is non-{@code null} and
+     * otherwise returns the non-{@code null} second argument.
+     *
+     * @param obj an object
+     * @param defaultObj a non-{@code null} object to return if the first argument
+     *                   is {@code null}
+     * @param <T> the type of the reference
+     * @return the first argument if it is non-{@code null} and
+     *        otherwise the second argument if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        {@code defaultObj} is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElse(T obj, T defaultObj) {
+        return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
+    }
+
+    /**
+     * Returns the first argument if it is non-{@code null} and otherwise
+     * returns the non-{@code null} value of {@code supplier.get()}.
+     *
+     * @param obj an object
+     * @param supplier of a non-{@code null} object to return if the first argument
+     *                 is {@code null}
+     * @param <T> the type of the first argument and return type
+     * @return the first argument if it is non-{@code null} and otherwise
+     *         the value from {@code supplier.get()} if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        either the {@code supplier} is {@code null} or
+     *        the {@code supplier.get()} value is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) {
+        return (obj != null) ? obj
+                : requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()");
+    }
+
+    /**
      * Checks that the specified object reference is not {@code null} and
      * throws a customized {@link NullPointerException} if it is.
      *
@@ -287,7 +342,86 @@
      */
     public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
         if (obj == null)
-            throw new NullPointerException(messageSupplier.get());
+            throw new NullPointerException(messageSupplier == null ?
+                                           null : messageSupplier.get());
         return obj;
     }
+
+    /**
+     * Checks if the {@code index} is within the bounds of the range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The {@code index} is defined to be out-of-bounds if any of the
+     * following inequalities is true:
+     * <ul>
+     *  <li>{@code index < 0}</li>
+     *  <li>{@code index >= length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param index the index
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code index} if it is within bounds of the range
+     * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds
+     * @since 9
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    //@ForceInline
+    public static
+    int checkIndex(int index, int length) {
+        return Preconditions.checkIndex(index, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+     * (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code fromIndex > toIndex}</li>
+     *  <li>{@code toIndex > length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-range
+     * @param toIndex the upper-bound (exclusive) of the sub-range
+     * @param length the upper-bound (exclusive) the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds
+     * @since 9
+     */
+    public static
+    int checkFromToIndex(int fromIndex, int toIndex, int length) {
+        return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code fromIndex + size} (exclusive) is within the bounds of range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code size < 0}</li>
+     *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-interval
+     * @param size the size of the sub-range
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds
+     * @since 9
+     */
+    public static
+    int checkFromIndexSize(int fromIndex, int size, int length) {
+        return Preconditions.checkFromIndexSize(fromIndex, size, length, null);
+    }
+
 }
diff --git a/ojluni/src/main/java/java/util/Set.java b/ojluni/src/main/java/java/util/Set.java
index 2703049..0499ea3 100644
--- a/ojluni/src/main/java/java/util/Set.java
+++ b/ojluni/src/main/java/java/util/Set.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,16 +27,16 @@
 
 /**
  * A collection that contains no duplicate elements.  More formally, sets
- * contain no pair of elements <code>e1</code> and <code>e2</code> such that
- * <code>e1.equals(e2)</code>, and at most one null element.  As implied by
+ * contain no pair of elements {@code e1} and {@code e2} such that
+ * {@code e1.equals(e2)}, and at most one null element.  As implied by
  * its name, this interface models the mathematical <i>set</i> abstraction.
  *
- * <p>The <tt>Set</tt> interface places additional stipulations, beyond those
- * inherited from the <tt>Collection</tt> interface, on the contracts of all
- * constructors and on the contracts of the <tt>add</tt>, <tt>equals</tt> and
- * <tt>hashCode</tt> methods.  Declarations for other inherited methods are
+ * <p>The {@code Set} interface places additional stipulations, beyond those
+ * inherited from the {@code Collection} interface, on the contracts of all
+ * constructors and on the contracts of the {@code add}, {@code equals} and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
  * also included here for convenience.  (The specifications accompanying these
- * declarations have been tailored to the <tt>Set</tt> interface, but they do
+ * declarations have been tailored to the {@code Set} interface, but they do
  * not contain any additional stipulations.)
  *
  * <p>The additional stipulation on constructors is, not surprisingly,
@@ -45,7 +45,7 @@
  *
  * <p>Note: Great care must be exercised if mutable objects are used as set
  * elements.  The behavior of a set is not specified if the value of an object
- * is changed in a manner that affects <tt>equals</tt> comparisons while the
+ * is changed in a manner that affects {@code equals} comparisons while the
  * object is an element in the set.  A special case of this prohibition is
  * that it is not permissible for a set to contain itself as an element.
  *
@@ -53,7 +53,7 @@
  * they may contain.  For example, some implementations prohibit null elements,
  * and some have restrictions on the types of their elements.  Attempting to
  * add an ineligible element throws an unchecked exception, typically
- * <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.  Attempting
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
  * to query the presence of an ineligible element may throw an exception,
  * or it may simply return false; some implementations will exhibit the former
  * behavior and some will exhibit the latter.  More generally, attempting an
@@ -63,6 +63,33 @@
  * Such exceptions are marked as "optional" in the specification for this
  * interface.
  *
+ * <h2><a id="immutable">Immutable Set Static Factory Methods</a></h2>
+ * <p>The {@link Set#of(Object...) Set.of()} static factory methods
+ * provide a convenient way to create immutable sets. The {@code Set}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Elements cannot be added or
+ * removed. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable, this may cause the
+ * Set to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>They reject duplicate elements at creation time. Duplicate elements
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of set elements is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
  * <p>This interface is a member of the
  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
@@ -87,28 +114,28 @@
 
     /**
      * Returns the number of elements in this set (its cardinality).  If this
-     * set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
-     * <tt>Integer.MAX_VALUE</tt>.
+     * set contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
      *
      * @return the number of elements in this set (its cardinality)
      */
     int size();
 
     /**
-     * Returns <tt>true</tt> if this set contains no elements.
+     * Returns {@code true} if this set contains no elements.
      *
-     * @return <tt>true</tt> if this set contains no elements
+     * @return {@code true} if this set contains no elements
      */
     boolean isEmpty();
 
     /**
-     * Returns <tt>true</tt> if this set contains the specified element.
-     * More formally, returns <tt>true</tt> if and only if this set
-     * contains an element <tt>e</tt> such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * {@code Objects.equals(o, e)}.
      *
      * @param o element whose presence in this set is to be tested
-     * @return <tt>true</tt> if this set contains the specified element
+     * @return {@code true} if this set contains the specified element
      * @throws ClassCastException if the type of the specified element
      *         is incompatible with this set
      * (<a href="Collection.html#optional-restrictions">optional</a>)
@@ -155,7 +182,7 @@
      * <p>If this set fits in the specified array with room to spare
      * (i.e., the array has more elements than this set), the element in
      * the array immediately following the end of the set is set to
-     * <tt>null</tt>.  (This is useful in determining the length of this
+     * {@code null}.  (This is useful in determining the length of this
      * set <i>only</i> if the caller knows that this set does not contain
      * any null elements.)
      *
@@ -168,15 +195,15 @@
      * precise control over the runtime type of the output array, and may,
      * under certain circumstances, be used to save allocation costs.
      *
-     * <p>Suppose <tt>x</tt> is a set known to contain only strings.
+     * <p>Suppose {@code x} is a set known to contain only strings.
      * The following code can be used to dump the set into a newly allocated
-     * array of <tt>String</tt>:
+     * array of {@code String}:
      *
      * <pre>
      *     String[] y = x.toArray(new String[0]);</pre>
      *
-     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
-     * <tt>toArray()</tt>.
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
      *
      * @param a the array into which the elements of this set are to be
      *        stored, if it is big enough; otherwise, a new array of the same
@@ -195,25 +222,25 @@
     /**
      * Adds the specified element to this set if it is not already present
      * (optional operation).  More formally, adds the specified element
-     * <tt>e</tt> to this set if the set contains no element <tt>e2</tt>
+     * {@code e} to this set if the set contains no element {@code e2}
      * such that
-     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
+     * {@code Objects.equals(e, e2)}.
      * If this set already contains the element, the call leaves the set
-     * unchanged and returns <tt>false</tt>.  In combination with the
+     * unchanged and returns {@code false}.  In combination with the
      * restriction on constructors, this ensures that sets never contain
      * duplicate elements.
      *
      * <p>The stipulation above does not imply that sets must accept all
      * elements; sets may refuse to add any particular element, including
-     * <tt>null</tt>, and throw an exception, as described in the
+     * {@code null}, and throw an exception, as described in the
      * specification for {@link Collection#add Collection.add}.
      * Individual set implementations should clearly document any
      * restrictions on the elements that they may contain.
      *
      * @param e element to be added to this set
-     * @return <tt>true</tt> if this set did not already contain the specified
+     * @return {@code true} if this set did not already contain the specified
      *         element
-     * @throws UnsupportedOperationException if the <tt>add</tt> operation
+     * @throws UnsupportedOperationException if the {@code add} operation
      *         is not supported by this set
      * @throws ClassCastException if the class of the specified element
      *         prevents it from being added to this set
@@ -227,23 +254,23 @@
 
     /**
      * Removes the specified element from this set if it is present
-     * (optional operation).  More formally, removes an element <tt>e</tt>
+     * (optional operation).  More formally, removes an element {@code e}
      * such that
-     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if
-     * this set contains such an element.  Returns <tt>true</tt> if this set
+     * {@code Objects.equals(o, e)}, if
+     * this set contains such an element.  Returns {@code true} if this set
      * contained the element (or equivalently, if this set changed as a
      * result of the call).  (This set will not contain the element once the
      * call returns.)
      *
      * @param o object to be removed from this set, if present
-     * @return <tt>true</tt> if this set contained the specified element
+     * @return {@code true} if this set contained the specified element
      * @throws ClassCastException if the type of the specified element
      *         is incompatible with this set
      * (<a href="Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if the specified element is null and this
      *         set does not permit null elements
      * (<a href="Collection.html#optional-restrictions">optional</a>)
-     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     * @throws UnsupportedOperationException if the {@code remove} operation
      *         is not supported by this set
      */
     boolean remove(Object o);
@@ -252,12 +279,12 @@
     // Bulk Operations
 
     /**
-     * Returns <tt>true</tt> if this set contains all of the elements of the
+     * Returns {@code true} if this set contains all of the elements of the
      * specified collection.  If the specified collection is also a set, this
-     * method returns <tt>true</tt> if it is a <i>subset</i> of this set.
+     * method returns {@code true} if it is a <i>subset</i> of this set.
      *
      * @param  c collection to be checked for containment in this set
-     * @return <tt>true</tt> if this set contains all of the elements of the
+     * @return {@code true} if this set contains all of the elements of the
      *         specified collection
      * @throws ClassCastException if the types of one or more elements
      *         in the specified collection are incompatible with this
@@ -275,15 +302,15 @@
     /**
      * Adds all of the elements in the specified collection to this set if
      * they're not already present (optional operation).  If the specified
-     * collection is also a set, the <tt>addAll</tt> operation effectively
+     * collection is also a set, the {@code addAll} operation effectively
      * modifies this set so that its value is the <i>union</i> of the two
      * sets.  The behavior of this operation is undefined if the specified
      * collection is modified while the operation is in progress.
      *
      * @param  c collection containing elements to be added to this set
-     * @return <tt>true</tt> if this set changed as a result of the call
+     * @return {@code true} if this set changed as a result of the call
      *
-     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     * @throws UnsupportedOperationException if the {@code addAll} operation
      *         is not supported by this set
      * @throws ClassCastException if the class of an element of the
      *         specified collection prevents it from being added to this set
@@ -305,8 +332,8 @@
      * <i>intersection</i> of the two sets.
      *
      * @param  c collection containing elements to be retained in this set
-     * @return <tt>true</tt> if this set changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>retainAll</tt> operation
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
      *         is not supported by this set
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
@@ -327,8 +354,8 @@
      * the two sets.
      *
      * @param  c collection containing elements to be removed from this set
-     * @return <tt>true</tt> if this set changed as a result of the call
-     * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
      *         is not supported by this set
      * @throws ClassCastException if the class of an element of this set
      *         is incompatible with the specified collection
@@ -346,7 +373,7 @@
      * Removes all of the elements from this set (optional operation).
      * The set will be empty after this call returns.
      *
-     * @throws UnsupportedOperationException if the <tt>clear</tt> method
+     * @throws UnsupportedOperationException if the {@code clear} method
      *         is not supported by this set
      */
     void clear();
@@ -356,7 +383,7 @@
 
     /**
      * Compares the specified object with this set for equality.  Returns
-     * <tt>true</tt> if the specified object is also a set, the two sets
+     * {@code true} if the specified object is also a set, the two sets
      * have the same size, and every member of the specified set is
      * contained in this set (or equivalently, every member of this set is
      * contained in the specified set).  This definition ensures that the
@@ -364,17 +391,17 @@
      * set interface.
      *
      * @param o object to be compared for equality with this set
-     * @return <tt>true</tt> if the specified object is equal to this set
+     * @return {@code true} if the specified object is equal to this set
      */
     boolean equals(Object o);
 
     /**
      * Returns the hash code value for this set.  The hash code of a set is
      * defined to be the sum of the hash codes of the elements in the set,
-     * where the hash code of a <tt>null</tt> element is defined to be zero.
-     * This ensures that <tt>s1.equals(s2)</tt> implies that
-     * <tt>s1.hashCode()==s2.hashCode()</tt> for any two sets <tt>s1</tt>
-     * and <tt>s2</tt>, as required by the general contract of
+     * where the hash code of a {@code null} element is defined to be zero.
+     * This ensures that {@code s1.equals(s2)} implies that
+     * {@code s1.hashCode()==s2.hashCode()} for any two sets {@code s1}
+     * and {@code s2}, as required by the general contract of
      * {@link Object#hashCode}.
      *
      * @return the hash code value for this set
@@ -410,4 +437,267 @@
     default Spliterator<E> spliterator() {
         return Spliterators.spliterator(this, Spliterator.DISTINCT);
     }
+
+    /**
+     * Returns an immutable set containing zero elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @return an empty {@code Set}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of() {
+        return ImmutableCollections.Set0.instance();
+    }
+
+    /**
+     * Returns an immutable set containing one element.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the single element
+     * @return a {@code Set} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1) {
+        return new ImmutableCollections.Set1<>(e1);
+    }
+
+    /**
+     * Returns an immutable set containing two elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if the elements are duplicates
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2) {
+        return new ImmutableCollections.Set2<>(e1, e2);
+    }
+
+    /**
+     * Returns an immutable set containing three elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an immutable set containing four elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an immutable set containing five elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an immutable set containing six elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6);
+    }
+
+    /**
+     * Returns an immutable set containing seven elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7);
+    }
+
+    /**
+     * Returns an immutable set containing eight elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8);
+    }
+
+    /**
+     * Returns an immutable set containing nine elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an immutable set containing ten elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an immutable set containing an arbitrary number of elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting set will be the component type of the array, and the size of
+     * the set will be equal to the length of the array. To create a set with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     Set<String[]> list = Set.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link Set#of(Object) Set.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param elements the elements to be contained in the set
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> Set<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                return ImmutableCollections.Set0.instance();
+            case 1:
+                return new ImmutableCollections.Set1<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.Set2<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.SetN<>(elements);
+        }
+    }
 }
diff --git a/ojluni/src/main/java/java/util/concurrent/Flow.java b/ojluni/src/main/java/java/util/concurrent/Flow.java
new file mode 100644
index 0000000..0231790
--- /dev/null
+++ b/ojluni/src/main/java/java/util/concurrent/Flow.java
@@ -0,0 +1,319 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+// Android-changed: Remove reference to SubmissionPublisher class (not present on Android).
+/**
+ * Interrelated interfaces and static methods for establishing
+ * flow-controlled components in which {@link Publisher Publishers}
+ * produce items consumed by one or more {@link Subscriber
+ * Subscribers}, each managed by a {@link Subscription
+ * Subscription}.
+ *
+ * <p>These interfaces correspond to the <a
+ * href="http://www.reactive-streams.org/"> reactive-streams</a>
+ * specification.  They apply in both concurrent and distributed
+ * asynchronous settings: All (seven) methods are defined in {@code
+ * void} "one-way" message style. Communication relies on a simple form
+ * of flow control (method {@link Subscription#request}) that can be
+ * used to avoid resource management problems that may otherwise occur
+ * in "push" based systems.
+ *
+ * <p><b>Examples.</b> A {@link Publisher} usually defines its own
+ * {@link Subscription} implementation; constructing one in method
+ * {@code subscribe} and issuing it to the calling {@link
+ * Subscriber}. It publishes items to the subscriber asynchronously,
+ * normally using an {@link Executor}.  For example, here is a very
+ * simple publisher that only issues (when requested) a single {@code
+ * TRUE} item to a single subscriber.  Because the subscriber receives
+ * only a single item, this class does not use buffering and ordering
+ * control required in most implementations.
+ *
+ * <pre> {@code
+ * class OneShotPublisher implements Publisher<Boolean> {
+ *   private final ExecutorService executor = ForkJoinPool.commonPool(); // daemon-based
+ *   private boolean subscribed; // true after first subscribe
+ *   public synchronized void subscribe(Subscriber<? super Boolean> subscriber) {
+ *     if (subscribed)
+ *       subscriber.onError(new IllegalStateException()); // only one allowed
+ *     else {
+ *       subscribed = true;
+ *       subscriber.onSubscribe(new OneShotSubscription(subscriber, executor));
+ *     }
+ *   }
+ *   static class OneShotSubscription implements Subscription {
+ *     private final Subscriber<? super Boolean> subscriber;
+ *     private final ExecutorService executor;
+ *     private Future<?> future; // to allow cancellation
+ *     private boolean completed;
+ *     OneShotSubscription(Subscriber<? super Boolean> subscriber,
+ *                         ExecutorService executor) {
+ *       this.subscriber = subscriber;
+ *       this.executor = executor;
+ *     }
+ *     public synchronized void request(long n) {
+ *       if (n != 0 && !completed) {
+ *         completed = true;
+ *         if (n < 0) {
+ *           IllegalArgumentException ex = new IllegalArgumentException();
+ *           executor.execute(() -> subscriber.onError(ex));
+ *         } else {
+ *           future = executor.submit(() -> {
+ *             subscriber.onNext(Boolean.TRUE);
+ *             subscriber.onComplete();
+ *           });
+ *         }
+ *       }
+ *     }
+ *     public synchronized void cancel() {
+ *       completed = true;
+ *       if (future != null) future.cancel(false);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>A {@link Subscriber} arranges that items be requested and
+ * processed.  Items (invocations of {@link Subscriber#onNext}) are
+ * not issued unless requested, but multiple items may be requested.
+ * Many Subscriber implementations can arrange this in the style of
+ * the following example, where a buffer size of 1 single-steps, and
+ * larger sizes usually allow for more efficient overlapped processing
+ * with less communication; for example with a value of 64, this keeps
+ * total outstanding requests between 32 and 64.
+ * Because Subscriber method invocations for a given {@link
+ * Subscription} are strictly ordered, there is no need for these
+ * methods to use locks or volatiles unless a Subscriber maintains
+ * multiple Subscriptions (in which case it is better to instead
+ * define multiple Subscribers, each with its own Subscription).
+ *
+ * <pre> {@code
+ * class SampleSubscriber<T> implements Subscriber<T> {
+ *   final Consumer<? super T> consumer;
+ *   Subscription subscription;
+ *   final long bufferSize;
+ *   long count;
+ *   SampleSubscriber(long bufferSize, Consumer<? super T> consumer) {
+ *     this.bufferSize = bufferSize;
+ *     this.consumer = consumer;
+ *   }
+ *   public void onSubscribe(Subscription subscription) {
+ *     long initialRequestSize = bufferSize;
+ *     count = bufferSize - bufferSize / 2; // re-request when half consumed
+ *     (this.subscription = subscription).request(initialRequestSize);
+ *   }
+ *   public void onNext(T item) {
+ *     if (--count <= 0)
+ *       subscription.request(count = bufferSize - bufferSize / 2);
+ *     consumer.accept(item);
+ *   }
+ *   public void onError(Throwable ex) { ex.printStackTrace(); }
+ *   public void onComplete() {}
+ * }}</pre>
+ *
+ * <p>The default value of {@link #defaultBufferSize} may provide a
+ * useful starting point for choosing request sizes and capacities in
+ * Flow components based on expected rates, resources, and usages.
+ * Or, when flow control is never needed, a subscriber may initially
+ * request an effectively unbounded number of items, as in:
+ *
+ * <pre> {@code
+ * class UnboundedSubscriber<T> implements Subscriber<T> {
+ *   public void onSubscribe(Subscription subscription) {
+ *     subscription.request(Long.MAX_VALUE); // effectively unbounded
+ *   }
+ *   public void onNext(T item) { use(item); }
+ *   public void onError(Throwable ex) { ex.printStackTrace(); }
+ *   public void onComplete() {}
+ *   void use(T item) { ... }
+ * }}</pre>
+ *
+ * @author Doug Lea
+ * @since 9
+ */
+public final class Flow {
+
+    private Flow() {} // uninstantiable
+
+    /**
+     * A producer of items (and related control messages) received by
+     * Subscribers.  Each current {@link Subscriber} receives the same
+     * items (via method {@code onNext}) in the same order, unless
+     * drops or errors are encountered. If a Publisher encounters an
+     * error that does not allow items to be issued to a Subscriber,
+     * that Subscriber receives {@code onError}, and then receives no
+     * further messages.  Otherwise, when it is known that no further
+     * messages will be issued to it, a subscriber receives {@code
+     * onComplete}.  Publishers ensure that Subscriber method
+     * invocations for each subscription are strictly ordered in <a
+     * href="package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * order.
+     *
+     * <p>Publishers may vary in policy about whether drops (failures
+     * to issue an item because of resource limitations) are treated
+     * as unrecoverable errors.  Publishers may also vary about
+     * whether Subscribers receive items that were produced or
+     * available before they subscribed.
+     *
+     * @param <T> the published item type
+     */
+    @FunctionalInterface
+    public static interface Publisher<T> {
+        /**
+         * Adds the given Subscriber if possible.  If already
+         * subscribed, or the attempt to subscribe fails due to policy
+         * violations or errors, the Subscriber's {@code onError}
+         * method is invoked with an {@link IllegalStateException}.
+         * Otherwise, the Subscriber's {@code onSubscribe} method is
+         * invoked with a new {@link Subscription}.  Subscribers may
+         * enable receiving items by invoking the {@code request}
+         * method of this Subscription, and may unsubscribe by
+         * invoking its {@code cancel} method.
+         *
+         * @param subscriber the subscriber
+         * @throws NullPointerException if subscriber is null
+         */
+        public void subscribe(Subscriber<? super T> subscriber);
+    }
+
+    /**
+     * A receiver of messages.  The methods in this interface are
+     * invoked in strict sequential order for each {@link
+     * Subscription}.
+     *
+     * @param <T> the subscribed item type
+     */
+    public static interface Subscriber<T> {
+        /**
+         * Method invoked prior to invoking any other Subscriber
+         * methods for the given Subscription. If this method throws
+         * an exception, resulting behavior is not guaranteed, but may
+         * cause the Subscription not to be established or to be cancelled.
+         *
+         * <p>Typically, implementations of this method invoke {@code
+         * subscription.request} to enable receiving items.
+         *
+         * @param subscription a new subscription
+         */
+        public void onSubscribe(Subscription subscription);
+
+        /**
+         * Method invoked with a Subscription's next item.  If this
+         * method throws an exception, resulting behavior is not
+         * guaranteed, but may cause the Subscription to be cancelled.
+         *
+         * @param item the item
+         */
+        public void onNext(T item);
+
+        /**
+         * Method invoked upon an unrecoverable error encountered by a
+         * Publisher or Subscription, after which no other Subscriber
+         * methods are invoked by the Subscription.  If this method
+         * itself throws an exception, resulting behavior is
+         * undefined.
+         *
+         * @param throwable the exception
+         */
+        public void onError(Throwable throwable);
+
+        /**
+         * Method invoked when it is known that no additional
+         * Subscriber method invocations will occur for a Subscription
+         * that is not already terminated by error, after which no
+         * other Subscriber methods are invoked by the Subscription.
+         * If this method throws an exception, resulting behavior is
+         * undefined.
+         */
+        public void onComplete();
+    }
+
+    /**
+     * Message control linking a {@link Publisher} and {@link
+     * Subscriber}.  Subscribers receive items only when requested,
+     * and may cancel at any time. The methods in this interface are
+     * intended to be invoked only by their Subscribers; usages in
+     * other contexts have undefined effects.
+     */
+    public static interface Subscription {
+        /**
+         * Adds the given number {@code n} of items to the current
+         * unfulfilled demand for this subscription.  If {@code n} is
+         * less than or equal to zero, the Subscriber will receive an
+         * {@code onError} signal with an {@link
+         * IllegalArgumentException} argument.  Otherwise, the
+         * Subscriber will receive up to {@code n} additional {@code
+         * onNext} invocations (or fewer if terminated).
+         *
+         * @param n the increment of demand; a value of {@code
+         * Long.MAX_VALUE} may be considered as effectively unbounded
+         */
+        public void request(long n);
+
+        /**
+         * Causes the Subscriber to (eventually) stop receiving
+         * messages.  Implementation is best-effort -- additional
+         * messages may be received after invoking this method.
+         * A cancelled subscription need not ever receive an
+         * {@code onComplete} or {@code onError} signal.
+         */
+        public void cancel();
+    }
+
+    /**
+     * A component that acts as both a Subscriber and Publisher.
+     *
+     * @param <T> the subscribed item type
+     * @param <R> the published item type
+     */
+    public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
+    }
+
+    static final int DEFAULT_BUFFER_SIZE = 256;
+
+    /**
+     * Returns a default value for Publisher or Subscriber buffering,
+     * that may be used in the absence of other constraints.
+     *
+     * @implNote
+     * The current value returned is 256.
+     *
+     * @return the buffer size value
+     */
+    public static int defaultBufferSize() {
+        return DEFAULT_BUFFER_SIZE;
+    }
+
+}
diff --git a/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java b/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java
index b71d11a..c3e3c30 100644
--- a/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java
+++ b/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java
@@ -30,6 +30,7 @@
 import java.net.HttpURLConnection;
 import java.security.Principal;
 import java.security.cert.X509Certificate;
+import libcore.api.CorePlatformApi;
 
 /**
  * <code>HttpsURLConnection</code> extends <code>HttpURLConnection</code>
@@ -186,6 +187,8 @@
      * Holds the default instance so class preloading doesn't create an instance of
      * it.
      */
+    private static final String OK_HOSTNAME_VERIFIER_CLASS
+        = "com.android.okhttp.internal.tls.OkHostnameVerifier";
     private static class NoPreloadHolder {
         public static HostnameVerifier defaultHostnameVerifier;
         static {
@@ -197,7 +200,7 @@
                   * the server name from the certificate mismatch.
                   */
                 defaultHostnameVerifier = (HostnameVerifier)
-                        Class.forName("com.android.okhttp.internal.tls.OkHostnameVerifier")
+                        Class.forName(OK_HOSTNAME_VERIFIER_CLASS)
                         .getField("INSTANCE").get(null);
             } catch (Exception e) {
                 throw new AssertionError("Failed to obtain okhttp HostnameVerifier", e);
@@ -319,6 +322,30 @@
         hostnameVerifier = v;
     }
 
+    // BEGIN Android-added: Core platform API to obtain a strict hostname verifier
+    /**
+     * Obtains a stricter <code>HostnameVerifier</code>.
+     *
+     * The <code>HostnameVerifier</code> returned by this method will reject certificates
+     * with wildcards for top-level domains such "*.com".
+     *
+     * @see com.squareup.okhttp.internal.tls.OkHostnameVerifier
+     *
+     * @hide
+     */
+    @CorePlatformApi
+    public static HostnameVerifier getStrictHostnameVerifier() {
+        try {
+            return (HostnameVerifier) Class
+                .forName(OK_HOSTNAME_VERIFIER_CLASS)
+                .getMethod("strictInstance")
+                .invoke(null);
+        } catch (Exception e) {
+            return null;
+        }
+     }
+    // END Android-added: Core platform API to obtain a strict hostname verifier
+
     /**
      * Gets the <code>HostnameVerifier</code> in place on this instance.
      *
diff --git a/ojluni/src/main/java/jdk/internal/util/Preconditions.java b/ojluni/src/main/java/jdk/internal/util/Preconditions.java
new file mode 100644
index 0000000..0e91afd
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/util/Preconditions.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.util;
+
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * Utility methods to check if state or arguments are correct.
+ *
+ */
+public class Preconditions {
+
+    /**
+     * Maps out-of-bounds values to a runtime exception.
+     *
+     * @param checkKind the kind of bounds check, whose name may correspond
+     *        to the name of one of the range check methods, checkIndex,
+     *        checkFromToIndex, checkFromIndexSize
+     * @param args the out-of-bounds arguments that failed the range check.
+     *        If the checkKind corresponds a the name of a range check method
+     *        then the bounds arguments are those that can be passed in order
+     *        to the method.
+     * @param oobef the exception formatter that when applied with a checkKind
+     *        and a list out-of-bounds arguments returns a runtime exception.
+     *        If {@code null} then, it is as if an exception formatter was
+     *        supplied that returns {@link IndexOutOfBoundsException} for any
+     *        given arguments.
+     * @return the runtime exception
+     */
+    private static RuntimeException outOfBounds(
+            BiFunction<String, List<Integer>, ? extends RuntimeException> oobef,
+            String checkKind,
+            Integer... args) {
+        List<Integer> largs = List.of(args);
+        RuntimeException e = oobef == null
+                             ? null : oobef.apply(checkKind, largs);
+        return e == null
+               ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e;
+    }
+
+    private static RuntimeException outOfBoundsCheckIndex(
+            BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
+            int index, int length) {
+        return outOfBounds(oobe, "checkIndex", index, length);
+    }
+
+    private static RuntimeException outOfBoundsCheckFromToIndex(
+            BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
+            int fromIndex, int toIndex, int length) {
+        return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length);
+    }
+
+    private static RuntimeException outOfBoundsCheckFromIndexSize(
+            BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
+            int fromIndex, int size, int length) {
+        return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length);
+    }
+
+    /**
+     * Returns an out-of-bounds exception formatter from an given exception
+     * factory.  The exception formatter is a function that formats an
+     * out-of-bounds message from its arguments and applies that message to the
+     * given exception factory to produce and relay an exception.
+     *
+     * <p>The exception formatter accepts two arguments: a {@code String}
+     * describing the out-of-bounds range check that failed, referred to as the
+     * <em>check kind</em>; and a {@code List<Integer>} containing the
+     * out-of-bound integer values that failed the check.  The list of
+     * out-of-bound values is not modified.
+     *
+     * <p>Three check kinds are supported {@code checkIndex},
+     * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding
+     * respectively to the specified application of an exception formatter as an
+     * argument to the out-of-bounds range check methods
+     * {@link #checkIndex(int, int, BiFunction) checkIndex},
+     * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and
+     * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}.
+     * Thus a supported check kind corresponds to a method name and the
+     * out-of-bound integer values correspond to method argument values, in
+     * order, preceding the exception formatter argument (similar in many
+     * respects to the form of arguments required for a reflective invocation of
+     * such a range check method).
+     *
+     * <p>Formatter arguments conforming to such supported check kinds will
+     * produce specific exception messages describing failed out-of-bounds
+     * checks.  Otherwise, more generic exception messages will be produced in
+     * any of the following cases: the check kind is supported but fewer
+     * or more out-of-bounds values are supplied, the check kind is not
+     * supported, the check kind is {@code null}, or the list of out-of-bound
+     * values is {@code null}.
+     *
+     * @apiNote
+     * This method produces an out-of-bounds exception formatter that can be
+     * passed as an argument to any of the supported out-of-bounds range check
+     * methods declared by {@code Objects}.  For example, a formatter producing
+     * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a
+     * {@code static final} field as follows:
+     * <pre>{@code
+     * static final
+     * BiFunction<String, List<Integer>, ArrayIndexOutOfBoundsException> AIOOBEF =
+     *     outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
+     * }</pre>
+     * The formatter instance {@code AIOOBEF} may be passed as an argument to an
+     * out-of-bounds range check method, such as checking if an {@code index}
+     * is within the bounds of a {@code limit}:
+     * <pre>{@code
+     * checkIndex(index, limit, AIOOBEF);
+     * }</pre>
+     * If the bounds check fails then the range check method will throw an
+     * {@code ArrayIndexOutOfBoundsException} with an appropriate exception
+     * message that is a produced from {@code AIOOBEF} as follows:
+     * <pre>{@code
+     * AIOOBEF.apply("checkIndex", List.of(index, limit));
+     * }</pre>
+     *
+     * @param f the exception factory, that produces an exception from a message
+     *        where the message is produced and formatted by the returned
+     *        exception formatter.  If this factory is stateless and side-effect
+     *        free then so is the returned formatter.
+     *        Exceptions thrown by the factory are relayed to the caller
+     *        of the returned formatter.
+     * @param <X> the type of runtime exception to be returned by the given
+     *        exception factory and relayed by the exception formatter
+     * @return the out-of-bounds exception formatter
+     */
+    public static <X extends RuntimeException>
+    BiFunction<String, List<Integer>, X> outOfBoundsExceptionFormatter(Function<String, X> f) {
+        // Use anonymous class to avoid bootstrap issues if this method is
+        // used early in startup
+        return new BiFunction<String, List<Integer>, X>() {
+            @Override
+            public X apply(String checkKind, List<Integer> args) {
+                return f.apply(outOfBoundsMessage(checkKind, args));
+            }
+        };
+    }
+
+    private static String outOfBoundsMessage(String checkKind, List<Integer> args) {
+        if (checkKind == null && args == null) {
+            return String.format("Range check failed");
+        } else if (checkKind == null) {
+            return String.format("Range check failed: %s", args);
+        } else if (args == null) {
+            return String.format("Range check failed: %s", checkKind);
+        }
+
+        int argSize = 0;
+        switch (checkKind) {
+            case "checkIndex":
+                argSize = 2;
+                break;
+            case "checkFromToIndex":
+            case "checkFromIndexSize":
+                argSize = 3;
+                break;
+            default:
+        }
+
+        // Switch to default if fewer or more arguments than required are supplied
+        switch ((args.size() != argSize) ? "" : checkKind) {
+            case "checkIndex":
+                return String.format("Index %d out-of-bounds for length %d",
+                                     args.get(0), args.get(1));
+            case "checkFromToIndex":
+                return String.format("Range [%d, %d) out-of-bounds for length %d",
+                                     args.get(0), args.get(1), args.get(2));
+            case "checkFromIndexSize":
+                return String.format("Range [%d, %<d + %d) out-of-bounds for length %d",
+                                     args.get(0), args.get(1), args.get(2));
+            default:
+                return String.format("Range check failed: %s %s", checkKind, args);
+        }
+    }
+
+    /**
+     * Checks if the {@code index} is within the bounds of the range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The {@code index} is defined to be out-of-bounds if any of the
+     * following inequalities is true:
+     * <ul>
+     *  <li>{@code index < 0}</li>
+     *  <li>{@code index >= length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * <p>If the {@code index} is out-of-bounds, then a runtime exception is
+     * thrown that is the result of applying the following arguments to the
+     * exception formatter: the name of this method, {@code checkIndex};
+     * and an unmodifiable list integers whose values are, in order, the
+     * out-of-bounds arguments {@code index} and {@code length}.
+     *
+     * @param <X> the type of runtime exception to throw if the arguments are
+     *        out-of-bounds
+     * @param index the index
+     * @param length the upper-bound (exclusive) of the range
+     * @param oobef the exception formatter that when applied with this
+     *        method name and out-of-bounds arguments returns a runtime
+     *        exception.  If {@code null} or returns {@code null} then, it is as
+     *        if an exception formatter produced from an invocation of
+     *        {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
+     *        instead (though it may be more efficient).
+     *        Exceptions thrown by the formatter are relayed to the caller.
+     * @return {@code index} if it is within bounds of the range
+     * @throws X if the {@code index} is out-of-bounds and the exception
+     *         formatter is non-{@code null}
+     * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds
+     *         and the exception formatter is {@code null}
+     * @since 9
+     *
+     * @implNote
+     * This method is made intrinsic in optimizing compilers to guide them to
+     * perform unsigned comparisons of the index and length when it is known the
+     * length is a non-negative value (such as that of an array length or from
+     * the upper bound of a loop)
+    */
+    // Android-removed: @HotSpotIntrinsicCandidate not present on Android yet (could reconsider).
+    // @HotSpotIntrinsicCandidate
+    public static <X extends RuntimeException>
+    int checkIndex(int index, int length,
+                   BiFunction<String, List<Integer>, X> oobef) {
+        if (index < 0 || index >= length)
+            throw outOfBoundsCheckIndex(oobef, index, length);
+        return index;
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+     * (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code fromIndex > toIndex}</li>
+     *  <li>{@code toIndex > length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * <p>If the sub-range  is out-of-bounds, then a runtime exception is
+     * thrown that is the result of applying the following arguments to the
+     * exception formatter: the name of this method, {@code checkFromToIndex};
+     * and an unmodifiable list integers whose values are, in order, the
+     * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}.
+     *
+     * @param <X> the type of runtime exception to throw if the arguments are
+     *        out-of-bounds
+     * @param fromIndex the lower-bound (inclusive) of the sub-range
+     * @param toIndex the upper-bound (exclusive) of the sub-range
+     * @param length the upper-bound (exclusive) the range
+     * @param oobef the exception formatter that when applied with this
+     *        method name and out-of-bounds arguments returns a runtime
+     *        exception.  If {@code null} or returns {@code null} then, it is as
+     *        if an exception formatter produced from an invocation of
+     *        {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
+     *        instead (though it may be more efficient).
+     *        Exceptions thrown by the formatter are relayed to the caller.
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws X if the sub-range is out-of-bounds and the exception factory
+     *         function is non-{@code null}
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and
+     *         the exception factory function is {@code null}
+     * @since 9
+     */
+    public static <X extends RuntimeException>
+    int checkFromToIndex(int fromIndex, int toIndex, int length,
+                         BiFunction<String, List<Integer>, X> oobef) {
+        if (fromIndex < 0 || fromIndex > toIndex || toIndex > length)
+            throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length);
+        return fromIndex;
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code fromIndex + size} (exclusive) is within the bounds of range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code size < 0}</li>
+     *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * <p>If the sub-range  is out-of-bounds, then a runtime exception is
+     * thrown that is the result of applying the following arguments to the
+     * exception formatter: the name of this method, {@code checkFromIndexSize};
+     * and an unmodifiable list integers whose values are, in order, the
+     * out-of-bounds arguments {@code fromIndex}, {@code size}, and
+     * {@code length}.
+     *
+     * @param <X> the type of runtime exception to throw if the arguments are
+     *        out-of-bounds
+     * @param fromIndex the lower-bound (inclusive) of the sub-interval
+     * @param size the size of the sub-range
+     * @param length the upper-bound (exclusive) of the range
+     * @param oobef the exception formatter that when applied with this
+     *        method name and out-of-bounds arguments returns a runtime
+     *        exception.  If {@code null} or returns {@code null} then, it is as
+     *        if an exception formatter produced from an invocation of
+     *        {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used
+     *        instead (though it may be more efficient).
+     *        Exceptions thrown by the formatter are relayed to the caller.
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws X if the sub-range is out-of-bounds and the exception factory
+     *         function is non-{@code null}
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and
+     *         the exception factory function is {@code null}
+     * @since 9
+     */
+    public static <X extends RuntimeException>
+    int checkFromIndexSize(int fromIndex, int size, int length,
+                           BiFunction<String, List<Integer>, X> oobef) {
+        if ((length | fromIndex | size) < 0 || size > length - fromIndex)
+            throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length);
+        return fromIndex;
+    }
+}
diff --git a/ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java b/ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java
new file mode 100644
index 0000000..34b6540
--- /dev/null
+++ b/ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.vm.annotation;
+
+import java.lang.annotation.*;
+
+// Android-removed: HotSpot-specific implementation notes not relevant for Android.
+/**
+ * A field may be annotated as stable if all of its component variables
+ * changes value at most once.
+ * A field's value counts as its component value.
+ * If the field is typed as an array, then all the non-null components
+ * of the array, of depth up to the rank of the field's array type,
+ * also count as component values.
+ * By extension, any variable (either array or field) which has annotated
+ * as stable is called a stable variable, and its non-null or non-zero
+ * value is called a stable value.
+ * <p>
+ * Since all fields begin with a default value of null for references
+ * (resp., zero for primitives), it follows that this annotation indicates
+ * that the first non-null (resp., non-zero) value stored in the field
+ * will never be changed.
+ * <p>
+ * If the field is not of an array type, there are no array elements,
+ * then the value indicated as stable is simply the value of the field.
+ * If the dynamic type of the field value is an array but the static type
+ * is not, the components of the array are <em>not</em> regarded as stable.
+ * <p>
+ * If the field is an array type, then both the field value and
+ * all the components of the field value (if the field value is non-null)
+ * are indicated to be stable.
+ * If the field type is an array type with rank {@code N > 1},
+ * then each component of the field value (if the field value is non-null),
+ * is regarded as a stable array of rank {@code N-1}.
+ * <p>
+ * Fields which are declared {@code final} may also be annotated as stable.
+ * Since final fields already behave as stable values, such an annotation
+ * conveys no additional information regarding change of the field's value, but
+ * still conveys information regarding change of additional components values if
+ * the type of the field is an array type (as described above).
+ * <p>
+ * It is (currently) undefined what happens if a field annotated as stable
+ * is given a third value (by explicitly updating a stable field, a component of
+ * a stable array, or a final stable field via reflection or other means).
+ *
+ * @implNote
+ * This annotation only takes effect for fields of classes loaded by the boot
+ * loader.  Annoations on fields of classes loaded outside of the boot loader
+ * are ignored.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Stable {
+}
diff --git a/openjdk_java_files.bp b/openjdk_java_files.bp
index e966590..c1ee4ac 100644
--- a/openjdk_java_files.bp
+++ b/openjdk_java_files.bp
@@ -950,6 +950,7 @@
         "ojluni/src/main/java/java/util/concurrent/ExecutorCompletionService.java",
         "ojluni/src/main/java/java/util/concurrent/ExecutorService.java",
         "ojluni/src/main/java/java/util/concurrent/Executors.java",
+        "ojluni/src/main/java/java/util/concurrent/Flow.java",
         "ojluni/src/main/java/java/util/concurrent/ForkJoinPool.java",
         "ojluni/src/main/java/java/util/concurrent/ForkJoinTask.java",
         "ojluni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java",
@@ -1435,6 +1436,8 @@
         "ojluni/src/main/java/java/beans/ChangeListenerMap.java",
         "ojluni/src/main/java/java/time/zone/IcuZoneRulesProvider.java",
         "ojluni/src/main/java/java/time/zone/ZoneRulesProvider.java",
+        "ojluni/src/main/java/java/util/ImmutableCollections.java",
+        "ojluni/src/main/java/java/util/KeyValueHolder.java",
         "ojluni/src/main/java/java/util/JapaneseImperialCalendar.java",
         "ojluni/src/main/java/sun/misc/FDBigInteger.java",
         "ojluni/src/main/java/sun/misc/FloatingDecimal.java",
@@ -1442,6 +1445,8 @@
         "ojluni/src/main/java/jdk/net/NetworkPermission.java",
         "ojluni/src/main/java/jdk/net/SocketFlow.java",
         "ojluni/src/main/java/jdk/net/Sockets.java",
+        "ojluni/src/main/java/jdk/internal/vm/annotation/Stable.java",
+        "ojluni/src/main/java/jdk/internal/util/Preconditions.java",
         "ojluni/src/main/java/sun/invoke/util/BytecodeDescriptor.java",
         "ojluni/src/main/java/sun/invoke/util/Wrapper.java",
         "ojluni/src/main/java/sun/invoke/util/VerifyAccess.java",
diff --git a/test-rules/src/main/java/libcore/junit/util/SwitchTargetSdkVersionRule.java b/test-rules/src/main/java/libcore/junit/util/SwitchTargetSdkVersionRule.java
index 455d3cb..b860ea6 100644
--- a/test-rules/src/main/java/libcore/junit/util/SwitchTargetSdkVersionRule.java
+++ b/test-rules/src/main/java/libcore/junit/util/SwitchTargetSdkVersionRule.java
@@ -135,8 +135,8 @@
         public void evaluate() throws Throwable {
           Object runtime = runtimeInstanceGetter.invoke(null);
           int oldTargetSdkVersion = (int) targetSdkVersionGetter.invoke(runtime);
+          targetSdkVersionSetter.invoke(runtime, targetSdkVersion);
           try {
-            targetSdkVersionSetter.invoke(runtime, targetSdkVersion);
             statement.evaluate();
           } finally {
             targetSdkVersionSetter.invoke(runtime, oldTargetSdkVersion);
diff --git a/tools/upstream/src/main/java/libcore/CompareUpstreams.java b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
index bdd2364..0f4de21 100644
--- a/tools/upstream/src/main/java/libcore/CompareUpstreams.java
+++ b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
@@ -170,8 +170,7 @@
                 : null;
 
         for (Path relPath : relPaths) {
-            Repository expectedUpstream = standardRepositories.referenceUpstreamAsOfAndroidP(
-                relPath);
+            Repository expectedUpstream = standardRepositories.referenceUpstream(relPath);
             out.print(relPath + "\t");
             Path ojluniFile = standardRepositories.ojluni().absolutePath(relPath);
             List<String> linesB = Util.readLines(ojluniFile);
diff --git a/tools/upstream/src/main/java/libcore/CopyUpstreamFiles.java b/tools/upstream/src/main/java/libcore/CopyUpstreamFiles.java
index 7137861..807607f 100644
--- a/tools/upstream/src/main/java/libcore/CopyUpstreamFiles.java
+++ b/tools/upstream/src/main/java/libcore/CopyUpstreamFiles.java
@@ -45,8 +45,7 @@
             }
         }
         for (Path relPath : relPaths) {
-            Repository expectedUpstream = standardRepositories.referenceUpstreamAsOfAndroidP(
-                relPath);
+            Repository expectedUpstream = standardRepositories.referenceUpstream(relPath);
             for (Repository upstream : standardRepositories.upstreams()) {
                 Path upstreamFile = upstream.absolutePath(relPath);
                 if (upstreamFile != null) {
diff --git a/tools/upstream/src/main/java/libcore/StandardRepositories.java b/tools/upstream/src/main/java/libcore/StandardRepositories.java
index 31efe94..846b321 100644
--- a/tools/upstream/src/main/java/libcore/StandardRepositories.java
+++ b/tools/upstream/src/main/java/libcore/StandardRepositories.java
@@ -37,6 +37,7 @@
     private final List<Repository> historicUpstreams;
     private final Repository openJdk8u121;
     private final Repository openJdk9b113;
+    private final Repository openJdk9p181;
     private final Repository openJdk7u40;
     private final OjluniRepository ojluni;
 
@@ -46,6 +47,7 @@
         allUpstreams.add(openJdk9(upstreamRoot, "9+181"));
         this.openJdk9b113 = addAndReturn(allUpstreams, openJdk9(upstreamRoot, "9b113+"));
         this.openJdk8u121 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "8u121-b13"));
+        this.openJdk9p181 = addAndReturn(allUpstreams, openJdk9(upstreamRoot, "9+181"));
         Repository openJdk8u60 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "8u60"));
         this.openJdk7u40 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "7u40"));
         this.allUpstreams = Collections.unmodifiableList(new ArrayList<>(allUpstreams));
@@ -109,9 +111,26 @@
         return result;
     }
 
-    public Repository referenceUpstreamAsOfAndroidP(Path relPath) {
+    private static final Set<String> REL_PATHS_AT_OPENJDK9_181 = Collections.unmodifiableSet(
+            new HashSet<>(Arrays.asList(
+                    "java/util/concurrent/Flow.java",
+                    "java/util/AbstractList.java",
+                    "java/util/ImmutableCollections.java",
+                    "java/util/KeyValueHolder.java",
+                    "java/util/List.java",
+                    "java/util/Map.java",
+                    "java/util/Objects.java",
+                    "java/util/Set.java",
+                    "jdk/internal/HotSpotIntrinsicCandidate.java",
+                    "jdk/internal/vm/annotation/Stable.java",
+                    "jdk/internal/util/Preconditions.java"
+                    )));
+
+    public Repository referenceUpstream(Path relPath) {
         boolean isJsr166 = isJsr166(relPath);
-        if (isJsr166) {
+        if (REL_PATHS_AT_OPENJDK9_181.contains(relPath.toString())) {
+            return openJdk9p181;
+        } else if (isJsr166) {
             return openJdk9b113;
         } else if (relPath.startsWith("java/sql/") || relPath.startsWith("javax/sql/")) {
             return openJdk7u40;