Merge "[automerger skipped] Merge "[RESTRICT AUTOMERGE] Remove unnecessary test." into oreo-mr1-cts-dev am: 3b1e6518bd -s ours" into pie-cts-dev am: 8194bd87b5 -s ours am: 89072307a5 -s ours am: 7f6b6787fb am: 69beac6e54 -s ours

am skip reason: subject contains skip directive

Original change: https://android-review.googlesource.com/c/platform/libcore/+/1545729

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ic16db5e6bb1e21efe468f72fc98048c813dec835
diff --git a/Android.bp b/Android.bp
index e57045f..d205aeb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,21 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_visibility: ["//visibility:private"],
+}
+
 build = [
     "JavaLibrary.bp",
     "NativeCode.bp",
@@ -5,6 +23,9 @@
 
 genrule {
     name: "notices-for-framework-stubs",
+    visibility: [
+        "//frameworks/base",
+    ],
     tool_files: [
         "NOTICE",
         "ojluni/NOTICE",
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 465c964..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# -*- mode: makefile -*-
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-#
-# Subprojects with separate makefiles
-#
-
-subdirs := benchmarks tzdata ojluni tools/upstream metrictests
-subdir_makefiles := $(call all-named-subdir-makefiles,$(subdirs))
-
-#
-# Disable test modules if LIBCORE_SKIP_TESTS environment variable is set.
-#
-
-ifneq ($(LIBCORE_SKIP_TESTS),)
-$(info ********************************************************************************)
-$(info * libcore tests are skipped because environment variable LIBCORE_SKIP_TESTS=$(LIBCORE_SKIP_TESTS))
-$(info ********************************************************************************)
-endif
-
-include $(subdir_makefiles)
diff --git a/JavaLibrary.bp b/JavaLibrary.bp
index 2066c42..8b0ab3b 100644
--- a/JavaLibrary.bp
+++ b/JavaLibrary.bp
@@ -19,8 +19,8 @@
 // The Android core library provides low-level APIs for use by the rest of the
 // Android software stack. It is made up of various parts, some of which can be
 // found in libcore/ and other parts that can be found in various external/
-// directories. See the "core-system-modules" definition for the parts.
-
+// directories.
+//
 // libcore has some sub-directories that follow a common structure:
 // e.g. dalvik, dom, harmony-tests, json, jsr166-tests, luni, libart, ojluni,
 // support, xml, xmlpull.
@@ -45,14 +45,40 @@
 ]
 
 // The Java files and their associated resources.
-core_resource_dirs = [
-    "luni/src/main/java",
-    "ojluni/src/main/resources/",
+filegroup {
+    name: "core-luni-resources",
+    visibility: [
+        "//libcore:__subpackages__",
+    ],
+    path: "luni/src/main/java/",
+    srcs: [
+        "luni/src/main/java/java/util/logging/logging.properties",
+        "luni/src/main/java/java/security/security.properties",
+    ],
+}
+
+filegroup {
+    name: "core-ojluni-resources",
+    visibility: [
+        "//libcore:__subpackages__",
+    ],
+    path: "ojluni/src/main/resources/",
+    srcs: [
+        "ojluni/src/main/resources/**/*",
+    ],
+}
+
+core_resources = [
+    ":core-luni-resources",
+    ":core-ojluni-resources",
 ]
 
 // The source files that go into core-oj.
 filegroup {
     name: "core_oj_java_files",
+    visibility: [
+        "//libcore:__subpackages__",
+    ],
     srcs: [":openjdk_java_files"],
 }
 
@@ -66,9 +92,11 @@
 // The source files that go into core-libart.
 filegroup {
     name: "core_libart_java_files",
+    visibility: [
+        "//libcore:__subpackages__",
+    ],
     srcs: [
         ":non_openjdk_java_files",
-        ":android_icu4j_src_files",
     ],
 }
 
@@ -78,36 +106,26 @@
     name: "core_libart_api_files",
     srcs: [
         ":non_openjdk_javadoc_files",
-        ":android_icu4j_src_files",
     ],
 }
 
-// The set of files for the core library that have been marked up with @hide
-// for the public SDK APIs. Used from frameworks/base/ to indicate the source
-// files for inclusion in the public SDK docs.
-filegroup {
-    name: "core_public_api_files",
-    srcs: [
-        ":core_oj_api_files",
-        ":core_libart_api_files",
-        ":conscrypt_public_api_files",
-    ],
-}
-
-// The set of files for the core library that have been marked up with @hide and
-// API-related annotations. Note that this includes the intra-core and
-// core-platform APIs as well as the public APIs.
+// The set of files for the ART module that contribute to one or more API
+// surfaces. This includes files that are in the public API as well as those
+// that are not but which have been marked up with @hide plus one or more of
+// the API defining annotations.
 //
 // Some source files in :core_oj_api_files and :openjdk_mmodule_extra_files are
 // annotated by applying annotations to the .annotated.java stubs files in
 // ojluni/annotated/mmodules and rather than in the original source. See the comments
 // in openjdk_java_files.bp for more details.
 filegroup {
-    name: "core_api_files",
+    name: "art_module_api_files",
+    visibility: [
+        "//libcore:__subpackages__",
+    ],
     srcs: [
         ":apache-xml_api_files",
         ":bouncycastle_java_files",
-        ":conscrypt_java_files",
         ":core_oj_api_files",
         ":core_libart_api_files",
         ":okhttp_api_files",
@@ -124,8 +142,8 @@
     dxflags: ["--core-library"],
     errorprone: {
         javacflags: [
-            "-Xep:MissingOverride:OFF",  // Ignore missing @Override.
-            "-Xep:ConstantOverflow:WARN",  // Known constant overflow in SplittableRandom
+            "-Xep:MissingOverride:OFF", // Ignore missing @Override.
+            "-Xep:ConstantOverflow:WARN", // Known constant overflow in SplittableRandom
         ],
     },
 }
@@ -134,41 +152,46 @@
 // Build for the target (device).
 //
 
-// Rule generating resource lib for android_icu4j.
-// In the downstream branch master-icu-dev, the resource files are generated.
-// This rule can't be moved external/icu because soong enforces that no_standard_libs:true can only
-// be used in libcore/ or development/
-java_library {
-    name: "android_icu4j_resources_lib",
-    java_resources: [":android_icu4j_resources"],
-    no_standard_libs: true,
-    system_modules: "none",
-}
-
 // A target used to bootstrap compilation for the core library.
+//
 // See core-all-system-modules for more details.
 java_library {
     name: "core-all",
     defaults: ["libcore_java_defaults"],
 
     srcs: [
+        // Use the source code for the I18N module intra core API as using the
+        // compiled version does not work due to limitations in either soong or the javac
+        // toolchain. See http://b/142056316 for more details.
+        ":i18n-module-intra-core-api-stubs-source",
         ":core_oj_java_files",
         ":core_libart_java_files",
         ":openjdk_lambda_stub_files",
+        ":openjdk_generated_annotation_stub_files",
+        ":app-compat-annotations-source",
     ],
 
-    no_standard_libs: true,
+    sdk_version: "none",
     system_modules: "none",
+    patch_module: "java.base",
     openjdk9: {
         srcs: ["luni/src/module/java/module-info.java"],
-        javacflags: ["--patch-module=java.base=."],
     },
 
-    java_resource_dirs: core_resource_dirs,
-    static_libs: ["android_icu4j_resources_lib"],
+    java_resources: core_resources,
     java_version: "1.9",
 
     installable: false,
+
+    plugins: [
+        "compat-changeid-annotation-processor",
+        "unsupportedappusage-annotation-processor",
+    ],
+}
+
+platform_compat_config {
+    name: "libcore-platform-compat-config",
+    src: ":core-all",
 }
 
 // A system modules definition for use by core library targets only. It only
@@ -178,30 +201,43 @@
 // etc. This system_modules definition is used to bootstrap compilation for
 // other parts of the core library like core-oj, core-libart, conscrypt,
 // bouncycastle, etc.
-//
-// If you want to compile against the entire core library implementation, for
-// example to build core library tests, see "core-system-modules" instead.
 java_system_modules {
     name: "core-all-system-modules",
+
+    // Visibility is deliberately restricted to a small set of build modules that
+    // the core library team control.
+    visibility: [
+        "//external/apache-harmony:__subpackages__",
+        "//external/apache-xml",
+        "//external/okhttp",
+        "//libcore:__subpackages__",
+    ],
+
     libs: ["core-all"],
 }
 
 // Contains the parts of core library associated with OpenJDK.
 java_library {
     name: "core-oj",
+    visibility: [
+        "//art/build/apex",
+        "//external/wycheproof",
+        "//libcore/benchmarks",
+    ],
+    apex_available: [
+        "com.android.art.release",
+        "com.android.art.debug",
+    ],
     defaults: ["libcore_java_defaults"],
     installable: true,
     hostdex: true,
 
     srcs: [":core_oj_java_files"],
-    java_resource_dirs: core_resource_dirs,
+    java_resources: core_resources,
 
-    no_standard_libs: true,
-    libs: ["core-all"],
+    sdk_version: "none",
     system_modules: "core-all-system-modules",
-    openjdk9: {
-        javacflags: ["--patch-module=java.base=."],
-    },
+    patch_module: "java.base",
 
     jacoco: {
         exclude_filter: [
@@ -225,24 +261,31 @@
 }
 
 // Contains parts of core library not associated with OpenJDK. Contains not
-// just java.*, javax.* code but also android.icu.*, android.system.* and
-// various internal libcore.* packages.
+// just java.*, javax.* code but also android.system.* and various internal
+// libcore.* packages.
 java_library {
     name: "core-libart",
+    visibility: [
+        "//art/build/apex",
+        "//external/robolectric-shadows",
+        "//external/wycheproof",
+        "//libcore/benchmarks",
+        "//frameworks/layoutlib",
+    ],
+    apex_available: [
+        "com.android.art.release",
+        "com.android.art.debug",
+    ],
     defaults: ["libcore_java_defaults"],
     installable: true,
     hostdex: true,
 
     srcs: [":core_libart_java_files"],
-    static_libs: ["android_icu4j_resources_lib"],
     java_version: "1.9",
 
-    no_standard_libs: true,
-    libs: ["core-all"],
+    sdk_version: "none",
     system_modules: "core-all-system-modules",
-    openjdk9: {
-        javacflags: ["--patch-module=java.base=."],
-    },
+    patch_module: "java.base",
 
     jacoco: {
         exclude_filter: [
@@ -251,35 +294,55 @@
         ],
     },
 
-    required: [
-        // Device files put in /system.
-        "tzdata",
-        "tz_version",
-        // Files used to simulate the /system and runtime APEX dir
-        // structure on host.
-        "tzdata_host",
-        "tzdata_host_runtime_apex",
-        "tzlookup.xml_host_runtime_apex",
-        "tz_version_host",
-        "tz_version_host_runtime_apex",
-    ],
+    target: {
+        hostdex: {
+            required: [
+                // Files used to simulate the /system, runtime APEX and tzdata
+                // APEX dir structure on host.
+                "icu_tzdata.dat_host_tzdata_apex",
+                "tzdata_host",
+                "tzdata_host_tzdata_apex",
+                "tzlookup.xml_host_tzdata_apex",
+                "tz_version_host",
+                "tz_version_host_tzdata_apex",
+            ],
+        },
+    },
 }
 
 // Provided solely to contribute information about which hidden parts of the
 // core-oj API are used by apps.
+//
+// The build system determines that this library provides hiddenapi information
+// for the core-oj bootjar because its name is of the form <x>-hiddenapi, where
+// <x> is the name of a boot jar. That triggers the generation of a flags.csv
+// file which encapsulates information extracted from the UnsupportedAppUsage
+// annotations in the dex. The information from that file is then encoded into
+// the core-oj file.
+//
+// Usually, e.g. for core-libart, the UnsupportedAppUsage annotations are
+// added to the source that is compiled directly into the bootjar and the build
+// system extracts the information about UnsupportedAppUsage directly from
+// there.
+//
+// This approach of having separate annotated source and a separate build
+// target was taken for ojluni to avoid having to maintain local patches in the
+// ojluni source for UnsupportedAppUsage annotations as that would make it more
+// difficult to pull down changes from upstream.
+//
 java_library {
     name: "core-oj-hiddenapi",
+    // Do not allow this to be accessed from outside this directory.
+    visibility: ["//visibility:private"],
     defaults: ["libcore_java_defaults"],
     compile_dex: true,
 
     srcs: [":openjdk_hiddenapi_javadoc_files"],
 
-    no_standard_libs: true,
-    libs: ["core-all"],
+    sdk_version: "none",
     system_modules: "core-all-system-modules",
-    openjdk9: {
-        javacflags: ["--patch-module=java.base=."],
-    },
+    patch_module: "java.base",
+    plugins: ["unsupportedappusage-annotation-processor"],
 }
 
 //
@@ -293,8 +356,7 @@
     name: "core-oj-testdex",
     installable: true,
     static_libs: ["core-oj"],
-    no_standard_libs: true,
-    libs: ["core-all"],
+    sdk_version: "none",
     system_modules: "core-all-system-modules",
     dxflags: ["--core-library"],
     dex_preopt: {
@@ -308,8 +370,7 @@
     name: "core-libart-testdex",
     installable: true,
     static_libs: ["core-libart"],
-    no_standard_libs: true,
-    libs: ["core-all"],
+    sdk_version: "none",
     system_modules: "core-all-system-modules",
     dxflags: ["--core-library"],
     dex_preopt: {
@@ -318,18 +379,14 @@
     notice: "ojluni/NOTICE",
 }
 
-
 java_defaults {
     name: "core_lambda_stubs_defaults",
     defaults: ["libcore_java_defaults"],
     hostdex: true,
 
-    no_standard_libs: true,
-    libs: ["core-all"],
+    sdk_version: "none",
     system_modules: "core-all-system-modules",
-    openjdk9: {
-        javacflags: ["--patch-module=java.base=."],
-    },
+    patch_module: "java.base",
 
     notice: "ojluni/NOTICE",
 
@@ -343,11 +400,15 @@
 // are also in the public SDK API from API level 26 onwards.
 java_library {
     name: "core-lambda-stubs",
+    visibility: ["//visibility:public"],
     defaults: ["core_lambda_stubs_defaults"],
     srcs: [
         ":openjdk_lambda_stub_files",
         ":openjdk_lambda_duplicate_stub_files",
     ],
+    // This jar is packaged as part of the SDK, use -target 8 so that it works
+    // with old JDKs.
+    java_version: "1.8",
 }
 
 // An alternative to core-lambda-stubs that omits openjdk_lambda_duplicate_stub_files
@@ -355,41 +416,50 @@
 // (since API level 26).
 java_library {
     name: "core-lambda-stubs-for-system-modules",
+    visibility: [
+        "//libcore/mmodules/core_platform_api",
+    ],
     defaults: ["core_lambda_stubs_defaults"],
     srcs: [
         ":openjdk_lambda_stub_files",
     ],
+    include_srcs: true,
 }
 
-// A system modules definition containing the implementations for the various
-// parts that make up the core library.
-//
-// This system module is intended for use by tests that may need access to
-// core library internals. It should not be generally used; most of the
-// platform build should build against API stubs instead. See
-// "core-platform-api-stubs-system-modules", which is the default used by the
-// Android build.
-//
-// This module also includes lambda stubs for compiling source containing
-// Java lambdas.
-java_system_modules {
-    name: "core-system-modules",
-    libs: [
-        "core-oj",
-        "core-libart",
-        "bouncycastle",
-        "conscrypt",
-        "okhttp",
-        "apache-xml",
-        // This one is not on device but it's needed when javac compiles code
-        // containing lambdas.
-        "core-lambda-stubs-for-system-modules",
+// Creates a jar that exists to satisfy javac when compiling source code that
+// contains @Generated annotations, which are produced by some code generation
+// tools (notably dagger) but aren't part of the Android API.
+// See http://b/123891440.
+java_library {
+    name: "core-generated-annotation-stubs",
+    visibility: [
+        "//libcore/mmodules/core_platform_api",
     ],
+    defaults: ["libcore_java_defaults"],
+    srcs: [
+        ":openjdk_generated_annotation_stub_files",
+    ],
+    hostdex: true,
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
+    patch_module: "java.base",
+    notice: "ojluni/NOTICE",
+    installable: false,
+    include_srcs: true,
 }
 
 // Builds libcore test rules
 java_library_static {
     name: "core-test-rules",
+    visibility: [
+        "//art/build/sdk",
+        "//external/conscrypt",
+        "//external/conscrypt/apex/tests",
+        "//frameworks/base/location/tests/locationtests",
+        "//frameworks/base/core/tests/coretests",
+        "//frameworks/base/wifi/tests",
+        "//cts/tests/tests/util",
+    ],
     hostdex: true,
     srcs: [
         "dalvik/test-rules/src/main/**/*.java",
@@ -397,18 +467,53 @@
     ],
     static_libs: ["junit"],
 
-    no_standard_libs: true,
-    libs: ["core-all"],
+    sdk_version: "none",
     system_modules: "core-all-system-modules",
 }
 
+// Builds platform_compat test rules
+java_library_static {
+    name: "core-compat-test-rules",
+    visibility: [
+        "//art/build/sdk",
+        "//frameworks/base/tests/PlatformCompatGating/test-rules",
+    ],
+    srcs: [
+        "luni/src/main/java/android/compat/**/*.java",
+        "test-rules/src/platform_compat/**/*.java",
+        "luni/src/main/java/libcore/api/CorePlatformApi.java",
+        "luni/src/main/java/libcore/api/IntraCoreApi.java",
+    ],
+    static_libs: [
+        "junit",
+        "guava",
+    ],
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
+    // This builds classes that are in the java.base Java module:
+    patch_module: "java.base",
+    hostdex: true,
+}
+
 // Builds the core-tests-support library used by various tests.
 java_library_static {
     name: "core-tests-support",
+    visibility: [
+        "//art/build/sdk",
+        "//cts/apps/CtsVerifier",
+        "//cts/tests/tests/keystore",
+        "//cts/tests/tests/net",
+        "//cts/tests/tests/net/api23Test",
+        "//external/apache-harmony",
+        "//frameworks/base/core/tests/coretests",
+        "//libcore/benchmarks",
+        "//packages/apps/KeyChain/tests",
+        "//system/timezone/distro/core",
+    ],
     hostdex: true,
     srcs: ["support/src/test/java/**/*.java"],
 
-    no_framework_libs: true,
+    sdk_version: "core_platform",
     libs: ["junit"],
     static_libs: [
         "bouncycastle-unbundled",
@@ -420,44 +525,39 @@
 // Builds the jsr166-tests library.
 java_test {
     name: "jsr166-tests",
+    visibility: [
+        "//cts/tests/libcore/jsr166",
+    ],
     srcs: ["jsr166-tests/src/test/java/**/*.java"],
-    no_standard_libs: true,
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
     libs: [
-        "core-all",
         "junit",
     ],
-    system_modules: "core-all-system-modules",
 }
 
-// Builds a library just containing files from luni/src/test/filesystems
-// for use in tests.
-java_library {
-    name: "filesystemstest",
-    compile_dex: true,
-    srcs: ["luni/src/test/filesystems/src/**/*.java"],
-    java_resource_dirs: ["luni/src/test/filesystems/resources"],
-    no_framework_libs: true,
-    errorprone: {
-        javacflags: ["-Xep:MissingOverride:OFF"],
-    },
+// A filegroup that provides access to a source file for a toolchain test that
+// checks Java 9 language features are handled properly by JarJar.
+filegroup {
+    name: "core-java-9-language-features-source",
+    srcs: ["luni/src/main/java/libcore/internal/Java9LanguageFeatures.java"],
+    visibility: ["//libcore/luni/src/test/java9language"],
 }
 
-// Builds a library just containing files from luni/src/test/parameter_metadata
-// for use in tests.
-java_library {
-    name: "parameter-metadata-test",
-    compile_dex: true,
-    srcs: ["luni/src/test/parameter_metadata/src/**/*.java"],
-    no_framework_libs: true,
-    javacflags: ["-parameters"],
-    errorprone: {
-        javacflags: ["-Xep:MissingOverride:OFF"],
-    },
+genrule {
+    name: "core-tests-smali-dex",
+    srcs: ["luni/src/test/java/**/*.smali"],
+    cmd: "$(location smali) ass --api 28 -o $(out) $(in)",
+    out: ["core-tests-smali.dex"],
+    tools: ["smali"],
 }
 
 // Builds the core-tests library.
 java_test {
     name: "core-tests",
+    visibility: [
+        "//cts/tests/libcore/luni",
+    ],
     defaults: ["libcore_java_defaults"],
     hostdex: true,
     srcs: [
@@ -471,8 +571,12 @@
         "xml/src/test/java/**/*.java",
     ],
     exclude_srcs: [
+        "harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/*.java",
         "luni/src/test/java/libcore/java/util/zip/Zip64Test.java",
         "luni/src/test/java/libcore/java/util/zip/Zip64FileTest.java",
+        "luni/src/test/java/libcore/javax/crypto/**/*.java",
+        "luni/src/test/java/libcore/javax/net/ssl/**/*.java",
+        "luni/src/test/java/org/apache/harmony/crypto/**/*.java",
     ],
 
     java_resource_dirs: [
@@ -485,23 +589,26 @@
     ],
 
     java_resources: [
+        ":annotations-test",
         ":filesystemstest",
         ":parameter-metadata-test",
+        ":core-tests-smali-dex",
     ],
 
-    no_standard_libs: true,
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
     libs: [
-        "core-all",
         "okhttp",
         "bouncycastle",
     ],
-    system_modules: "core-all-system-modules",
 
     static_libs: [
-        "archive-patcher",
+        "core-compat-test-rules",
+        "core-java-9-language-tests",
         "core-test-rules",
         "core-tests-support",
         "junit-params",
+        "libcore-crypto-tests",
         "mockftpserver",
         "mockito-target",
         "mockwebserver",
@@ -509,7 +616,7 @@
         "slf4j-jdk14",
         "sqlite-jdbc",
         "tzdata-testing",
-        "truth-prebuilt",
+        "truth-prebuilt-jar",
     ],
 
     errorprone: {
@@ -522,6 +629,40 @@
     test_config: "AndroidTest-core-tests.xml",
 }
 
+java_test {
+    name: "libcore-crypto-tests",
+
+    visibility: [
+        "//art/build/sdk",
+        "//external/conscrypt/apex/tests",
+    ],
+    srcs: [
+        "harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/*.java",
+        "luni/src/test/java/libcore/javax/crypto/**/*.java",
+        "luni/src/test/java/libcore/javax/net/ssl/**/*.java",
+        "luni/src/test/java/org/apache/harmony/crypto/**/*.java",
+    ],
+    exclude_srcs: [
+        "luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java",
+    ],
+
+    java_resource_dirs: [
+        "luni/src/test/java",
+        "luni/src/test/resources",
+        "support/src/test/java",
+    ],
+
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
+
+    static_libs: [
+        "core-test-rules",
+        "core-tests-support",
+        "junit-params",
+        "mockito-target",
+    ],
+}
+
 // Builds the core-ojtests library that contains test code from OpenJDK.
 java_test {
     name: "core-ojtests",
@@ -536,13 +677,12 @@
         "ojluni/src/test/resources",
     ],
 
-    no_standard_libs: true,
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
     libs: [
-        "core-all",
         "okhttp",
         "bouncycastle",
     ],
-    system_modules: "core-all-system-modules",
 
     static_libs: ["testng"],
 
@@ -552,7 +692,7 @@
     // code if it's declared to also be in java.base at
     // compile time.
     //
-    // For now, we use --patch-module to put all sources
+    // For now, we use patch_module to put all sources
     // and dependencies from this make target into java.base;
     // other source directories in this make target are in
     // packages not from java.base; if this becomes a problem
@@ -567,6 +707,9 @@
 // Like core-ojtests but smaller.
 java_test {
     name: "core-ojtests-public",
+    visibility: [
+        "//cts/tests/libcore/ojluni",
+    ],
     defaults: ["libcore_java_defaults"],
     srcs: [
         "ojluni/src/test/java/**/*.java",
@@ -588,14 +731,13 @@
         "ojluni/src/test/dist",
     ],
 
-    no_standard_libs: true,
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
     libs: [
-        "core-all",
         "bouncycastle",
         "okhttp",
         "testng",
     ],
-    system_modules: "core-all-system-modules",
 }
 
 // Exports annotated stubs source files in ojluni/annotations/sdk to make them
@@ -604,16 +746,21 @@
     name: "ojluni-annotated-sdk-stubs",
     path: "ojluni/annotations/sdk",
 }
+
 droiddoc_exported_dir {
     name: "ojluni-annotated-nullability-stubs",
     path: "ojluni/annotations/sdk/nullability",
 }
 
 // Exports annotated stubs source files in ojluni/annotations/mmodules to make
-// them available to metalava. Used for core platform API and intra-code API
+// them available to metalava. Used for core platform API and intra-core API
 // annotations in OpenJDK source.
 droiddoc_exported_dir {
     name: "ojluni-annotated-mmodule-stubs",
+    visibility: [
+        "//libcore/mmodules/core_platform_api",
+        "//libcore/mmodules/intracoreapi",
+    ],
     path: "ojluni/annotations/mmodule",
 }
 
@@ -621,24 +768,163 @@
 // source code and so should not cause an error or warning.
 filegroup {
     name: "known-oj-tags",
+    visibility: [
+        "//frameworks/base",
+    ],
     srcs: [
         "known_oj_tags.txt",
     ],
 }
 
-// Generates stubs for the parts of the public SDK API provided by the core
-// library.
+// A special set of stubs containing the minimal set of self consistent
+// classes for which a system module can be created. Every system module must
+// contain the java.lang classes so the set was constructed by starting with
+// the java.lang classes and then adding their transitive dependencies without
+// splitting packages. So, if one class from a package is used then all classes
+// in that package were added to the set.
 //
-// Only for use by core.current.stubs target below.
+// Needed for java-current-stubs-system-modules.
 droidstubs {
-    name: "core-current-stubs-gen",
-    srcs: [":core_api_files"],
+    name: "java-current-stubs-source",
+    srcs: [
+        ":core_oj_api_files",
+        ":core_libart_api_files",
+    ],
     java_version: "1.9",
     installable: false,
-    no_framework_libs: true,
-    args: " --exclude-annotations "
-        + "--hide-annotation libcore.api.Hide",
-    merge_inclusion_annotations_dirs: ["ojluni-annotated-mmodule-stubs"],
+    sdk_version: "none",
+    system_modules: "none",
+
+    args: "--stub-packages java.*:javax.*:org.w3c.dom.*:org.xml.sax.*",
+}
+
+java_library {
+    name: "java.current.stubs",
+    srcs: [":java-current-stubs-source"],
+    errorprone: {
+        javacflags: [
+            "-Xep:MissingOverride:OFF",
+        ],
+    },
+    patch_module: "java.base",
+    sdk_version: "none",
+    system_modules: "none",
+}
+
+// A special set of system modules needed to build art.module.public.api.stubs
+// that contain nullability annotations when targeting java language level 1.9
+// and above.
+java_system_modules {
+    name: "java-current-stubs-system-modules",
+    libs: [
+        // Minimal set of classes required for a system module.
+        "java.current.stubs",
+
+        // The nullability annotations used by the generated stubs.
+        "stub-annotations",
+    ],
+}
+
+// http://b/129765390 Rewrite links to "platform" or "technotes" folders
+// which are siblings (and thus outside of) {@docRoot}.
+//
+// We have to escape \ as \\ and $ as $$ here because they get resolved by
+// different layers of the build tooling. The arguments are wrapped in '' so
+// that the shell doesn't add yet another level of escaping.
+rewrite_openjdk_doc_args = "--replace-documentation " +
+    // packages whose descendants to apply replacement to (all packages from
+    // libcore/ojluni/src/main/java that contribute to documentation).
+    "com.sun:java:javax:jdk.net:sun " +
+    // regex of the string to replace
+    "'(<a\\s+href\\s?=[\\*\\s]*\")(?:(?:\\{@docRoot\\}/\\.\\./)|(?:(?:\\.\\./)+))((?:platform|technotes).+)\">' " +
+    // replacement (with $1, $2 backreferences to the regex groups)
+    "'$$1https://docs.oracle.com/javase/8/docs/$$2\">' "
+
+// Generates stubs for the parts of the public SDK API provided by the ART module.
+//
+// Only for use by art.module.public.api.stubs target below and the building of the
+// public API.
+droidstubs {
+    name: "art-module-public-api-stubs-source",
+    visibility: [
+        "//frameworks/base",
+    ],
+    srcs: [
+        ":core_oj_api_files",
+        ":core_libart_api_files",
+    ],
+    java_version: "1.9",
+    installable: false,
+    sdk_version: "none",
+    system_modules: "java-current-stubs-system-modules",
+    libs: [
+        // Provide access to I18N constants that are used to initialize
+        // constants in the public API. i.e. to allow the value of the
+        // java.text.CollectionElementIterator.NULLORDER to be initialized from
+        // android.icu.text.CollationElementIterator.NULLORDER.
+        "i18n.module.intra.core.api.stubs",
+    ],
+
+    args: rewrite_openjdk_doc_args,
+
+    create_doc_stubs: true,
+
+    // Emit nullability annotations from the source to the stub files.
+    annotations_enabled: true,
+
+    merge_annotations_dirs: [
+        "ojluni-annotated-sdk-stubs",
+    ],
+}
+
+// A stubs target containing the parts of the public SDK API provided by the ART module.
+java_library {
+    name: "art.module.public.api.stubs",
+    srcs: [":art-module-public-api-stubs-source"],
+    errorprone: {
+        javacflags: [
+            "-Xep:MissingOverride:OFF",
+        ],
+    },
+    patch_module: "java.base",
+    sdk_version: "none",
+    system_modules: "java-current-stubs-system-modules",
+}
+
+// Used when compiling higher-level code against art.module.public.api.stubs.
+//
+// This is only intended for use within core libraries and must not be used
+// from outside.
+java_system_modules {
+    name: "art-module-public-api-stubs-system-modules",
+    visibility: [
+        "//art/build/sdk",
+        "//external/conscrypt",
+        "//external/icu/android_icu4j",
+        "//external/wycheproof",
+    ],
+    libs: [
+        "art.module.public.api.stubs",
+        // This one is not on device but it's needed when javac compiles code
+        // containing lambdas.
+        "core-lambda-stubs-for-system-modules",
+        // This one is not on device but it's needed when javac compiles code
+        // containing @Generated annotations produced by some code generation
+        // tools.
+        // See http://b/123891440.
+        "core-generated-annotation-stubs",
+
+        // Ensure that core libraries that depend on the public API can access
+        // the UnsupportedAppUsage, CorePlatformApi and IntraCoreApi
+        // annotations.
+        "art.module.api.annotations.for.system.modules",
+
+        // Make nullability annotations available when compiling public stubs.
+        // They are provided as a separate library because while the
+        // annotations are not themselves part of the public API provided by
+        // this module they are used in the stubs.
+        "stub-annotations",
+    ],
 }
 
 // A stubs target containing the parts of the public SDK API provided by the
@@ -647,16 +933,13 @@
 // Don't use this directly, use "sdk_version: core_current".
 java_library {
     name: "core.current.stubs",
-    srcs: [":core-current-stubs-gen"],
-    errorprone: {
-        javacflags: [
-            "-Xep:MissingOverride:OFF",
-        ],
-    },
-    openjdk9: {
-        javacflags: ["--patch-module=java.base=."],
-    },
-    no_standard_libs: true,
+    visibility: ["//visibility:public"],
+    static_libs: [
+        "art.module.public.api.stubs",
+        "conscrypt.module.public.api.stubs",
+        "i18n.module.public.api.stubs",
+    ],
+    sdk_version: "none",
     system_modules: "none",
 
     dist: {
@@ -667,24 +950,60 @@
     },
 }
 
+// Distributed with the SDK for turning into system modules to compile apps
+// against.
+java_library {
+    name: "core-current-stubs-for-system-modules",
+    visibility: ["//development/sdk"],
+    static_libs: [
+        "core.current.stubs",
+        // This one is not on device but it's needed when javac compiles code
+        // containing lambdas.
+        "core-lambda-stubs-for-system-modules",
+        // This one is not on device but it's needed when javac compiles code
+        // containing @Generated annotations produced by some code generation
+        // tools.
+        // See http://b/123891440.
+        "core-generated-annotation-stubs",
+    ],
+    sdk_version: "none",
+    system_modules: "none",
+    dist: {
+        dest: "core-for-system-modules.jar",
+        targets: [
+            "sdk",
+            "win_sdk",
+        ],
+    },
+}
+
+// Used when compiling higher-level code against core.current.stubs.
+java_system_modules {
+    name: "core-current-stubs-system-modules",
+    visibility: ["//visibility:public"],
+    libs: [
+        "core-current-stubs-for-system-modules",
+    ],
+}
+
 // Target for validating nullability annotations for correctness and
 // completeness. To check that there are no nullability errors:
-//   make core-current-stubs-nullability-validation
+//   m art-module-public-api-stubs-nullability-validation
 // To check that there are only the expected nullability warnings:
-//   make core-current-stubs-nullability-validation-check-nullability-warnings
-// To update the the list of known expected nullability warnings:
-//   make core-current-stubs-nullability-validation-update-nullability-warnings
+//   m art-module-public-api-stubs-nullability-validation-check-nullability-warnings
+// (If that check fails, it will provide instructions on how to proceed,
+// including the command to run to update the expected warnings file.)
 droidstubs {
-    name: "core-current-stubs-nullability-validation",
-    srcs: [":core_api_files"],
+    name: "art-module-public-api-stubs-nullability-validation",
+    srcs: [":art_module_api_files"],
     installable: false,
-    no_framework_libs: true,
+    sdk_version: "none",
+    system_modules: "none",
     annotations_enabled: true,
     args: "--hide-annotation libcore.api.Hide " +
         "--validate-nullability-from-merged-stubs ",
     merge_inclusion_annotations_dirs: ["ojluni-annotated-mmodule-stubs"],
     merge_annotations_dirs: [
-        "metalava-manual",
         // N.B. Stubs in this filegroup will be validated:
         "ojluni-annotated-nullability-stubs",
     ],
@@ -700,5 +1019,50 @@
 // time zone data.
 java_library_host {
     name: "timezone-host",
+    visibility: [
+        "//art/build/sdk",
+        "//system/timezone/distro/core",
+    ],
     srcs: [":timezone_host_files"],
 }
+
+// A special set of system modules for building the following library for use
+// in the art-module-public-api-system-modules.
+java_system_modules {
+    name: "api-annotations-system-modules",
+    libs: [
+        "art.module.public.api.stubs",
+    ],
+}
+
+// A library that contains annotations that define API surfaces (core
+// platform, intra core and the hidden API) along with some supporting
+// constants. The annotations are source only and do not introduce any runtime
+// dependencies. Specially built for use in system modules definitions to
+// avoid introducing compile time cycles.
+java_library {
+    name: "art.module.api.annotations.for.system.modules",
+    srcs: [
+        ":api_surface_annotation_files",
+    ],
+
+    installable: false,
+    sdk_version: "none",
+    system_modules: "api-annotations-system-modules",
+    patch_module: "java.base",
+}
+
+// Create a library containing the api surface annotations, built against
+// core_current for use by the annotation processor in frameworks/base.
+java_library {
+    name: "art.module.api.annotations",
+    visibility: [
+        "//frameworks/base",
+    ],
+    host_supported: true,
+    srcs: [
+        ":api_surface_annotation_files",
+    ],
+    java_version: "1.9",
+    sdk_version: "core_current",
+}
diff --git a/NativeCode.bp b/NativeCode.bp
index 38f57b3..9619420 100644
--- a/NativeCode.bp
+++ b/NativeCode.bp
@@ -47,6 +47,13 @@
 
 cc_library_shared {
     name: "libjavacore",
+    visibility: [
+        "//art/build/apex",
+    ],
+    apex_available: [
+        "com.android.art.release",
+        "com.android.art.debug",
+    ],
     defaults: [
         "core_native_default_flags",
         "core_native_default_libs",
@@ -66,6 +73,7 @@
         "libz",
     ],
     static_libs: [
+        "libandroidicuinit",
         "libziparchive",
     ],
     target: {
@@ -82,6 +90,18 @@
 
 cc_library_shared {
     name: "libandroidio",
+    visibility: [
+        "//art/build/apex",
+        "//external/conscrypt",
+    ],
+    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",
     ],
@@ -104,8 +124,8 @@
         "core_native_default_libs",
     ],
     srcs: [":libopenjdk_native_srcs"],
-    include_dirs: [
-        "libcore/luni/src/main/native",
+    local_include_dirs: [
+        "luni/src/main/native",
     ],
     cflags: [
         // TODO(narayan): Prune down this list of exclusions once the underlying
@@ -154,6 +174,13 @@
 
 cc_library_shared {
     name: "libopenjdk",
+    visibility: [
+        "//art/build/apex",
+    ],
+    apex_available: [
+        "com.android.art.release",
+        "com.android.art.debug",
+    ],
     defaults: ["libopenjdk_native_defaults"],
     shared_libs: [
         "libopenjdkjvm",
@@ -163,6 +190,12 @@
 // Debug version of libopenjdk. Depends on libopenjdkjvmd.
 cc_library_shared {
     name: "libopenjdkd",
+    visibility: [
+        "//art/build/apex",
+    ],
+    apex_available: [
+        "com.android.art.debug",
+    ],
     defaults: ["libopenjdk_native_defaults"],
     shared_libs: [
         "libopenjdkjvmd",
@@ -172,6 +205,10 @@
 // Test JNI library.
 cc_library_shared {
     name: "libjavacoretests",
+    visibility: [
+        "//art/build/sdk",
+        "//cts/tests/libcore/luni",
+    ],
     defaults: ["core_native_default_flags"],
     host_supported: true,
 
@@ -219,8 +256,3 @@
 
     shared_libs: ["libnativehelper"],
 }
-
-subdirs = [
-    "luni/src/main/native",
-    "ojluni/src/main/native",
-]
diff --git a/OWNERS b/OWNERS
index c35f898..174fb87 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,9 +1,11 @@
+# Bug component: 24949
+
 # Use this reviewer by default.
 android-libcore-team+review@google.com
 
 # People who can approve changes for submission; don't send review emails to them
 # unless you know what you're doing.
-flooey@google.com
+dauletz@google.com
 narayan@google.com
 nfuller@google.com
 nikitai@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 3a75225..d5d57d7 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -8,3 +8,6 @@
 # Ensure there are no Apache-licensed files under:
 # * ojluni/src/main/java
 checkstyle-ojluni        = java -jar ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.jar -c tools/checkstyle/checkstyle-forbid-apache.xml ojluni/src/main/java
+
+[Builtin Hooks]
+bpfmt = true
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..51a7335
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,45 @@
+//
+// 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.
+
+// i18n APEX is intended as a home for ICU as of July 2019.
+// Various parts and dependencies of ICU would be gradually moved into this APEX,
+// and the below build rules should reflect the latest status.
+// TODO(b/138434658): Move the apex declaration back to external/icu
+// The apex is declared in libcore/ to workaround new dependency from external/icu
+// to system/sepolicy in a downstream branch.
+apex {
+    name: "com.android.i18n",
+    defaults: ["com.android.i18n-defaults"],
+    certificate: ":com.android.i18n.certificate",
+}
+
+apex_defaults {
+    name: "com.android.i18n-defaults",
+    compile_multilib: "both",
+    manifest: "manifest.json",
+    prebuilts: ["apex_icu.dat"],
+    key: "com.android.i18n.key",
+}
+
+apex_key {
+    name: "com.android.i18n.key",
+    public_key: "com.android.i18n.avbpubkey",
+    private_key: "com.android.i18n.pem",
+}
+
+android_app_certificate {
+    name: "com.android.i18n.certificate",
+    certificate: "com.android.i18n",
+}
diff --git a/apex/com.android.i18n.avbpubkey b/apex/com.android.i18n.avbpubkey
new file mode 100644
index 0000000..f1c97a0
--- /dev/null
+++ b/apex/com.android.i18n.avbpubkey
Binary files differ
diff --git a/apex/com.android.i18n.pem b/apex/com.android.i18n.pem
new file mode 100644
index 0000000..7676453
--- /dev/null
+++ b/apex/com.android.i18n.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKwIBAAKCAgEA89VXuQrlqB0L731Es2ud65k5XkyGn0FjQfynPYRPz3nkpNaF
+3LbJ6JXIGKUQMY2pVQFNl2wUtylTJohNv8SWu/hPBMOmHu2zGvvfErKN7QD25y12
+D9jws3VlPhCWQsEZSjloYKI1MvMPcvtLgHoSuMl6JlT8mngC+uR8WLGtDKZYGICf
+I2rhQ5ugzDp00tGJJV9HKAXHx7zA9X+29HbMte57ibOrO4Xs7zLankV3rVEc0ZcD
+phA1RYh6lg9KYfsq/zbEbCRGPLTlqKa3zDPrnXTKInR//5fW7tWgqqRyXGumM8pA
+B1Huba878WnMwcWWYLjxRMQ6hOOCnGY7167JoAnX+NRmUZWXrrSiaCr6o61ingb6
+6BvQTN0f1q2lXIf1bOPRkeNkxBB7q3YFa4XaF9ZpQs7V4vlrvE/uLWDmhTQ6snML
+zWYbD+/nQ6u5BIdh+1rNk5RWp53IoNTGyJQnTpSkA2u+rtDuyKG4av6Vx2cPJ5Mu
+8vAALAyEOqlZr0CeJR0h3m6XVt0PpDxNUvQU53tlzIKD2BuELWeRSJ79DkYf+Soh
+vc0upDbdsy1r4C/Df5UpKnOKCmrYmJ1tdiigVeDH3y0B0ilD2dUqubqlc5Tw0a13
+PkpWPdJV7QpTyb3GDWa4DRpYRxCGDylCsS2rsXbsiMGqJFL3G0w06ahTmFUCAwEA
+AQKCAgEA4nVbQsXHI8rOYgADBWxGwCCPsm/6fABbslZ38N9ozHYWD64ZpzKw9W3e
+6FytXIiIIyXRrXe5CZ+81UW0iA2KPUvR/8fCCmmTddVFifUBcYP6zBxh0TgX3WSD
+wg/frmHvHguRUGZ2aDpsN8sChXFa3/pnkyBNdx1NDz2T60AhS2VW3nLe2iMS0hrB
+Tcxg4cevy2DhEl/D+1LoF1olTojjeXjjjbGrr92jf0jI2EQGcZaq4FGUFvBouYqW
+57WNzNBcT6nK5fEOtqT/wxIMFACIrLViYnu2wWiBO1J3JOUUPZfRRbpqmyHSAlbE
+omMzwyfCkVRS6B4jh3ZRwPYGUDvKjyNLeXXEr7Q6sAiwhvgz8Z5DIyzZr9SkExuQ
+5jfjfYCNsFaA/QmA34hV5KsPLfLFbW3hvDc6ApOn3yvOkIP3Cb2JM/mfyHh7cRpz
+y/UTep2e3uNj7fDkdrqp2oj/EOSKa0KSJCpqkgUwEFFCEvxeYeUgwlM+axSZNXEx
+ocRgQpui/2tVH8rgny3ayYDknleVaWtzxg7QLH7vV90ztjh4XjmZgl4R6N6vO1IT
+G2XN05vySoE+8ZdQVz3Ko3w3NLon4gwyXv8K+PmHBUsIoY37OPpZoj24n/Uajcuh
+crr5zSGlXhC+OzNk1tJ1NosHF70b/sYwdSIRpxEzA7QggSi6iAUCggEBAP5yHpkr
+BZB/C95zT4xd8ugYAw/5rFQXgwYkf1CYUp/lEXBUJGnimIwo5Gr9tGAAxTwXTTJH
+TI25EhAFu/WEh4h31SkL2b3S6jqupCqYwZdrl5TAY/35FBpGZN+ZirTHPP6ZobxX
+8zhHTl+7mKN/neA6sbLwH4WDZa+LUHScTnVSjzyL2PorPdsolFjOLILQE6LZjinB
+5bX972wjK4Q72gfdkia/Csq8Wo2/k53A2ur0fFojRHHI1M9Fthe6OI4RX/RwyHih
+R9S68xrz2bcYQ8XpoaaNpLY/FXev8WcBicjApN+eQQCK2ZGA9+UxgQRld317Wvqf
+zAyKp5idtRJUbb8CggEBAPVSoNyrghZFfaWGDe3pCnKkeZhqNsLbI5YrQohX6Quy
+BhRCP5t5wyNuMQX5rRZqeb3VgbW/06faVwZZ+bwA0KT7RYy0zgJhfD6bZ7WmzQMc
+HmAVqvN8iZIIjpMeN/174yYdqq0ShUYmra151ReL/CWs32kBWNKT6l487J7DAoYR
+ZHtec9nbs2ZFqea+PNAP8VAcsmsemwXe1w63RxDgdZccJmMj0TWmBj47RstMWTLE
+CrCGfXW9qmvs/Itzbuy589DS0AXZfTW+U0TD4RnCcjV7JDyEZASA3V7lMiyKXDTJ
+6+CUcgzOWzdTfAeVcG0olXXNCdCePX8uiqkwSCaXpusCggEBAI4tHkPf8kAHfY5T
+SIPaizx9DlkC3fQvHxtzkWBrfN+zk8b8fUxdPXgz8U6HbR6nz44ARzZs+K3IV/tz
++M77uu/aZdWFtamIDTG1HC5hJOuDRzPrPPRRFZaI9xyqIwNYwRBSsDkZu+IalgSQ
+Qn45dPIyWdDus+5auZsZcV93Z6/O7hKa4icHuoyXZC0rJ1wBALficLmMitrihcIa
+9Nnyx6XVfTEBVvppvP+vqMBhXvIiosmLI1ehLKiU/2bKu4dG1iM0UhB1rjmELQtG
+bsUMXfJc1eLHCt566XfzbCRui5sNahM5zoCLFX9kXSBIRRs7x0TqhK++Uro/T97L
+YL5ZRukCggEBAOaEpB93EZ/34F7/HmumBWlAX/n2JErpPAFJ2RTg9l1FBS1YKwjf
+W5wZWPtyZ1Ce8JKO43lzLWGWaxvOxDoC0guVCP90jffyvprd0JACkrYPYAONmLt/
+FI4ieEaJqLcKCKGyUsSamJ0Yjy5pQvEDWwXT8YJr/5iv4RR4TyfHusFb6n16fYYD
+SgoZ/9KQg/hGYsySipzZf3X+tTpgweh74kMB8phJ+bZdsZQcgyNZNJ/dUuYZGh7f
+ABq174DiESNkgFSDI3G7skoj8360SPq5mjPi6GPtS0ZoCJu45nKv+ICqFHlNQ/YA
+mfnc+rjtlV0dO4QcDNL5PnQZubXNZp7M9c0CggEBAIrfxdeELSqeVld3nhHFty0b
+ZdmFJWRj6k9zjoOYe8LPkAiue0Zm10sCiLFiRgTH6msnfBloYJ2iiDgSSnIlUvaH
+HFxoLWtv2az2B3g6gfJ5KbdE8mqfz0hGMOUBPFBarC4HrPslR28Cwn8mD5CvN4a/
+oAz3kOlaGokVF6Ikwd606JBFTVKSwr2niTJUwGXgn85tViCWqUm4v24BntbZZ9Rs
+k6ffBUl/k02zw/U405I3qTjCAnetNY3wHmjvdqkCcoWTAmG04IfGlqVE3NMjjLQD
+h9Xx2Nr5SV6djWbmYfT0Ox4Ha/IPuCCAZbBv6Or2wQSOQwb5fUgFcu3NrXU1rQQ=
+-----END RSA PRIVATE KEY-----
diff --git a/apex/com.android.i18n.pk8 b/apex/com.android.i18n.pk8
new file mode 100644
index 0000000..100ed14
--- /dev/null
+++ b/apex/com.android.i18n.pk8
Binary files differ
diff --git a/apex/com.android.i18n.x509.pem b/apex/com.android.i18n.x509.pem
new file mode 100644
index 0000000..fcf1a53
--- /dev/null
+++ b/apex/com.android.i18n.x509.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFUTCCAzmgAwIBAgIUHufr9X4LD87MyuJ/8AaMvsIhXjUwDQYJKoZIhvcNAQEL
+BQAwNzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmcm9uaWExEzARBgNVBAoM
+Ckdvb2dsZSBMTEMwIBcNMTkwNzA1MTU0ODM2WhgPNDc1NzA1MzExNTQ4MzZaMDcx
+CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZnJvbmlhMRMwEQYDVQQKDApHb29n
+bGUgTExDMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsUMFBc1QNyhj
+gU47F2O3kUrZhATA6Gz644sXvrqUg03retG3jsIEFmBXgbXngvF2yq9sRiGm4D5j
+9Sf5fguDqy9C/Q8MiUEAqQo1ygy9MubMfdGVLb2dcFoKXwyig8KzSS03+73IiUnF
+iCy5GzPO6ltga4nsbXUE6egexE3WGLQ0Lu7gCLNZn1Zd20p4BlTUl64CEu9zt6NN
+D6okd7IGceipBbpK9WDMW6ygXJ5sTJohZYSrSOPkoQFVilWFd5VryBxboTmxhSyo
+4dvNavnNCKOhsCCi8QIHOlXMDWxN970giv60FzoXoD2QwD5o+3I6SIIutEnGmh/d
+SECcK9yK+YECqw2XhvoBR4NH4RltaWKZsy62YPSYZXJXZ4H1P+9L9Q5dwLlI2Itt
+IWtYY88T8P2w8e2KzYewkE/XM4kRUw8pNWod1Hok2WuvZxdbPJ0+Hhvo1FVTwV1K
+kdtUuVPut6fpA2hEfGmwdKpK18Qe5ZLBZ1r1lSrjlfct+BWelADaZRNNyJey0u/s
+DgZGbiJG6tJqDESN229/eMTRt9gDncIx7S37RFgOv8jlUul5miKH3QP6neotofWw
+EWEKFjaDNhqU83rdpk48Br/HTiXA6pvaGlN0RQyBVB7uavvTYKTp8cGU11hkIx8p
+Vkp0EOCs9ajlt1+GyMCrPOk8A10rrOcCAwEAAaNTMFEwHQYDVR0OBBYEFMXzY0Gf
+eAdY8RjzwPnOou8VgjD3MB8GA1UdIwQYMBaAFMXzY0GfeAdY8RjzwPnOou8VgjD3
+MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBABrAExrvMkg26gQg
+rUh170Ms8T5jvIpWyIb7fSLjsA0c2q+zZiIUViO1t2eNQtdExGcmEOBF1+LqAIbT
+zA8nz9ZHweGZi01VodPaGKuz2VWWMzQaENW2RQGaxO9g8nCHGrbwchE7IbNOT1FD
+jzVYWcCKydr4niJWjSy9ey8eNDv/Iqto64/nPI7PxtBVfH7G8hgamyVtwWhhciTH
+nlg6X0EAxq5VwZSK4G8n+gsozPQHRjvBrSzt0A187vh/g6LQPLDZjPnzbZVtfFtM
+pv+hImxyDN3DZYrna2aGxWBIXEFjH61xueBGWaCo8TwvR8NIHM/i4s/zyhUxGUYL
+307i940cEF3rYJ/urzZzXJlxiu8p0Y12i/t+vXRqXM8d65QSMLqDDBHqZ3mPkcBp
+U7hWVi5HuyWGQF4FMK8sdemJITJpg1xztybsvRJ9kDeWxPNQllC4dREaKVhI/3WM
+eP7bpMmZxngoHbAB2f11lQf1A0fWFkng/Gntqnw0Dd6J+++NuuoFUjZLAWzUpoje
+J6J9CuxBjng0n94ZN+E8E5zsAtaO9WvhSQwTvNbHZmERxvtSm6mIH1XEBTi5tOHZ
+PBAAJuzZrFFZWevI44vgpCrF4lO3F9qE+sKn+2sARGuAjGCNV+jJCD+7tySjf7js
+2uaWgWOl7EexciIHD9FbZ3ANsiRU
+-----END CERTIFICATE-----
diff --git a/apex/manifest.json b/apex/manifest.json
new file mode 100644
index 0000000..4d1b2b6
--- /dev/null
+++ b/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.i18n",
+  "version": 1
+}
\ No newline at end of file
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
new file mode 100644
index 0000000..4f2f157
--- /dev/null
+++ b/benchmarks/Android.bp
@@ -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.
+
+java_test {
+    name: "benchmarks",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "mockwebserver",
+        "core-tests-support",
+    ],
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
+    libs: [
+        "caliper-api-target",
+        "android.test.base",
+    ],
+}
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
deleted file mode 100644
index 623ba9c..0000000
--- a/benchmarks/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# -*- mode: makefile -*-
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-ifeq ($(LIBCORE_SKIP_TESTS),)
-
-##################################################
-include $(CLEAR_VARS)
-LOCAL_MODULE := benchmarks
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := mockwebserver core-tests-support
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := \
-  caliper-api-target \
-  core-oj \
-  core-libart \
-  android.test.base
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(PRODUCT_OUT)/data/caliperperf
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_JAVA_LIBRARY)
-
-endif
diff --git a/dalvik/src/main/java/dalvik/annotation/codegen/CovariantReturnType.java b/dalvik/src/main/java/dalvik/annotation/codegen/CovariantReturnType.java
index f302850..b43600d 100644
--- a/dalvik/src/main/java/dalvik/annotation/codegen/CovariantReturnType.java
+++ b/dalvik/src/main/java/dalvik/annotation/codegen/CovariantReturnType.java
@@ -21,6 +21,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import libcore.api.CorePlatformApi;
 
 /**
  * Indicates to the platform toolchain that there is an upcoming public SDK API change for a method.
@@ -60,24 +61,29 @@
 @Repeatable(CovariantReturnType.CovariantReturnTypes.class)
 @Retention(RetentionPolicy.CLASS)
 @Target({ ElementType.METHOD})
+@CorePlatformApi
 public @interface CovariantReturnType {
 
     /**
      * The return type of the synthetic method to generate. Must be a subclass of the return type
      * of the method being annotated.
      */
+    @CorePlatformApi
     Class<?> returnType();
 
     /**
      * The last Android API level not to have the generated synthetic method. The annotation can be
      * removed and the actual return type updated when support for this API level is dropped.
      */
+    @CorePlatformApi
     int presentAfter();
 
     /** @hide */
     @Retention(RetentionPolicy.CLASS)
     @Target({ElementType.METHOD})
+    @CorePlatformApi
     @interface CovariantReturnTypes {
+        @CorePlatformApi
         CovariantReturnType[] value();
     }
 }
diff --git a/dalvik/src/main/java/dalvik/annotation/compat/UnsupportedAppUsage.java b/dalvik/src/main/java/dalvik/annotation/compat/UnsupportedAppUsage.java
deleted file mode 100644
index 82b2f10..0000000
--- a/dalvik/src/main/java/dalvik/annotation/compat/UnsupportedAppUsage.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2018 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.annotation.compat;
-
-import static java.lang.annotation.ElementType.CONSTRUCTOR;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dalvik.system.VersionCodes;
-import java.lang.annotation.Repeatable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import libcore.api.CorePlatformApi;
-import libcore.api.IntraCoreApi;
-
-/**
- * Indicates that a class member, that is not part of the SDK, is used by apps.
- * Since the member is not part of the SDK, such use is not supported.
- *
- * <p>This annotation acts as a heads up that changing a given method or field
- * may affect apps, potentially breaking them when the next Android version is
- * released. In some cases, for members that are heavily used, this annotation
- * may imply restrictions on changes to the member.
- *
- * <p>This annotation also results in access to the member being permitted by the
- * runtime, with a warning being generated in debug builds.
- *
- * <p>For more details, see go/UnsupportedAppUsage.
- *
- * {@hide}
- */
-@Retention(CLASS)
-@Target({CONSTRUCTOR, METHOD, FIELD, TYPE})
-@Repeatable(UnsupportedAppUsage.Container.class)
-@CorePlatformApi
-@IntraCoreApi
-public @interface UnsupportedAppUsage {
-
-    /**
-     * Associates a bug tracking the work to add a public alternative to this API. Optional.
-     *
-     * @return ID of the associated tracking bug
-     */
-    @CorePlatformApi
-    @IntraCoreApi
-    long trackingBug() default 0;
-
-    /**
-     * Indicates that usage of this API is limited to apps based on their target SDK version.
-     *
-     * <p>Access to the API is allowed if the targetSdkVersion in the apps manifest is no greater
-     * than this value. Access checks are performed at runtime.
-     *
-     * <p>This is used to give app developers a grace period to migrate off a non-SDK interface.
-     * When making Android version N, existing APIs can have a maxTargetSdk of N-1 added to them.
-     * Developers must then migrate off the API when their app is updated in future, but it will
-     * continue working in the meantime.
-     *
-     * <p>Possible values are:
-     * <ul>
-     *     <li>
-     *         {@link VersionCodes#O} - in which case the API is available up to and including the
-     *         O release and all intermediate releases between O and P. Or in other words the API
-     *         is blacklisted (unavailable) from P onwards.
-     *     </li>
-     *     <li>
-     *         {@link VersionCodes#P} - in which case the API is available up to and including the
-     *         P release and all intermediate releases between P and Q. Or in other words the API
-     *         is blacklisted (unavailable) from Q onwards.
-     *     </li>
-     *     <li>
-     *         absent (default value) - All apps can access this API, but doing so may result in
-     *         warnings in the log, UI warnings (on developer builds) and/or strictmode violations.
-     *         The API is likely to be further restricted in future.
-     *     </li>
-     *
-     * </ul>
-     *
-     * @return The maximum value for an apps targetSdkVersion in order to access this API.
-     */
-    @CorePlatformApi
-    @IntraCoreApi
-    int maxTargetSdk() default Integer.MAX_VALUE;
-
-    /**
-     * For debug use only. The expected dex signature to be generated for this API, used to verify
-     * parts of the build process.
-     *
-     * @return A dex API signature.
-     */
-    @CorePlatformApi
-    @IntraCoreApi
-    String expectedSignature() default "";
-
-    /**
-     * The signature of an implicit (not present in the source) member that forms part of the
-     * hiddenapi.
-     *
-     * <p>Allows access to non-SDK API elements that are not represented in the input source to be
-     * managed.
-     *
-     * <p>This must only be used when applying the annotation to a type, using it in any other
-     * situation is an error.
-     *
-     * @return A dex API signature.
-     */
-    @CorePlatformApi
-    @IntraCoreApi
-    String implicitMember() default "";
-
-    /**
-     * Container for {@link UnsupportedAppUsage} that allows it to be applied repeatedly to types.
-     */
-    @Retention(CLASS)
-    @Target(TYPE)
-    @CorePlatformApi
-    @IntraCoreApi
-    @interface Container {
-        @CorePlatformApi
-        @IntraCoreApi
-        UnsupportedAppUsage[] value();
-    }
-}
diff --git a/dalvik/src/main/java/dalvik/system/VersionCodes.java b/dalvik/src/main/java/dalvik/annotation/compat/VersionCodes.java
similarity index 89%
rename from dalvik/src/main/java/dalvik/system/VersionCodes.java
rename to dalvik/src/main/java/dalvik/annotation/compat/VersionCodes.java
index 670db0f..8f7bcd2 100644
--- a/dalvik/src/main/java/dalvik/system/VersionCodes.java
+++ b/dalvik/src/main/java/dalvik/annotation/compat/VersionCodes.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dalvik.system;
+package dalvik.annotation.compat;
 
 import libcore.api.CorePlatformApi;
 import libcore.api.IntraCoreApi;
@@ -50,4 +50,11 @@
     @CorePlatformApi
     @IntraCoreApi
     public static final int P = 28;
+
+    /**
+     * The version code for Android Q (API version 29).
+     */
+    @CorePlatformApi
+    @IntraCoreApi
+    public static final int Q = 29;
 }
diff --git a/dalvik/src/main/java/dalvik/annotation/optimization/FastNative.java b/dalvik/src/main/java/dalvik/annotation/optimization/FastNative.java
index a5c0dc5..f25233c 100644
--- a/dalvik/src/main/java/dalvik/annotation/optimization/FastNative.java
+++ b/dalvik/src/main/java/dalvik/annotation/optimization/FastNative.java
@@ -57,6 +57,16 @@
  * </p>
  *
  * <p>
+ * Note that even in FastNative methods you <b>are</b> allowed to
+ * allocate objects and make upcalls into Java code. A call from Java to
+ * a FastNative function and back to Java is equivalent to a call from one Java
+ * method to another. What's forbidden in a FastNative method is blocking
+ * the calling thread in some non-Java code and thereby preventing the thread
+ * from responding to requests from the garbage collector to enter the suspended
+ * state.
+ * </p>
+ *
+ * <p>
  * Has no effect when used with non-native methods.
  * </p>
  *
diff --git a/dalvik/src/main/java/dalvik/annotation/optimization/ReachabilitySensitive.java b/dalvik/src/main/java/dalvik/annotation/optimization/ReachabilitySensitive.java
index 4eea1a5..7b82c3c 100644
--- a/dalvik/src/main/java/dalvik/annotation/optimization/ReachabilitySensitive.java
+++ b/dalvik/src/main/java/dalvik/annotation/optimization/ReachabilitySensitive.java
@@ -79,6 +79,7 @@
  *
  * @hide
  */
+@libcore.api.IntraCoreApi
 @Retention(RetentionPolicy.RUNTIME)  // Let the GC or interpreter ask, if they need to.
                                      // TODO(b/72332040): Reconsider retention later.
 @Target({ElementType.FIELD, ElementType.METHOD})
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index 9cf5f80..ee20d80 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -16,7 +16,7 @@
 
 package dalvik.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
@@ -24,8 +24,11 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import sun.misc.CompoundEnumeration;
 
 /**
@@ -125,40 +128,48 @@
                 : Arrays.copyOf(sharedLibraryLoaders, sharedLibraryLoaders.length);
         this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
 
-        if (reporter != null) {
-            reportClassLoaderChain();
-        }
+        reportClassLoaderChain();
     }
 
     /**
      * Reports the current class loader chain to the registered {@code reporter}.
+     *
+     * @hide
      */
-    private void reportClassLoaderChain() {
-        ArrayList<ClassLoader> classLoadersChain = new ArrayList<>();
-        ArrayList<String> classPaths = new ArrayList<>();
-
-        classLoadersChain.add(this);
-        classPaths.add(String.join(File.pathSeparator, pathList.getDexPaths()));
-
-        ClassLoader bootClassLoader = ClassLoader.getSystemClassLoader().getParent();
-        ClassLoader current = getParent();
-
-        while (current != null && current != bootClassLoader) {
-            classLoadersChain.add(current);
-            if (current instanceof BaseDexClassLoader) {
-                BaseDexClassLoader bdcCurrent = (BaseDexClassLoader) current;
-                classPaths.add(String.join(File.pathSeparator, bdcCurrent.pathList.getDexPaths()));
-            } else {
-                // We can't determine the classpath for arbitrary class loaders.
-                classPaths.add(null);
-            }
-            current = current.getParent();
+    @libcore.api.CorePlatformApi
+    public void reportClassLoaderChain() {
+        if (reporter == null) {
+            return;
         }
 
-        reporter.report(classLoadersChain, classPaths);
+        String[] classPathAndClassLoaderContexts = computeClassLoaderContextsNative();
+        if (classPathAndClassLoaderContexts.length == 0) {
+            return;
+        }
+        Map<String, String> dexFileMapping =
+                new HashMap<>(classPathAndClassLoaderContexts.length / 2);
+        for (int i = 0; i < classPathAndClassLoaderContexts.length; i += 2) {
+            dexFileMapping.put(classPathAndClassLoaderContexts[i],
+                    classPathAndClassLoaderContexts[i + 1]);
+        }
+        reporter.report(Collections.unmodifiableMap(dexFileMapping));
     }
 
     /**
+     * Computes the classloader contexts for each classpath entry in {@code pathList.getDexPaths()}.
+     *
+     * Note that this method is not thread safe, i.e. it is the responsibility of the caller to
+     * ensure that {@code pathList.getDexPaths()} is not modified concurrently with this method
+     * being called.
+     *
+     * @return A non-null array of non-null strings of length
+     *   {@code 2 * pathList.getDexPaths().size()}. Every even index (0 is even here) is a dex file
+     *   path and every odd entry is the class loader context used to load the previously listed dex
+     *   file. E.g. a result might be {@code { "foo.dex", "PCL[]", "bar.dex", "PCL[foo.dex]" } }.
+     */
+    private native String[] computeClassLoaderContextsNative();
+
+    /**
      * Constructs an instance.
      *
      * dexFile must be an in-memory representation of a full dexFile.
@@ -359,19 +370,16 @@
     @libcore.api.CorePlatformApi
     public interface Reporter {
         /**
-         * Reports the construction of a BaseDexClassLoader and provides information about the
-         * class loader chain.
+         * Reports the construction of a BaseDexClassLoader and provides opaque information about
+         * the class loader chain. For example, if the childmost ClassLoader in the chain:
+         * {@quote BaseDexClassLoader { foo.dex } -> BaseDexClassLoader { base.apk }
+         *    -> BootClassLoader } was just initialized then the load of {@code "foo.dex"} would be
+         * reported with a classLoaderContext of {@code "PCL[];PCL[base.apk]"}.
          *
-         * @param classLoadersChain the chain of class loaders used during the construction of the
-         *     class loader. The first element is the BaseDexClassLoader being constructed,
-         *     the second element is its parent, and so on.
-         * @param classPaths the class paths of the class loaders present in
-         *     {@param classLoadersChain}. The first element corresponds to the first class
-         *     loader and so on. A classpath is represented as a list of dex files separated by
-         *     {@code File.pathSeparator}. If the class loader is not a BaseDexClassLoader the
-         *     classpath will be null.
+         * @param contextsMap A map from dex file paths to the class loader context used to load
+         *     each dex file.
          */
         @libcore.api.CorePlatformApi
-        void report(List<ClassLoader> classLoadersChain, List<String> classPaths);
+        void report(Map<String, String> contextsMap);
     }
 }
diff --git a/dalvik/src/main/java/dalvik/system/BlockGuard.java b/dalvik/src/main/java/dalvik/system/BlockGuard.java
index c608407..192e450 100644
--- a/dalvik/src/main/java/dalvik/system/BlockGuard.java
+++ b/dalvik/src/main/java/dalvik/system/BlockGuard.java
@@ -16,10 +16,10 @@
 
 package dalvik.system;
 
-import libcore.util.NonNull;
+import android.compat.annotation.UnsupportedAppUsage;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import java.util.Objects;
+import libcore.util.NonNull;
 
 /**
  * Interface that enables {@code StrictMode} to install callbacks to implement
diff --git a/dalvik/src/main/java/dalvik/system/CloseGuard.java b/dalvik/src/main/java/dalvik/system/CloseGuard.java
index 6fe94a9..99ddf3e 100644
--- a/dalvik/src/main/java/dalvik/system/CloseGuard.java
+++ b/dalvik/src/main/java/dalvik/system/CloseGuard.java
@@ -16,7 +16,7 @@
 
 package dalvik.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * CloseGuard is a mechanism for flagging implicit finalizer cleanup of
@@ -134,11 +134,14 @@
      */
     private static volatile Tracker currentTracker = null; // Disabled by default.
 
+    private static final String MESSAGE = "A resource was acquired at attached stack trace but never released. " +
+            "See java.io.Closeable for information on avoiding resource leaks.";
+
     /**
      * Returns a CloseGuard instance. {@code #open(String)} can be used to set
      * up the instance to warn on failure to close.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug=111170242)
     @libcore.api.CorePlatformApi
     @libcore.api.IntraCoreApi
     public static CloseGuard get() {
@@ -220,10 +223,25 @@
      * @param closer non-null name of explicit termination method. Printed by warnIfOpen.
      * @throws NullPointerException if closer is null.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug=111170242)
     @libcore.api.CorePlatformApi
     @libcore.api.IntraCoreApi
     public void open(String closer) {
+        openWithCallSite(closer, null /* callsite */);
+    }
+
+    /**
+     * Like {@link #open(String)}, but with explicit callsite string being passed in for better
+     * performance.
+     * <p>
+     * This only has better performance than {@link #open(String)} if {@link #isEnabled()} returns {@code true}, which
+     * usually shouldn't happen on release builds.
+     *
+     * @param closer Non-null name of explicit termination method. Printed by warnIfOpen.
+     * @param callsite Non-null string uniquely identifying the callsite.
+     */
+    @libcore.api.CorePlatformApi
+    public void openWithCallSite(String closer, String callsite) {
         // always perform the check for valid API usage...
         if (closer == null) {
             throw new NullPointerException("closer == null");
@@ -233,12 +251,18 @@
             closerNameOrAllocationInfo = closer;
             return;
         }
-        String message = "Explicit termination method '" + closer + "' not called";
-        Throwable stack = new Throwable(message);
-        closerNameOrAllocationInfo = stack;
+        // Always record stack trace when tracker installed, which only happens in tests. Otherwise, skip expensive
+        // stack trace creation when explicit callsite is passed in for better performance.
         Tracker tracker = currentTracker;
-        if (tracker != null) {
-            tracker.open(stack);
+        if (callsite == null || tracker != null) {
+            String message = "Explicit termination method '" + closer + "' not called";
+            Throwable stack = new Throwable(message);
+            closerNameOrAllocationInfo = stack;
+            if (tracker != null) {
+                tracker.open(stack);
+            }
+        } else {
+            closerNameOrAllocationInfo = callsite;
         }
     }
 
@@ -270,24 +294,23 @@
      * the allocation to the current reporter. If it was not enabled, it just
      * directly logs a brief message.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug=111170242)
     @libcore.api.CorePlatformApi
     @libcore.api.IntraCoreApi
     public void warnIfOpen() {
         if (closerNameOrAllocationInfo != null) {
-            if (closerNameOrAllocationInfo instanceof String) {
+            if (closerNameOrAllocationInfo instanceof Throwable) {
+                reporter.report(MESSAGE, (Throwable) closerNameOrAllocationInfo);
+            } else if (stackAndTrackingEnabled) {
+                reporter.report(MESSAGE + " Callsite: " + closerNameOrAllocationInfo);
+            } else {
                 System.logW("A resource failed to call "
                         + (String) closerNameOrAllocationInfo + ". ");
-            } else {
-                String message =
-                        "A resource was acquired at attached stack trace but never released. ";
-                message += "See java.io.Closeable for information on avoiding resource leaks.";
-                Throwable stack = (Throwable) closerNameOrAllocationInfo;
-                reporter.report(message, stack);
             }
         }
     }
 
+
     /**
      * Interface to allow customization of tracking behaviour.
      *
@@ -308,6 +331,9 @@
         @UnsupportedAppUsage
         @libcore.api.CorePlatformApi
         void report(String message, Throwable allocationSite);
+
+        @libcore.api.CorePlatformApi
+        default void report(String message) {}
     }
 
     /**
@@ -320,5 +346,10 @@
         @Override public void report (String message, Throwable allocationSite) {
             System.logW(message, allocationSite);
         }
+
+        @Override
+        public void report(String message) {
+            System.logW(message);
+        }
     }
 }
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index 486ee90..176fde4 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -16,9 +16,9 @@
 
 package dalvik.system;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.annotation.optimization.ReachabilitySensitive;
+
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -28,6 +28,8 @@
 import java.util.List;
 import libcore.io.Libcore;
 
+import dalvik.annotation.optimization.ReachabilitySensitive;
+
 /**
  * Loads DEX files. This class is meant for internal use and should not be used
  * by applications.
diff --git a/dalvik/src/main/java/dalvik/system/DexPathList.java b/dalvik/src/main/java/dalvik/system/DexPathList.java
index c63bb13..798166c 100644
--- a/dalvik/src/main/java/dalvik/system/DexPathList.java
+++ b/dalvik/src/main/java/dalvik/system/DexPathList.java
@@ -16,11 +16,13 @@
 
 package dalvik.system;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 import android.system.StructStat;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Array;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.ByteBuffer;
@@ -219,32 +221,25 @@
                 suppressedExceptionList, definingContext, isTrusted);
 
         if (newElements != null && newElements.length > 0) {
-            final Element[] oldElements = dexElements;
-            dexElements = new Element[oldElements.length + newElements.length];
-            System.arraycopy(
-                    oldElements, 0, dexElements, 0, oldElements.length);
-            System.arraycopy(
-                    newElements, 0, dexElements, oldElements.length, newElements.length);
+            dexElements = concat(Element.class, dexElements, newElements);
         }
 
         if (suppressedExceptionList.size() > 0) {
-            final IOException[] newSuppressedExceptions = suppressedExceptionList.toArray(
+            final IOException[] newSuppExceptions = suppressedExceptionList.toArray(
                     new IOException[suppressedExceptionList.size()]);
-            if (dexElementsSuppressedExceptions != null) {
-                final IOException[] oldSuppressedExceptions = dexElementsSuppressedExceptions;
-                final int suppressedExceptionsLength = oldSuppressedExceptions.length +
-                        newSuppressedExceptions.length;
-                dexElementsSuppressedExceptions = new IOException[suppressedExceptionsLength];
-                System.arraycopy(oldSuppressedExceptions, 0, dexElementsSuppressedExceptions,
-                        0, oldSuppressedExceptions.length);
-                System.arraycopy(newSuppressedExceptions, 0, dexElementsSuppressedExceptions,
-                        oldSuppressedExceptions.length, newSuppressedExceptions.length);
-            } else {
-                dexElementsSuppressedExceptions = newSuppressedExceptions;
-            }
+            dexElementsSuppressedExceptions = dexElementsSuppressedExceptions != null
+                    ? concat(IOException.class, dexElementsSuppressedExceptions, newSuppExceptions)
+                    : newSuppExceptions;
         }
     }
 
+    private static<T> T[] concat(Class<T> componentType, T[] inputA, T[] inputB) {
+        T[] output = (T[]) Array.newInstance(componentType, inputA.length + inputB.length);
+        System.arraycopy(inputA, 0, output, 0, inputA.length);
+        System.arraycopy(inputB, 0, output, inputA.length, inputB.length);
+        return output;
+    }
+
     /**
      * For InMemoryDexClassLoader. Initializes {@code dexElements} with dex files
      * loaded from {@code dexFiles} buffers.
diff --git a/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java b/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java
index b479d6f..7a1c20b 100644
--- a/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java
+++ b/dalvik/src/main/java/dalvik/system/EmulatedStackFrame.java
@@ -346,20 +346,29 @@
             return this;
         }
 
-        protected void checkType(Class<?> type) {
+        private Class<?> getCurrentArgumentType() {
             if (argumentIdx >= numArgs || argumentIdx == (RETURN_VALUE_IDX + 1)) {
                 throw new IllegalArgumentException("Invalid argument index: " + argumentIdx);
             }
-
-            final Class<?> expectedType = (argumentIdx == RETURN_VALUE_IDX) ?
+            return (argumentIdx == RETURN_VALUE_IDX) ?
                     frame.type.rtype() : frame.type.ptypes()[argumentIdx];
+        }
 
-            if (expectedType != type) {
-                throw new IllegalArgumentException("Incorrect type: " + type +
-                        ", expected: " + expectedType);
+        private static void checkAssignable(Class<?> expectedType, Class<?> actualType) {
+            if (!expectedType.isAssignableFrom(actualType)) {
+                throw new IllegalArgumentException("Incorrect type: " + actualType
+                                                   + ", expected: " + expectedType);
             }
         }
 
+        protected void checkWriteType(Class<?> type) {
+            checkAssignable(getCurrentArgumentType(), type);
+        }
+
+        protected void checkReadType(Class<?> expectedType) {
+            checkAssignable(expectedType, getCurrentArgumentType());
+        }
+
         /**
          * Positions the cursor at the return value location, either in the references array
          * or in the stack frame array. The next put* or next* call will result in a read or
@@ -408,55 +417,55 @@
      */
     public static class StackFrameWriter extends StackFrameAccessor {
         public void putNextByte(byte value) {
-            checkType(byte.class);
+            checkWriteType(byte.class);
             argumentIdx++;
             frameBuf.putInt(value);
         }
 
         public void putNextInt(int value) {
-            checkType(int.class);
+            checkWriteType(int.class);
             argumentIdx++;
             frameBuf.putInt(value);
         }
 
         public void putNextLong(long value) {
-            checkType(long.class);
+            checkWriteType(long.class);
             argumentIdx++;
             frameBuf.putLong(value);
         }
 
         public void putNextChar(char value) {
-            checkType(char.class);
+            checkWriteType(char.class);
             argumentIdx++;
             frameBuf.putInt((int) value);
         }
 
         public void putNextBoolean(boolean value) {
-            checkType(boolean.class);
+            checkWriteType(boolean.class);
             argumentIdx++;
             frameBuf.putInt(value ? 1 : 0);
         }
 
         public void putNextShort(short value) {
-            checkType(short.class);
+            checkWriteType(short.class);
             argumentIdx++;
             frameBuf.putInt((int) value);
         }
 
         public void putNextFloat(float value) {
-            checkType(float.class);
+            checkWriteType(float.class);
             argumentIdx++;
             frameBuf.putFloat(value);
         }
 
         public void putNextDouble(double value) {
-            checkType(double.class);
+            checkWriteType(double.class);
             argumentIdx++;
             frameBuf.putDouble(value);
         }
 
         public void putNextReference(Object value, Class<?> expectedType) {
-            checkType(expectedType);
+            checkWriteType(expectedType);
             argumentIdx++;
             frame.references[referencesOffset++] = value;
         }
@@ -468,55 +477,55 @@
      */
     public static class StackFrameReader extends StackFrameAccessor {
         public byte nextByte() {
-            checkType(byte.class);
+            checkReadType(byte.class);
             argumentIdx++;
             return (byte) frameBuf.getInt();
         }
 
         public int nextInt() {
-            checkType(int.class);
+            checkReadType(int.class);
             argumentIdx++;
             return frameBuf.getInt();
         }
 
         public long nextLong() {
-            checkType(long.class);
+            checkReadType(long.class);
             argumentIdx++;
             return frameBuf.getLong();
         }
 
         public char nextChar() {
-            checkType(char.class);
+            checkReadType(char.class);
             argumentIdx++;
             return (char) frameBuf.getInt();
         }
 
         public boolean nextBoolean() {
-            checkType(boolean.class);
+            checkReadType(boolean.class);
             argumentIdx++;
             return (frameBuf.getInt() != 0);
         }
 
         public short nextShort() {
-            checkType(short.class);
+            checkReadType(short.class);
             argumentIdx++;
             return (short) frameBuf.getInt();
         }
 
         public float nextFloat() {
-            checkType(float.class);
+            checkReadType(float.class);
             argumentIdx++;
             return frameBuf.getFloat();
         }
 
         public double nextDouble() {
-            checkType(double.class);
+            checkReadType(double.class);
             argumentIdx++;
             return frameBuf.getDouble();
         }
 
         public <T> T nextReference(Class<T> expectedType) {
-            checkType(expectedType);
+            checkReadType(expectedType);
             argumentIdx++;
             return (T) frame.references[referencesOffset++];
         }
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/SocketTagger.java b/dalvik/src/main/java/dalvik/system/SocketTagger.java
index 54ede15..0493daa 100644
--- a/dalvik/src/main/java/dalvik/system/SocketTagger.java
+++ b/dalvik/src/main/java/dalvik/system/SocketTagger.java
@@ -16,7 +16,7 @@
 
 package dalvik.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.io.FileDescriptor;
 import java.net.DatagramSocket;
 import java.net.Socket;
diff --git a/dalvik/src/main/java/dalvik/system/TEST_MAPPING b/dalvik/src/main/java/dalvik/system/TEST_MAPPING
new file mode 100644
index 0000000..5f4d46c
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.dalvik.system"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
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/dalvik/src/main/java/dalvik/system/VMDebug.java b/dalvik/src/main/java/dalvik/system/VMDebug.java
index 2a0e4ef..4436e3f 100644
--- a/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -16,13 +16,15 @@
 
 package dalvik.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.annotation.optimization.FastNative;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
+import dalvik.annotation.optimization.FastNative;
+
 /**
  * Provides access to some VM-specific debug features. Though this class and
  * many of its members are public, this class is meant to be wrapped in a more
diff --git a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
index 13769e1..7e8fe36 100644
--- a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
+++ b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
@@ -21,6 +21,7 @@
 import android.icu.util.ULocale;
 
 import java.io.File;
+import java.io.FileDescriptor;
 
 /**
  * Provides hooks for the zygote to call back into the runtime to perform
@@ -58,6 +59,12 @@
         for (ULocale uLocale : localesToPin) {
             new DecimalFormatSymbols(uLocale);
         }
+
+        // Framework's LocalLog is used during app start-up. It indirectly uses the current ICU time
+        // zone. Pre-loading the current time zone in ICU improves app startup time. b/150605074
+        // We're being explicit about the fully qualified name of the TimeZone class to avoid
+        // confusion with java.util.TimeZome.getDefault().
+        android.icu.util.TimeZone.getDefault();
     }
 
     /**
@@ -67,6 +74,11 @@
     public static void onEndPreload() {
         // All cache references created by ICU from this point will be soft.
         CacheValue.setStrength(CacheValue.Strength.SOFT);
+
+        // Clone standard descriptors as originals closed / rebound during zygote post fork.
+        FileDescriptor.in.cloneForFork();
+        FileDescriptor.out.cloneForFork();
+        FileDescriptor.err.cloneForFork();
     }
 
     /**
@@ -112,8 +124,8 @@
      * before {@code postForkChild} for system server.
      */
     @libcore.api.CorePlatformApi
-    public static void postForkSystemServer() {
-        nativePostForkSystemServer();
+    public static void postForkSystemServer(int runtimeFlags) {
+        nativePostForkSystemServer(runtimeFlags);
     }
 
     /**
@@ -136,13 +148,14 @@
      */
     @libcore.api.CorePlatformApi
     public static void postForkCommon() {
-        Daemons.startPostZygoteFork();
+        // Notify the runtime before creating new threads.
         nativePostZygoteFork();
+        Daemons.startPostZygoteFork();
     }
 
 
     // Hook for SystemServer specific early initialization post-forking.
-    private static native void nativePostForkSystemServer();
+    private static native void nativePostForkSystemServer(int runtimeFlags);
 
     private static native long nativePreFork();
     private static native void nativePostZygoteFork();
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java
index 373364b..292e967 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java
@@ -16,7 +16,7 @@
 
 package org.apache.harmony.dalvik.ddmc;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.nio.ByteBuffer;
 
 /**
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java
index d7f370d..0fb74f8 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java
@@ -16,7 +16,7 @@
 
 package org.apache.harmony.dalvik.ddmc;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
index e961d56..f1f58b6 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
@@ -16,12 +16,14 @@
 
 package org.apache.harmony.dalvik.ddmc;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.annotation.optimization.FastNative;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 
+import dalvik.annotation.optimization.FastNative;
+
 
 /**
  * This represents our connection to the DDM Server.
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java
index ac994bb..2c961da 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java
@@ -16,7 +16,7 @@
 
 package org.apache.harmony.dalvik.ddmc;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import dalvik.annotation.optimization.FastNative;
 
 /**
diff --git a/dalvik/src/test/java/libcore/dalvik/system/CloseGuardTest.java b/dalvik/src/test/java/libcore/dalvik/system/CloseGuardTest.java
index f7f58bd..92c2946 100644
--- a/dalvik/src/test/java/libcore/dalvik/system/CloseGuardTest.java
+++ b/dalvik/src/test/java/libcore/dalvik/system/CloseGuardTest.java
@@ -64,6 +64,14 @@
     }
 
     @Test
+    public void testEnabled_OpenWithCallsiteNotClosed() throws Throwable {
+        CloseGuard.setEnabled(true);
+        ResourceOwner owner = new ResourceOwner();
+        owner.openWithCallsite("testEnabled_OpoenWIthCallsiteNotClosed");
+        assertUnreleasedResources(owner, 1);
+    }
+
+    @Test
     public void testEnabled_OpenThenClosed() throws Throwable {
         CloseGuard.setEnabled(true);
         ResourceOwner owner = new ResourceOwner();
@@ -73,6 +81,15 @@
     }
 
     @Test
+    public void testEnabled_OpenWithCallsiteThenClosed() throws Throwable {
+        CloseGuard.setEnabled(true);
+        ResourceOwner owner = new ResourceOwner();
+        owner.openWithCallsite("testEnabled_OpenWithCallsiteThenClosed");
+        owner.close();
+        assertUnreleasedResources(owner, 0);
+    }
+
+    @Test
     public void testEnabledWhenCreated_DisabledWhenOpen() throws Throwable {
         CloseGuard.setEnabled(true);
         ResourceOwner owner = new ResourceOwner();
@@ -111,6 +128,14 @@
     }
 
     @Test
+    public void testDisabled_OpenWithCallsiteNotClosed() throws Throwable {
+        CloseGuard.setEnabled(false);
+        ResourceOwner owner = new ResourceOwner();
+        owner.openWithCallsite("testDisabled_OpenWithCallsiteNotClosed");
+        assertUnreleasedResources(owner, 0);
+    }
+
+    @Test
     public void testDisabled_OpenThenClosed() throws Throwable {
         CloseGuard.setEnabled(false);
         ResourceOwner owner = new ResourceOwner();
@@ -120,6 +145,15 @@
     }
 
     @Test
+    public void testDisabled_OpenWithCallsiteThenClosed() throws Throwable {
+        CloseGuard.setEnabled(false);
+        ResourceOwner owner = new ResourceOwner();
+        owner.openWithCallsite("testDisabled_OpenWithCallsiteThenClosed");
+        owner.close();
+        assertUnreleasedResources(owner, 0);
+    }
+
+    @Test
     public void testDisabledWhenCreated_EnabledWhenOpen() throws Throwable {
         CloseGuard.setEnabled(false);
         ResourceOwner owner = new ResourceOwner();
@@ -156,6 +190,10 @@
             closeGuard.open("close");
         }
 
+        public void openWithCallsite(String callsite) {
+            closeGuard.openWithCallSite("close", callsite);
+        }
+
         public void close() {
             closeGuard.close();
         }
diff --git a/dalvik/test-rules/src/main/java/libcore/dalvik/system/CloseGuardSupport.java b/dalvik/test-rules/src/main/java/libcore/dalvik/system/CloseGuardSupport.java
index ca007a8..e419f16 100644
--- a/dalvik/test-rules/src/main/java/libcore/dalvik/system/CloseGuardSupport.java
+++ b/dalvik/test-rules/src/main/java/libcore/dalvik/system/CloseGuardSupport.java
@@ -261,6 +261,7 @@
         private final Thread callingThread = Thread.currentThread();
 
         private final List<Throwable> unreleasedResourceAllocationSites = new ArrayList<>();
+        private final List<String> unreleasedResourceAllocationCallsites = new ArrayList<>();
 
         @Override
         public void report(String message, Throwable allocationSite) {
@@ -270,8 +271,17 @@
             }
         }
 
+        @Override
+        public void report(String message) {
+            // Only care about resources that are not reported on this thread.
+            if (callingThread == Thread.currentThread()) {
+                unreleasedResourceAllocationCallsites.add(message);
+            }
+        }
+
         void assertUnreleasedResources(int expectedCount) {
-            int unreleasedResourceCount = unreleasedResourceAllocationSites.size();
+            int unreleasedResourceCount = unreleasedResourceAllocationSites.size()
+                    + unreleasedResourceAllocationCallsites.size();
             if (unreleasedResourceCount == expectedCount) {
                 return;
             }
@@ -282,6 +292,9 @@
             for (Throwable unreleasedResourceAllocationSite : unreleasedResourceAllocationSites) {
                 error.addSuppressed(unreleasedResourceAllocationSite);
             }
+            for (String unreleasedResourceAllocationCallsite : unreleasedResourceAllocationCallsites) {
+                error.addSuppressed(new Throwable(unreleasedResourceAllocationCallsite));
+            }
             throw error;
         }
     }
diff --git a/expectations/Android.bp b/expectations/Android.bp
new file mode 100644
index 0000000..c2667d3
--- /dev/null
+++ b/expectations/Android.bp
@@ -0,0 +1,29 @@
+// 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.
+
+expectations_visibility = [
+    "//cts/tests/libcore:__subpackages__",
+]
+
+filegroup {
+    name: "libcore-expectations-knownfailures",
+    visibility: expectations_visibility,
+    srcs: ["knownfailures.txt"],
+}
+
+filegroup {
+    name: "libcore-expectations-virtualdeviceknownfailures",
+    visibility: expectations_visibility,
+    srcs: ["virtualdeviceknownfailures.txt"],
+}
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 6c14660..80e1c97 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1312,12 +1312,6 @@
   ]
 },
 {
-  description: "Known failure in MathTest 1^NAN should be NAN",
-  bug: 11669804,
-  result: EXEC_FAILED,
-  name: "org.apache.harmony.tests.java.lang.MathTest#test_powDD"
-},
-{
   description: "Known failures in URLTest and URLDecoderTest",
   bug: 11686814,
   names: [
@@ -1336,80 +1330,63 @@
   description: "external/apache-harmony tests for java.sql are broken for various reasons. java.sql is not a high enough priority to fix.",
   bug: 17342415,
   names: [
-    "com.android.org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetDataSize",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetIndex",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetParameter",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetRead",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetTransferSize",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testDataTruncationintbooleanbooleanintint",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DateTest#test_valueOf_IllegalArgumentException",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testDeregisterDriver",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testGetConnectionString",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testGetConnectionStringProperties",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testGetConnectionStringStringString",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testGetDriver",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testGetDrivers",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testGetLogStream",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testGetLogWriter",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testGetLoginTimeout",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testPrintln",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testRegisterDriver",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testSetLogStream",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testSetLogWriter",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#testSetLoginTimeout",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#test_getConnection_LStringLProperties",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#test_initClass",
-    "com.android.org.apache.harmony.sql.tests.java.sql.DriverManagerTest#test_registerDriver_MultiTimes",
-    "com.android.org.apache.harmony.sql.tests.java.sql.TimestampTest#testCompareToDate",
-    "com.android.org.apache.harmony.sql.tests.java.sql.TimestampTest#testOverridingTimestamp"
+    "org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetDataSize",
+    "org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetIndex",
+    "org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetParameter",
+    "org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetRead",
+    "org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testGetTransferSize",
+    "org.apache.harmony.sql.tests.java.sql.DataTruncationTest#testDataTruncationintbooleanbooleanintint",
+    "org.apache.harmony.sql.tests.java.sql.DateTest#test_valueOf_IllegalArgumentException",
+    "org.apache.harmony.sql.tests.java.sql.TimestampTest#testCompareToDate",
+    "org.apache.harmony.sql.tests.java.sql.TimestampTest#testOverridingTimestamp"
   ]
 },
 {
   description: "java.util.logging: Android introduced config fallback behavior in LogManager.readConfiguration()",
   bug: 13882147,
   names: [
-    "com.android.org.apache.harmony.logging.tests.java.util.logging.LogManagerTest#testNotExistConfigFile",
-    "com.android.org.apache.harmony.logging.tests.java.util.logging.LoggerTest#testGetLogger_Empty",
-    "com.android.org.apache.harmony.logging.tests.java.util.logging.LoggerTest#testGetLogger_Null",
-    "com.android.org.apache.harmony.logging.tests.java.util.logging.LoggerTest#testGetLoggerWithRes_InvalidRes",
-    "com.android.org.apache.harmony.logging.tests.java.util.logging.LoggerTest#testGetLoggerWithRes_Empty"
+    "org.apache.harmony.logging.tests.java.util.logging.LogManagerTest#testNotExistConfigFile",
+    "org.apache.harmony.logging.tests.java.util.logging.LoggerTest#testGetLogger_Empty",
+    "org.apache.harmony.logging.tests.java.util.logging.LoggerTest#testGetLogger_Null",
+    "org.apache.harmony.logging.tests.java.util.logging.LoggerTest#testGetLoggerWithRes_InvalidRes",
+    "org.apache.harmony.logging.tests.java.util.logging.LoggerTest#testGetLoggerWithRes_Empty"
   ]
 },
 {
   description: "java.util.logging: Android's user.home system property cannot be cleared",
   bug: 13882147,
   names: [
-    "com.android.org.apache.harmony.logging.tests.java.util.logging.FileHandlerTest#testConstructor_NoUsrHome",
-    "com.android.org.apache.harmony.logging.tests.java.util.logging.FileHandlerTest#testConstructor_NoTmpDir_NoUsrHome"
+    "org.apache.harmony.logging.tests.java.util.logging.FileHandlerTest#testConstructor_NoUsrHome",
+    "org.apache.harmony.logging.tests.java.util.logging.FileHandlerTest#testConstructor_NoTmpDir_NoUsrHome"
   ]
 },
 {
   description: "java.util.logging: Android's user.home system property points to root (/) dir",
   bug: 13882147,
-  name: "com.android.org.apache.harmony.logging.tests.java.util.logging.FileHandlerTest#testConstructor_NoTmpDir"
+  name: "org.apache.harmony.logging.tests.java.util.logging.FileHandlerTest#testConstructor_NoTmpDir"
 },
 {
   description: "java.util.logging: The defaults for FileHandler don't work on Android because they try to write to the read-only user.home dir",
   bug: 13882147,
-  name: "com.android.org.apache.harmony.logging.tests.java.util.logging.FileHandlerTest#testDefaultValue"
+  name: "org.apache.harmony.logging.tests.java.util.logging.FileHandlerTest#testDefaultValue"
 },
 {
   description: "java.util.logging: Android's classes have been stubbed in places.",
   bug: 13882147,
   names: [
-    "com.android.org.apache.harmony.logging.tests.java.util.logging.LogManagerTest#testGetLoggingMXBean"
+    "org.apache.harmony.logging.tests.java.util.logging.LogManagerTest#testGetLoggingMXBean"
   ]
 },
 {
-  description: "java.util.logging: the serialized form references org.apache not com.android.org.apache",
+  description: "java.util.logging: the serialized form references org.apache not org.apache",
   bug: 13882147,
-  name: "com.android.org.apache.harmony.logging.tests.java.util.logging.LevelTest#testSerializationCompatibility"
+  name: "org.apache.harmony.logging.tests.java.util.logging.LevelTest#testSerializationCompatibility"
 },
 {
-  description: "java.util.beans: the serialized form references org.apache not com.android.org.apache",
+  description: "java.util.beans: the serialized form references org.apache not org.apache",
   bug: 17394106,
   names: [
-    "com.android.org.apache.harmony.beans.tests.java.beans.PropertyChangeSupportTest#testSerializationCompatibility"
+    "org.apache.harmony.beans.tests.java.beans.PropertyChangeSupportTest#testSerializationCompatibility"
   ]
 },
 {
@@ -1513,7 +1490,7 @@
   bug: 28536847,
   result: EXEC_FAILED,
   names: [
-    "com.android.org.apache.harmony.luni.tests.java.net.UnixNetworkInterfaceTest"
+    "org.apache.harmony.luni.tests.java.net.UnixNetworkInterfaceTest"
   ]
 },
 {
@@ -1521,7 +1498,7 @@
   bug: 28535349,
   result: EXEC_FAILED,
   names: [
-    "com.android.org.apache.harmony.luni.tests.java.net.URLClassLoaderImplTest#test_Constructor$Ljava_net_URLLjava_lang_ClassLoaderLjava_net_URLStreamHandlerFactory"
+    "org.apache.harmony.luni.tests.java.net.URLClassLoaderImplTest#test_Constructor$Ljava_net_URLLjava_lang_ClassLoaderLjava_net_URLStreamHandlerFactory"
   ]
 },
 {
@@ -1721,7 +1698,7 @@
   description: "Some tests (ExcludedProxyTest) connect to a public webserver to check that the HTTP client works",
   result: EXEC_FAILED,
   names: [
-    "com.android.org.apache.harmony.luni.tests.java.net.ExcludedProxyTest"
+    "org.apache.harmony.luni.tests.java.net.ExcludedProxyTest"
   ]
 },
 {
@@ -1749,14 +1726,6 @@
   ]
 },
 {
-  description: "The ResourceBundle code under test is probably not used much on Android and needs a lot of attention.",
-  modes: [device],
-  bug: 13747957,
-  names: [
-      "org.apache.harmony.tests.java.util.ControlTest#test_needsReload_LStringLLocaleLStringLClassLoaderResourceBundleJ"
-  ]
-},
-{
   description: "Fails in CTS, passes in CoreTestRunner.",
   result: EXEC_FAILED,
   modes: [device],
@@ -1814,15 +1783,7 @@
   bug: 28535961,
   result: EXEC_FAILED,
   names: [
-      "com.android.org.apache.harmony.luni.tests.java.net.URLClassLoaderTest"
-  ]
-},
-{
-  description: "Unable to execute Support_AvailTest",
-  result: EXEC_FAILED,
-  bug: 28535603,
-  names: [
-      "com.android.org.apache.harmony.luni.tests.internal.process.SystemProcessTest#test_interrupt"
+      "org.apache.harmony.luni.tests.java.net.URLClassLoaderTest"
   ]
 },
 {
diff --git a/expectations/virtualdeviceknownfailures.txt b/expectations/virtualdeviceknownfailures.txt
index 66b67e4..b689133 100644
--- a/expectations/virtualdeviceknownfailures.txt
+++ b/expectations/virtualdeviceknownfailures.txt
@@ -1,5 +1,14 @@
 /*
  * List of test cases known to fail on a virtual device.
+ *
+ * Many are because of the network environment used by some or all of the
+ * virtual devices during CTS runs.
+ *
+ * See: https://cloud.google.com/vpc/docs/vpc
+ * As of 2019-05: "VPC networks only support IPv4 unicast traffic. They do not
+ * support broadcast, multicast, or IPv6 traffic within the network: VMs in the
+ * VPC network can only send to IPv4 destinations and only receive traffic from
+ * IPv4 sources.
  */
 [
 {
@@ -15,15 +24,19 @@
 },
 {
   description: "multicast not supported in virtual device testing infra",
-  names: ["org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_InetAddress_IPv4",
-          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4_nullInterface",
-          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_InetAddress_IPv4",
-          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_sendLjava_net_DatagramPacketB_IPv4",
-          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv4"
+  names: ["org.apache.harmony.tests.java.net.MulticastSocketTest",
+          "libcore.java.net.MulticastSocketTest#testGroupReceiveIPv6",
+          "libcore.java.nio.channels.DatagramChannelMulticastTest#test_joinAnySource_IPv4",
+          "libcore.java.nio.channels.DatagramChannelMulticastTest#test_joinAnySource_multicastLoopOption_IPv4"
           ],
   bug: 35922755
 },
 {
+  description: "DNS lookups of {1.2.3.4.} do not reliably fail on GCE networks",
+  names: ["libcore.java.net.InetAddressTest#test_getByName_invalid[1]"],
+  bug: 35922755
+},
+{
   description: "Kernels between 4.4 and 4.9 interpret the backlog parameter differently than we
                 expect, causing this test to fail, and our emulators currently use those kernel
                 versions.  See b/31960002 for a full discussion and references to the upstream
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FilterOutputStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FilterOutputStreamTest.java
index 666955d..2ba710b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FilterOutputStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/FilterOutputStreamTest.java
@@ -17,14 +17,16 @@
 
 package org.apache.harmony.tests.java.io;
 
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
-import junit.framework.TestCase;
-
 public class FilterOutputStreamTest extends TestCase {
 
     private OutputStream os;
@@ -59,6 +61,29 @@
     }
 
     /**
+     * java.io.FilterOutputStream#close()
+     */
+    public void test_doubleClose() throws IOException {
+        OutputStream outputStream = Mockito.mock(OutputStream.class);
+        IOException testException = new IOException("test exception");
+        Mockito.doThrow(testException).when(outputStream).flush();
+        FilterOutputStream filterOutputStream = new FilterOutputStream(outputStream);
+        // FilterOutputStream.close() flushes and closes the underlying stream.
+        try {
+            filterOutputStream.close();
+            fail();
+        } catch (IOException expected) {
+            assertEquals(testException, expected);
+        }
+        Mockito.verify(outputStream, Mockito.times(1)).flush();
+        Mockito.verify(outputStream, Mockito.times(1)).close();
+        // A second close() does not delegate to the already-closed underlying stream again.
+        filterOutputStream.close();
+        Mockito.verify(outputStream, Mockito.times(1)).flush();
+        Mockito.verify(outputStream, Mockito.times(1)).close();
+    }
+
+    /**
      * java.io.FilterOutputStream#flush()
      */
     public void test_flush() throws IOException {
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 eaaae86..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));
     }
 
     /**
@@ -1101,16 +1111,16 @@
         assertTrue(Character.isJavaIdentifierStart(0x01BB));
         assertTrue(Character.isJavaIdentifierStart(0x2F888));
 
-        assertTrue(Character.isJavaIdentifierPart(0x0024));
-        assertTrue(Character.isJavaIdentifierPart(0xFFE6));
+        assertTrue(Character.isJavaIdentifierStart(0x0024));
+        assertTrue(Character.isJavaIdentifierStart(0xFFE6));
 
-        assertTrue(Character.isJavaIdentifierPart(0x005F));
-        assertTrue(Character.isJavaIdentifierPart(0xFF3F));
+        assertTrue(Character.isJavaIdentifierStart(0x005F));
+        assertTrue(Character.isJavaIdentifierStart(0xFF3F));
 
-        assertTrue(Character.isJavaIdentifierPart(0x2160));
-        assertTrue(Character.isJavaIdentifierPart(0x1034A));
+        assertTrue(Character.isJavaIdentifierStart(0x2160));
+        assertTrue(Character.isJavaIdentifierStart(0x1034A));
 
-        assertFalse(Character.isJavaIdentifierPart(0x110000));
+        assertFalse(Character.isJavaIdentifierStart(0x110000));
     }
 
     /**
@@ -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/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/MathTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/MathTest.java
index ed0a094..e3dc9fc 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/MathTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/MathTest.java
@@ -1165,9 +1165,16 @@
             assertEquals("Result should be Math.pow(" + negateDval + "," + 1.0
                     + ")=" + negateDval, negateDval, Math.pow(negateDval, 1.0));
 
+            // The libm implementation of pow() has the following set of special case behaviors:
+            //     If the first argument is 1.0, then the result is 1.0.
+            // i.e. the answer for the following case is not Double.NaN. http://b/11669804
+            {
+                double answer = dval == 1.0d ? 1.0d : Double.NaN;
+                assertEquals("Result should be Math.pow(" + dval + "," + Double.NaN
+                        + ")=" + answer, answer, Math.pow(dval, Double.NaN));
+            }
+
             // If the second argument is NaN, then the result is NaN.
-            assertEquals("Result should be Math.pow(" + dval + "," + Double.NaN
-                    + ")=" + Double.NaN, Double.NaN, Math.pow(dval, Double.NaN));
             assertEquals("Result should be Math.pow(" + negateDval + ","
                     + Double.NaN + ")=" + Double.NaN, Double.NaN, Math.pow(negateDval,
                     Double.NaN));
@@ -1301,21 +1308,23 @@
                 }
             }
 
-            // If the absolute value of the first argument equals 1 and the
-            // second argument is infinite, then the result is NaN.
             if (dval == 1) {
+                // The libm implementation of pow() has the following set of special case behaviors:
+                //     1.0 or -1.0 to the power of positive or negative infinity is 1.0.
+                // i.e. the answer for the following cases is not Double.NaN. http://b/11669804
+
                 assertEquals("Result should be Math.pow(" + dval + ","
-                        + Double.POSITIVE_INFINITY + ")=" + Double.NaN, Double.NaN, Math
+                        + Double.POSITIVE_INFINITY + ")=" + 1.0d, 1.0d, Math
                         .pow(dval, Double.POSITIVE_INFINITY));
                 assertEquals("Result should be Math.pow(" + dval + ","
-                        + Double.NEGATIVE_INFINITY + ")=" + Double.NaN, Double.NaN, Math
+                        + Double.NEGATIVE_INFINITY + ")=" + 1.0d, 1.0d, Math
                         .pow(dval, Double.NEGATIVE_INFINITY));
 
                 assertEquals("Result should be Math.pow(" + negateDval + ","
-                        + Double.POSITIVE_INFINITY + ")=" + Double.NaN, Double.NaN, Math
+                        + Double.POSITIVE_INFINITY + ")=" + 1.0d, 1.0d, Math
                         .pow(negateDval, Double.POSITIVE_INFINITY));
                 assertEquals("Result should be Math.pow(" + negateDval + ","
-                        + Double.NEGATIVE_INFINITY + ")=" + Double.NaN, Double.NaN, Math
+                        + Double.NEGATIVE_INFINITY + ")=" + 1.0d, 1.0d, Math
                         .pow(negateDval, Double.NEGATIVE_INFINITY));
             }
 
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
index 29470d1..8b36163 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
@@ -689,8 +689,12 @@
         format.setPositivePrefix("");
         assertEquals("", format.getPositivePrefix());
 
-        format.setPositivePrefix(null);
-        assertNull(format.getPositivePrefix());
+        try {
+            format.setPositivePrefix(null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+        assertNotNull(format.getPositivePrefix());
     }
 
     public void test_setPositiveSuffix() throws Exception {
@@ -704,8 +708,12 @@
         format.setPositiveSuffix("");
         assertEquals("", format.getPositiveSuffix());
 
-        format.setPositiveSuffix(null);
-        assertNull(format.getPositiveSuffix());
+        try {
+            format.setPositiveSuffix(null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+        assertNotNull(format.getPositiveSuffix());
     }
 
     public void test_setNegativePrefix() throws Exception {
@@ -718,8 +726,12 @@
         format.setNegativePrefix("");
         assertEquals("", format.getNegativePrefix());
 
-        format.setNegativePrefix(null);
-        assertNull(format.getNegativePrefix());
+        try {
+            format.setNegativePrefix(null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+        assertNotNull(format.getNegativePrefix());
     }
 
     public void test_setNegativeSuffix() throws Exception {
@@ -733,8 +745,12 @@
         format.setNegativeSuffix("");
         assertEquals("", format.getNegativeSuffix());
 
-        format.setNegativeSuffix(null);
-        assertNull(format.getNegativeSuffix());
+        try {
+            format.setNegativeSuffix(null);
+            fail();
+        } catch (NullPointerException expected) {
+        }
+        assertNotNull(format.getNegativeSuffix());
     }
 
     public void test_setGroupingUsed() {
@@ -867,13 +883,18 @@
         }
     }
 
+    /**
+     * Test the constructor and applyPattern with various format patterns and what toPattern()
+     * returns. These have changed on Android over time: we are not particularly opinionated about
+     * the output of toPattern() in invalid cases.
+     */
     public void test_applyPattern() {
         DecimalFormat format = new DecimalFormat("#.#");
-        assertEquals("Wrong pattern 1", "#0.#", format.toPattern());
+        assertEquals("Wrong pattern 1", "0.#", format.toPattern());
         format = new DecimalFormat("#.");
-        assertEquals("Wrong pattern 2", "#0.", format.toPattern());
+        assertEquals("Wrong pattern 2", "0.", format.toPattern());
         format = new DecimalFormat("#");
-        assertEquals("Wrong pattern 3", "#", format.toPattern());
+        assertEquals("Wrong pattern 3", "0", format.toPattern());
         format = new DecimalFormat(".#");
         assertEquals("Wrong pattern 4", "#.0", format.toPattern());
 
@@ -906,7 +927,10 @@
         }
     }
 
-    // AndroidOnly: icu supports 2 grouping sizes
+    /**
+     * Test applyPattern() with different grouping sizes and what toPattern() returns.
+     * AndroidOnly: icu supports 2 grouping sizes
+     */
     public void test_applyPattern_icu2GroupingSizes() {
         DecimalFormat decFormat = new DecimalFormat("#.#");
         String[] patterns = {
@@ -917,12 +941,12 @@
         };
 
         String[] expResult = {
-                "#0.##", "#0.######", "#000000.000000",
-                "#.000000", "#000000.######", " #0.###", "$#0.######",
-                "$$#0.######",
-                "%#,###,####", // icu only. icu supports two grouping sizes
+                "0.##", "0.######", "000000.000000",
+                "#.000000", "000000.######", " 0.###", "$0.######",
+                "$$0.######",
+                "%#,###,###0", // icu only. icu supports two grouping sizes
                 "#,##0.00;(#,##0.00)",
-                "#0.##-E"
+                "0.##-E"
                 // icu only. E in the suffix does not need to be quoted.
         };
 
@@ -940,11 +964,11 @@
 
         // case 1: Try to apply correct variants of pattern.
         format.applyLocalizedPattern("#.#");
-        assertEquals("Wrong pattern 1", "#0.#", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 1", "0.#", format.toLocalizedPattern());
         format.applyLocalizedPattern("#.");
-        assertEquals("Wrong pattern 2", "#0.", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 2", "0.", format.toLocalizedPattern());
         format.applyLocalizedPattern("#");
-        assertEquals("Wrong pattern 3", "#", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 3", "0", format.toLocalizedPattern());
         format.applyLocalizedPattern(".#");
         assertEquals("Wrong pattern 4", "#.0", format.toLocalizedPattern());
 
@@ -966,11 +990,11 @@
     public void test_toPattern() {
         DecimalFormat format = new DecimalFormat();
         format.applyPattern("#.#");
-        assertEquals("Wrong pattern 1", "#0.#", format.toPattern());
+        assertEquals("Wrong pattern 1", "0.#", format.toPattern());
         format.applyPattern("#.");
-        assertEquals("Wrong pattern 2", "#0.", format.toPattern());
+        assertEquals("Wrong pattern 2", "0.", format.toPattern());
         format.applyPattern("#");
-        assertEquals("Wrong pattern 3", "#", format.toPattern());
+        assertEquals("Wrong pattern 3", "0", format.toPattern());
         format.applyPattern(".#");
         assertEquals("Wrong pattern 4", "#.0", format.toPattern());
     }
@@ -979,11 +1003,11 @@
         DecimalFormat format = new DecimalFormat();
         format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
         format.applyLocalizedPattern("#.#");
-        assertEquals("Wrong pattern 1", "#0.#", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 1", "0.#", format.toLocalizedPattern());
         format.applyLocalizedPattern("#.");
-        assertEquals("Wrong pattern 2", "#0.", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 2", "0.", format.toLocalizedPattern());
         format.applyLocalizedPattern("#");
-        assertEquals("Wrong pattern 3", "#", format.toLocalizedPattern());
+        assertEquals("Wrong pattern 3", "0", format.toLocalizedPattern());
         format.applyLocalizedPattern(".#");
         assertEquals("Wrong pattern 4", "#.0", format.toLocalizedPattern());
     }
@@ -1136,12 +1160,12 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (0) + "max fractional digits (1) == 1
-        formatTester.format(df, "0.0E0", 0.0);
-        formatTester.format(df, "1.0E0", 1.0);
-        formatTester.format(df, "1.0E1", 12.0);
-        formatTester.format(df, "1.0E2", 123.0);
-        formatTester.format(df, "1.0E3", 1234.0);
-        formatTester.format(df, "1.0E4", 9999.0);
+        formatTester.format(df, "0E0", 0.0);
+        formatTester.format(df, "1E0", 1.0);
+        formatTester.format(df, "1E1", 12.0);
+        formatTester.format(df, "1E2", 123.0);
+        formatTester.format(df, "1E3", 1234.0);
+        formatTester.format(df, "1E4", 9999.0);
 
         df = new DecimalFormat("0.E0", dfs);
         // ["0.E0",isDecimalSeparatorAlwaysShown=true,groupingSize=0,multiplier=1,negativePrefix=-,
@@ -1308,8 +1332,8 @@
         // Because maximum integer digit count is set: The exponent must be a multiple of it (1).
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
-        // Max: "min integer digits" (0) + "max fractional digits (1) == 2
-        formatTester.format(df, "-0.0E0", -0.0);
+        // Max: "min integer digits" (0) + "max fractional digits (1) == 1
+        formatTester.format(df, "-0E0", -0.0);
 
         df = new DecimalFormat("0.#E0", dfs);
         // ["0.#E0",isDecimalSeparatorAlwaysShown=false,groupingSize=0,multiplier=1,
@@ -1425,12 +1449,12 @@
         // Scientific notation => use significant digit logic
         // '@' not present: Significant digits: Min: 1,
         // Max: "min integer digits" (0) + "max fractional digits (1) == 1
-        formatTester.format(df, "0.0E0", 0);
-        formatTester.format(df, "1.0E0", 1);
-        formatTester.format(df, "1.0E1", 12);
-        formatTester.format(df, "1.0E2", 123);
-        formatTester.format(df, "1.0E3", 1234);
-        formatTester.format(df, "1.0E4", 9999);
+        formatTester.format(df, "0E0", 0);
+        formatTester.format(df, "1E0", 1);
+        formatTester.format(df, "1E1", 12);
+        formatTester.format(df, "1E2", 123);
+        formatTester.format(df, "1E3", 1234);
+        formatTester.format(df, "1E4", 9999);
 
         df = new DecimalFormat("0.#E0", dfs);
         // ["0.#E0",isDecimalSeparatorAlwaysShown=false,groupingSize=0,multiplier=1,
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ControlTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ControlTest.java
index d0b236d..717e7d9 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ControlTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ControlTest.java
@@ -27,6 +27,7 @@
 import java.io.Reader;
 import java.io.Writer;
 import java.net.URL;
+import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -45,6 +46,8 @@
  */
 public class ControlTest extends TestCase {
 
+    public static final String RESOURCE_PACKAGE_NAME = "tests.resources.control_test";
+
     /**
      * Control with format:FORMAT_PROPERTIES
      */
@@ -374,13 +377,9 @@
     }
 
     @SuppressWarnings("nls")
-    static File copyFile(final URL src) throws IOException {
+    static File copyFile(final URL src, final String targetDir) throws IOException {
         String tail = src.getFile().split("hyts_resource")[1];
-        String tmpdir = System.getProperty("java.io.tmpdir");
-        if (null == tmpdir) {
-            return null;
-        }
-        String copyName = tmpdir + File.separator + "hyts_resource_copy" + tail;
+        String copyName = targetDir + File.separator + "hyts_resource_copy" + tail;
         File copy = new File(copyName);
         if (copy.exists()) {
             copy.delete();
@@ -454,23 +453,27 @@
     public void test_needsReload_LStringLLocaleLStringLClassLoaderResourceBundleJ()
             throws Exception {
         String className = "tests.support.Support_TestResource";
-        String propertiesName = Support_Resources.RESOURCE_PACKAGE_NAME
-                + ".hyts_resource";
+        String propertiesName = RESOURCE_PACKAGE_NAME + ".hyts_resource";
         String propertiesNameCopy = "hyts_resource_copy";
         String CLASS = "java.class";
         String PROPERTIES = "java.properties";
         Locale frFR = new Locale("fr", "FR");
-        ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
-        ClassLoader URLLoader = systemLoader;
+        ClassLoader testCodeClassLoader = this.getClass().getClassLoader();
         ResourceBundle bundle = null;
         long time = 0L;
-        final URL srcFile = URLLoader.getResource(control.toResourceName(
+        final URL srcFile = testCodeClassLoader.getResource(control.toResourceName(
                 control.toBundleName(propertiesName, frFR), "properties"));
         assertNotNull(srcFile);
-        final File copyFile = copyFile(srcFile);
+
+        String tmpdir = System.getProperty("java.io.tmpdir");
+        assertNotNull(tmpdir);
+        final File copyFile = copyFile(srcFile, tmpdir);
+        ClassLoader URLLoader = new URLClassLoader(
+                new URL[] { new File(tmpdir).toURL() },
+                testCodeClassLoader);
 
         // 1. format = "java.properties"
-        if (null != URLLoader.getResourceAsStream(copyFile.toURL().toString())) {
+        if (null != URLLoader.getResourceAsStream(copyFile.getName())) {
             Thread.sleep(1000);
             bundle = control.newBundle(propertiesNameCopy, frFR, PROPERTIES,
                     URLLoader, false);
@@ -492,15 +495,10 @@
                     PROPERTIES, URLLoader, bundle, 2006L));
             // other loader
             assertFalse(control.needsReload(propertiesNameCopy, frFR,
-                    PROPERTIES, systemLoader, bundle, time));
+                    PROPERTIES, testCodeClassLoader, bundle, time));
             // other bundle
             ResourceBundle otherBundle = control.newBundle(propertiesName,
-                    Locale.ROOT, PROPERTIES, systemLoader, false);
-            assertEquals("parent", otherBundle.getString("property"));
-            assertTrue(control.needsReload(propertiesNameCopy, frFR,
-                    PROPERTIES, URLLoader, otherBundle, time));
-            otherBundle = control.newBundle(propertiesName, Locale.ROOT,
-                    PROPERTIES, URLLoader, false);
+                    Locale.ROOT, PROPERTIES, URLLoader, false);
             assertEquals("resource", otherBundle.getString("property"));
             assertTrue(control.needsReload(propertiesNameCopy, frFR,
                     PROPERTIES, URLLoader, otherBundle, time));
@@ -508,16 +506,14 @@
             assertFalse(control.needsReload(propertiesNameCopy, frFR,
                     PROPERTIES, URLLoader, bundle, System.currentTimeMillis()));
         } else {
-            System.err
-                    .println("Can not find the test file, some code of this test 'test_needsReload_LStringLLocaleLStringLClassLoaderResourceBundleJ' did not run.");
-
+            fail("Can not find the test file:" + copyFile);
         }
 
         // 2. format = "java.class"
-        bundle = control.newBundle(className, frFR, CLASS, systemLoader, false);
+        bundle = control.newBundle(className, frFR, CLASS, testCodeClassLoader, false);
         time = System.currentTimeMillis();
         assertEquals("frFRValue3", bundle.getString("parent3"));
-        assertFalse(control.needsReload(className, frFR, CLASS, systemLoader,
+        assertFalse(control.needsReload(className, frFR, CLASS, testCodeClassLoader,
                 bundle, time));
         // exceptions
         control.needsReload(propertiesName, frFR, PROPERTIES, URLLoader,
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
index 4a5c803..85899f3 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ScannerTest.java
@@ -5694,13 +5694,15 @@
     }
 
     // http://code.google.com/p/android/issues/detail?id=57050
-    public void testPerformance() throws Exception {
+    // Disable this test since it causes oom failures in follow on
+    // tests. See b/160171148 for details.
+    public void disableTestPerformance() throws Exception {
         int count = 100000;
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         BufferedWriter out = new BufferedWriter(new OutputStreamWriter(baos));
         for (int i = 0; i < count; ++i) {
-            out.write(Integer.toString(123) + " ");
+            out.write("123 ");
         }
         out.close();
 
@@ -5709,7 +5711,16 @@
 
         Scanner s = new Scanner(new BufferedReader(new InputStreamReader(bais)));
         for (int i = 0; i < count; ++i) {
-            if (s.nextInt() != 123) {
+            final int value;
+            try {
+                value = s.nextInt();
+            } catch (RuntimeException e) {
+                String msg = String.format(Locale.US,
+                        "Failed to parse float on item %d/%d with locale %s: %s",
+                        (i+1), count, s.locale(), s);
+                throw new RuntimeException(msg, e);
+            }
+            if (value != 123) {
                 fail();
             }
         }
@@ -5717,9 +5728,19 @@
         bais.reset();
         s = new Scanner(new BufferedReader(new InputStreamReader(bais)));
         for (int i = 0; i < count; ++i) {
-            if (s.nextFloat() != 123.0) {
+            final float value;
+            try {
+                value = s.nextFloat();
+            } catch (RuntimeException e) {
+                String msg = String.format(Locale.US,
+                        "Failed to parse float on item %d/%d with locale %s: %s",
+                        (i+1), count, s.locale(), s);
+                throw new RuntimeException(msg, e);
+            }
+            if (value != 123.0) {
                 fail();
             }
         }
+        System.gc();
     }
 }
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
index 74c3a7f..d820689 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HandshakeCompletedEventTest.java
@@ -431,8 +431,6 @@
                     assertEquals(i, j);
                 }
 
-                istream.close();
-
                 OutputStream ostream = clientSocket.getOutputStream();
 
                 for (int i = 0; i < 256; i++) {
@@ -503,7 +501,6 @@
                 }
 
                 ostream.flush();
-                ostream.close();
 
                 InputStream istream = socket.getInputStream();
 
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
index 45e9d40..f688b9b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLContextSpiTest.java
@@ -15,9 +15,16 @@
  */
 package org.apache.harmony.tests.javax.net.ssl;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContextSpi;
 import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
 import javax.net.ssl.SSLServerSocketFactory;
 import javax.net.ssl.SSLSessionContext;
 import javax.net.ssl.SSLSocketFactory;
@@ -28,18 +35,20 @@
 
 import java.security.KeyStore;
 import java.security.SecureRandom;
-import java.security.Security;
-
-import junit.framework.TestCase;
 
 import org.apache.harmony.xnet.tests.support.SSLContextSpiImpl;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class SSLContextSpiTest extends TestCase {
+@RunWith(JUnit4.class)
+public class SSLContextSpiTest {
 
     /**
      * javax.net.ssl.SSLContextSpi#SSLContextSpi()
      */
-    public void test_Constructor() {
+    @Test
+    public void constructor() {
         try {
             SSLContextSpiImpl ssl = new SSLContextSpiImpl();
             assertTrue(ssl instanceof SSLContextSpi);
@@ -52,7 +61,8 @@
      * javax.net.ssl.SSLContextSpi#engineCreateSSLEngine()
      * Verify exception when SSLContextSpi object wasn't initialiazed.
      */
-    public void test_engineCreateSSLEngine_01() {
+    @Test
+    public void engineCreateSSLEngine_01() {
         SSLContextSpiImpl ssl = new SSLContextSpiImpl();
         try {
             SSLEngine sleng = ssl.engineCreateSSLEngine();
@@ -70,7 +80,8 @@
      * javax.net.ssl.SSLContextSpi#engineCreateSSLEngine(String host, int port)
      * Verify exception when SSLContextSpi object wasn't initialiazed.
      */
-    public void test_engineCreateSSLEngine_02() {
+    @Test
+    public void engineCreateSSLEngine_02() {
         int[] invalid_port = {Integer.MIN_VALUE, -65535, -1, 65536, Integer.MAX_VALUE};
         SSLContextSpiImpl ssl = new SSLContextSpiImpl();
         try {
@@ -101,7 +112,8 @@
      * SSLContextSpi#engineGetSocketFactory()
      * Verify exception when SSLContextSpi object wasn't initialiazed.
      */
-    public void test_commonTest_01() {
+    @Test
+    public void commonTest_01() {
         SSLContextSpiImpl ssl = new SSLContextSpiImpl();
 
         try {
@@ -152,34 +164,19 @@
     /**
      * SSLContextSpi#engineInit(KeyManager[] km, TrustManager[] tm, SecureRandom sr)
      */
-    public void test_engineInit() {
+    @Test
+    public void engineInit() throws Exception {
         SSLContextSpiImpl ssl = new SSLContextSpiImpl();
-        String defaultAlgorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
+        KeyManager[] km = getKeyManagers();
+        TrustManager[] tm = getTrustManagers();
+        SecureRandom sr = getSecureRandom();
+        ssl.engineInit(km, tm, sr);
+
         try {
-            KeyManagerFactory kmf = KeyManagerFactory.getInstance(defaultAlgorithm);
-            char[] pass = "password".toCharArray();
-            kmf.init(null, pass);
-            KeyManager[] km = kmf.getKeyManagers();
-            defaultAlgorithm = Security.getProperty("ssl.TrustManagerFactory.algorithm");
-            TrustManagerFactory trustMF = TrustManagerFactory.getInstance(defaultAlgorithm);
-            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
-            ks.load(null, null);
-            trustMF.init(ks);
-            TrustManager[] tm = trustMF.getTrustManagers();
-            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
-            try {
-                ssl.engineInit(km, tm, sr);
-            } catch (KeyManagementException kme) {
-                fail(kme + " was throw for engineInit method");
-            }
-            try {
-                ssl.engineInit(km, tm, null);
-                fail("KeyManagementException wasn't thrown");
-            } catch (KeyManagementException kme) {
-                //expected
-            }
-        } catch (Exception ex) {
-            fail(ex + " unexpected exception");
+            ssl.engineInit(km, tm, null);
+            fail("KeyManagementException wasn't thrown");
+        } catch (KeyManagementException kme) {
+            //expected
         }
     }
 
@@ -191,39 +188,77 @@
      * SSLContextSpi#engineGetServerSocketFactory()
      * SSLContextSpi#engineGetSocketFactory()
      */
-    public void test_commonTest_02() {
+    @Test
+    public void commonTest_02() throws Exception {
         SSLContextSpiImpl ssl = new SSLContextSpiImpl();
-        String defaultAlgorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
-        try {
-            KeyManagerFactory kmf = KeyManagerFactory.getInstance(defaultAlgorithm);
-            char[] pass = "password".toCharArray();
-            kmf.init(null, pass);
-            KeyManager[] km = kmf.getKeyManagers();
-            defaultAlgorithm = Security.getProperty("ssl.TrustManagerFactory.algorithm");
-            TrustManagerFactory trustMF = TrustManagerFactory.getInstance(defaultAlgorithm);
-            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
-            ks.load(null, null);
-            trustMF.init(ks);
-            TrustManager[] tm = trustMF.getTrustManagers();
-            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
-            ssl.engineInit(km, tm, sr);
-        } catch (Exception ex) {
-            fail(ex + " unexpected exception");
-        }
+        ssl.engineInit(getKeyManagers(), getTrustManagers(), getSecureRandom());
 
-        try {
-            assertNotNull("Subtest_01: Object is NULL", ssl.engineCreateSSLEngine());
-            SSLEngine sleng = ssl.engineCreateSSLEngine("localhost", 1080);
-            assertNotNull("Subtest_02: Object is NULL", sleng);
-            assertEquals(sleng.getPeerPort(), 1080);
-            assertEquals(sleng.getPeerHost(), "localhost");
-            assertNull("Subtest_03: Object not NULL", ssl.engineGetClientSessionContext());
-            assertNull("Subtest_04: Object not NULL", ssl.engineGetServerSessionContext());
-            assertNull("Subtest_05: Object not NULL", ssl.engineGetServerSocketFactory());
-            assertNull("Subtest_06: Object not NULL", ssl.engineGetSocketFactory());
-        } catch (Exception e) {
-            fail("Unexpected exception " + e);
+        assertNotNull("Subtest_01: Object is NULL", ssl.engineCreateSSLEngine());
+        SSLEngine sleng = ssl.engineCreateSSLEngine("localhost", 1080);
+        assertNotNull("Subtest_02: Object is NULL", sleng);
+        assertEquals(sleng.getPeerPort(), 1080);
+        assertEquals(sleng.getPeerHost(), "localhost");
+        assertNull("Subtest_03: Object not NULL", ssl.engineGetClientSessionContext());
+        assertNull("Subtest_04: Object not NULL", ssl.engineGetServerSessionContext());
+        assertNull("Subtest_05: Object not NULL", ssl.engineGetServerSocketFactory());
+        assertNull("Subtest_06: Object not NULL", ssl.engineGetSocketFactory());
+    }
+
+    private static class SpiWithSocketFactory extends SSLContextSpiImpl {
+        @Override
+        public SSLSocketFactory engineGetSocketFactory() {
+            super.engineGetSocketFactory();
+            return (SSLSocketFactory) SSLSocketFactory.getDefault();
         }
     }
 
+    /**
+     * Tests the default implementations of SSLContextSpi.engineGetDefaultSSLParameters()
+     * and SSLContextSpi.engineGetSupportedSSLParameters().  Requires a subclass which
+     * returns non-null from engineGetSocketFactory() for the base class to work.
+     *
+     * Verifies the returned SSLParameters for consistency.
+     */
+    @Test
+    public void getSslParameters() throws Exception {
+        SpiWithSocketFactory spi = new SpiWithSocketFactory();
+        spi.engineInit(getKeyManagers(), getTrustManagers(), getSecureRandom());
+
+        SSLParameters defaultParams = spi.engineGetDefaultSSLParameters();
+        assertNotNull(defaultParams);
+        String[] protocols = defaultParams.getProtocols();
+        assertNotNull(protocols);
+        assertTrue(protocols.length > 0);
+        String[] cipherSuites = defaultParams.getCipherSuites();
+        assertNotNull(cipherSuites);
+        assertTrue(cipherSuites.length > 0);
+
+        SSLParameters supportedParams = spi.engineGetSupportedSSLParameters();
+        assertNotNull(supportedParams);
+        protocols = supportedParams.getProtocols();
+        assertNotNull(protocols);
+        assertTrue(protocols.length > 0);
+        cipherSuites = supportedParams.getCipherSuites();
+        assertNotNull(cipherSuites);
+        assertTrue(cipherSuites.length > 0);
+    }
+
+    private SecureRandom getSecureRandom() throws Exception {
+        return SecureRandom.getInstance("SHA1PRNG");
+    }
+
+    private TrustManager[] getTrustManagers() throws Exception {
+        TrustManagerFactory tmf = TrustManagerFactory
+            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+        tmf.init(ks);
+        return tmf.getTrustManagers();
+    }
+
+    private KeyManager[] getKeyManagers() throws Exception {
+        KeyManagerFactory kmf = KeyManagerFactory
+            .getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(null, "password".toCharArray());
+        return kmf.getKeyManagers();
+    }
 }
diff --git a/harmony-tests/src/test/resources/tests/resources/control_test/hyts_resource.properties b/harmony-tests/src/test/resources/tests/resources/control_test/hyts_resource.properties
new file mode 100644
index 0000000..eae054e
--- /dev/null
+++ b/harmony-tests/src/test/resources/tests/resources/control_test/hyts_resource.properties
@@ -0,0 +1,3 @@
+property=resource
+propertyInURLParent=valueInURLParent
+ 
\ No newline at end of file
diff --git a/harmony-tests/src/test/resources/tests/resources/control_test/hyts_resource_fr_FR.properties b/harmony-tests/src/test/resources/tests/resources/control_test/hyts_resource_fr_FR.properties
new file mode 100644
index 0000000..0ac2c73
--- /dev/null
+++ b/harmony-tests/src/test/resources/tests/resources/control_test/hyts_resource_fr_FR.properties
@@ -0,0 +1,3 @@
+property=fr_FR_resource
+propertyInFRFR=valueInFRFR
+ 
\ No newline at end of file
diff --git a/json/src/main/java/org/json/JSONArray.java b/json/src/main/java/org/json/JSONArray.java
index 5e758d7..df0b243 100644
--- a/json/src/main/java/org/json/JSONArray.java
+++ b/json/src/main/java/org/json/JSONArray.java
@@ -16,7 +16,7 @@
 
 package org.json;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Collection;
diff --git a/json/src/main/java/org/json/JSONObject.java b/json/src/main/java/org/json/JSONObject.java
index 0565b25..40d15bb 100644
--- a/json/src/main/java/org/json/JSONObject.java
+++ b/json/src/main/java/org/json/JSONObject.java
@@ -16,7 +16,8 @@
 
 package org.json;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
diff --git a/json/src/main/java/org/json/JSONStringer.java b/json/src/main/java/org/json/JSONStringer.java
index 3d1738c..ef1b47c 100644
--- a/json/src/main/java/org/json/JSONStringer.java
+++ b/json/src/main/java/org/json/JSONStringer.java
@@ -16,7 +16,7 @@
 
 package org.json;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
diff --git a/json/src/main/java/org/json/JSONTokener.java b/json/src/main/java/org/json/JSONTokener.java
index 55667b0..6266860 100644
--- a/json/src/main/java/org/json/JSONTokener.java
+++ b/json/src/main/java/org/json/JSONTokener.java
@@ -16,7 +16,7 @@
 
 package org.json;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 // Note: this class was written without inspecting the non-free org.json sourcecode.
 
diff --git a/json/src/main/java/org/json/TEST_MAPPING b/json/src/main/java/org/json/TEST_MAPPING
new file mode 100644
index 0000000..22c9a26
--- /dev/null
+++ b/json/src/main/java/org/json/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.org.json"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/libart/src/main/java/dalvik/system/ClassExt.java b/libart/src/main/java/dalvik/system/ClassExt.java
index 9180d96..e523035 100644
--- a/libart/src/main/java/dalvik/system/ClassExt.java
+++ b/libart/src/main/java/dalvik/system/ClassExt.java
@@ -27,6 +27,28 @@
  */
 public final class ClassExt {
     /**
+     * A Pointer-sized-array of instance jfieldIDs in the same order as the ifields_ array.
+     * The jfieldID is associated with the ArtField at the corresonding index in the ifields_ array.
+     */
+    private Object instanceJfieldIDs;
+
+    /**
+     * A Pointer-sized-array of jmethodIDS in the same order as the methods_
+     * array. The jmethodID is associated with the ArtField at the corresonding
+     * index in the methods_ array.
+     */
+    private Object jmethodIDs;
+
+    /**
+     * If the class has undergone structural redefinition, the now obsolete class object.
+     *
+     * Needed to ensure that the class isn't unloaded before its jit code is. Normally this is
+     * handled by the classloader but since the class is now obsolete it's no longer held live
+     * there and instead we must do so manually. This class should not be used for anything.
+     */
+    private Class<?> obsoleteClass;
+
+    /**
      * An array of all obsolete DexCache objects that are needed for obsolete methods.
      *
      * These entries are associated with the obsolete ArtMethod pointers at the same indexes in the
@@ -63,6 +85,12 @@
     private Object originalDexFile;
 
     /**
+     * A Pointer-sized-array of static jfieldIDs in the same order as the sfields_ array.
+     * The jfieldID is associated with the ArtField at the corresonding index in the sfields_ array.
+     */
+    private Object staticJfieldIDs;
+
+    /**
      * If class verify fails, we must return same error on subsequent tries. We may store either
      * the class of the error, or an actual instance of Throwable here.
      *
@@ -95,6 +123,7 @@
      */
     private int preRedefineClassDefIndex;
 
+
     /**
     * Private constructor.
     *
diff --git a/libart/src/main/java/dalvik/system/TEST_MAPPING b/libart/src/main/java/dalvik/system/TEST_MAPPING
new file mode 100644
index 0000000..f9e6606
--- /dev/null
+++ b/libart/src/main/java/dalvik/system/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/dalvik/src/main/java/dalvik/system"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 7d70680..321f4e3 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -16,14 +16,21 @@
 
 package dalvik.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.annotation.optimization.FastNative;
+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.concurrent.atomic.AtomicInteger;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
 /**
  * Provides an interface to VM-global, Dalvik-specific features.
  * An application cannot create its own Runtime instance, and must obtain
@@ -53,9 +60,34 @@
         ABI_TO_INSTRUCTION_SET_MAP.put("x86", "x86");
         ABI_TO_INSTRUCTION_SET_MAP.put("x86_64", "x86_64");
         ABI_TO_INSTRUCTION_SET_MAP.put("arm64-v8a", "arm64");
+        ABI_TO_INSTRUCTION_SET_MAP.put("arm64-v8a-hwasan", "arm64");
     }
 
     /**
+     * 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.
+
+    /**
+     * Gating access to greylist-max-p APIs.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = VersionCodes.P)
+    private static final long HIDE_MAXTARGETSDK_P_HIDDEN_APIS = 149997251; // This is a bug id.
+
+    /**
+     * Gating access to greylist-max-q APIs.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = VersionCodes.Q)
+    private static final long HIDE_MAXTARGETSDK_Q_HIDDEN_APIS = 149994052; // This is a bug id.
+
+    /**
      * Interface for logging hidden API usage events.
      */
     @libcore.api.CorePlatformApi
@@ -148,6 +180,8 @@
     // Allocations since last call to native layer. See notifyNativeAllocation().
     private final AtomicInteger allocationCount = new AtomicInteger(0);
 
+    private long[] disabledCompatChanges = new long[0];
+
     /**
      * Prevents this class from being instantiated.
      */
@@ -272,12 +306,26 @@
      * app starts to run, because it may change the VM's behavior in
      * dangerous ways. Defaults to {@link #SDK_VERSION_CUR_DEVELOPMENT}.
      */
+    @UnsupportedAppUsage(maxTargetSdk=0, publicAlternatives="Use the {@code targetSdkVersion}"
+        +" attribute in the {@code uses-sdk} manifest tag instead.")
     @libcore.api.CorePlatformApi
     public synchronized void setTargetSdkVersion(int targetSdkVersion) {
         this.targetSdkVersion = targetSdkVersion;
         setTargetSdkVersionNative(this.targetSdkVersion);
     }
 
+
+    /**
+     * Sets the disabled compat changes. Should only be called before the
+     * app starts to run, because it may change the VM's behavior in
+     * dangerous ways. Defaults to empty.
+     */
+    @libcore.api.CorePlatformApi
+    public synchronized void setDisabledCompatChanges(long[] disabledCompatChanges) {
+        this.disabledCompatChanges = disabledCompatChanges;
+        setDisabledCompatChangesNative(this.disabledCompatChanges);
+    }
+
     /**
      * Gets the target SDK version. See {@link #setTargetSdkVersion} for
      * special values.
@@ -288,6 +336,7 @@
     }
 
     private native void setTargetSdkVersionNative(int targetSdkVersion);
+    private native void setDisabledCompatChangesNative(long[] disabledCompatChanges);
 
     /**
      * This method exists for binary compatibility.  It was part of a
@@ -441,12 +490,6 @@
     public native void clampGrowthLimit();
 
     /**
-     * Returns true if either a Java debugger or native debugger is active.
-     */
-    @FastNative
-    public native boolean isDebuggerActive();
-
-    /**
      * Returns true if native debugging is on.
      */
     @libcore.api.CorePlatformApi
@@ -631,6 +674,16 @@
     }
 
     /**
+     * Prevent initialization of the caller's class if they are calling
+     * from their clinit method. This works because calling a JNI method
+     * from clinit causes the transactional runtime to abort the current
+     * transaction.
+     * @hide
+     */
+    @CriticalNative
+    public static native void doNotInitializeInAot();
+
+    /**
      * Return false if the boot class path for the given instruction
      * set mapped from disk storage, versus being interpretted from
      * dirty pages in memory.
@@ -649,6 +702,20 @@
     public static native boolean hasBootImageSpaces();
 
     /**
+     * Used to notify the runtime that boot completed.
+     */
+    @libcore.api.CorePlatformApi
+    public static native void bootCompleted();
+
+    /**
+     * Used to notify the runtime to reset Jit counters. This is done for the boot image
+     * profiling configuration to avoid samples during class preloading. This helps avoid
+     * the regression from disabling class profiling.
+     */
+    @libcore.api.CorePlatformApi
+    public static native void resetJitCounters();
+
+    /**
      * Returns the instruction set of the current runtime.
      */
     @UnsupportedAppUsage
@@ -702,4 +769,15 @@
      */
     @libcore.api.CorePlatformApi
     public static native void setProcessDataDirectory(String dataDir);
+
+    /**
+     * Returns whether {@code encodedClassLoaderContext} is a valid encoded class loader context.
+     * A class loader context is an internal opaque format used by the runtime to encode the
+     * class loader hierarchy (including each ClassLoader's classpath) used to load a dex file.
+     *
+     * @return True if encodedClassLoaderContext is a non-null valid encoded class loader context.
+     *   Throws NullPointerException if encodedClassLoaderContext is null.
+     */
+    @libcore.api.CorePlatformApi
+    public static native boolean isValidClassLoaderContext(String encodedClassLoaderContext);
 }
diff --git a/libart/src/main/java/dalvik/system/VMStack.java b/libart/src/main/java/dalvik/system/VMStack.java
index d84fef6..89ce215 100644
--- a/libart/src/main/java/dalvik/system/VMStack.java
+++ b/libart/src/main/java/dalvik/system/VMStack.java
@@ -16,7 +16,8 @@
 
 package dalvik.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import dalvik.annotation.optimization.FastNative;
 
 /**
diff --git a/libart/src/main/java/java/lang/CaseMapper.java b/libart/src/main/java/java/lang/CaseMapper.java
index 66d5030..04eef09 100644
--- a/libart/src/main/java/java/lang/CaseMapper.java
+++ b/libart/src/main/java/java/lang/CaseMapper.java
@@ -17,8 +17,8 @@
 package java.lang;
 
 import android.icu.text.Transliterator;
+import com.android.icu.util.CaseMapperNative;
 import java.util.Locale;
-import libcore.icu.ICU;
 
 /**
  * Performs case operations as described by http://unicode.org/reports/tr21/tr21-5.html.
@@ -47,7 +47,7 @@
         // Note that Greek isn't a particularly hard case for toLowerCase, only toUpperCase.
         String languageCode = locale.getLanguage();
         if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
-            return ICU.toLowerCase(s, locale);
+            return CaseMapperNative.toLowerCase(s, locale);
         }
 
         char[] newValue = null;
@@ -56,7 +56,7 @@
             char newCh;
             if (ch == LATIN_CAPITAL_I_WITH_DOT || Character.isHighSurrogate(ch)) {
                 // Punt these hard cases.
-                return ICU.toLowerCase(s, locale);
+                return CaseMapperNative.toLowerCase(s, locale);
             } else if (ch == GREEK_CAPITAL_SIGMA && isFinalSigma(s, i)) {
                 newCh = GREEK_SMALL_FINAL_SIGMA;
             } else {
@@ -146,7 +146,7 @@
     public static String toUpperCase(Locale locale, String s, int count) {
         String languageCode = locale.getLanguage();
         if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
-            return ICU.toUpperCase(s, locale);
+            return CaseMapperNative.toUpperCase(s, locale);
         }
         if (languageCode.equals("el")) {
             return EL_UPPER.get().transliterate(s);
@@ -157,7 +157,7 @@
         for (int o = 0; o < count; o++) {
             char ch = s.charAt(o);
             if (Character.isHighSurrogate(ch)) {
-                return ICU.toUpperCase(s, locale);
+                return CaseMapperNative.toUpperCase(s, locale);
             }
             int index = upperIndex(ch);
             if (index == -1) {
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index 7d0eca2..6e05cea 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -16,19 +16,21 @@
 
 package java.lang;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.Os;
 import android.system.OsConstants;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VMRuntime;
+
 import java.lang.ref.FinalizerReference;
 import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
 import libcore.util.EmptyArray;
 
+import dalvik.system.VMRuntime;
+import dalvik.system.VMDebug;
+
 /**
  * Calls Object.finalize() on objects in the finalizer reference queue. The VM
  * will abort if any finalize() call takes more than the maximum finalize time
@@ -308,7 +310,7 @@
 
         private boolean needToWork = true;  // Only accessed in synchronized methods.
 
-        private long finalizerTimeoutMs = 0;  // Lazily initialized.
+        private long finalizerTimeoutNs = 0;  // Lazily initialized.
 
         FinalizerWatchdogDaemon() {
             super("FinalizerWatchdogDaemon");
@@ -321,7 +323,7 @@
                     continue;
                 }
                 final Object finalizing = waitForFinalization();
-                if (finalizing != null && !VMRuntime.getRuntime().isDebuggerActive()) {
+                if (finalizing != null && !VMDebug.isDebuggerConnected()) {
                     finalizerTimedOut(finalizing);
                     break;
                 }
@@ -368,17 +370,22 @@
         }
 
         /**
-         * Sleep for the given number of milliseconds.
+         * Sleep for the given number of nanoseconds, or slightly longer.
          * @return false if we were interrupted.
          */
-        private boolean sleepForMillis(long durationMillis) {
-            long startMillis = System.currentTimeMillis();
+        private boolean sleepForNanos(long durationNanos) {
+            // It's important to base this on nanoTime(), not currentTimeMillis(), since
+            // the former stops counting when the processor isn't running.
+            long startNanos = System.nanoTime();
             while (true) {
-                long elapsedMillis = System.currentTimeMillis() - startMillis;
-                long sleepMillis = durationMillis - elapsedMillis;
-                if (sleepMillis <= 0) {
+                long elapsedNanos = System.nanoTime() - startNanos;
+                long sleepNanos = durationNanos - elapsedNanos;
+                if (sleepNanos <= 0) {
                     return true;
                 }
+                // Ensure the nano time is always rounded up to the next whole millisecond,
+                // ensuring the delay is >= the requested delay.
+                long sleepMillis = (sleepNanos + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI;
                 try {
                     Thread.sleep(sleepMillis);
                 } catch (InterruptedException e) {
@@ -401,14 +408,15 @@
          * null.  Only called from a single thread.
          */
         private Object waitForFinalization() {
-            if (finalizerTimeoutMs == 0) {
-                finalizerTimeoutMs = VMRuntime.getRuntime().getFinalizerTimeoutMs();
+            if (finalizerTimeoutNs == 0) {
+                finalizerTimeoutNs =
+                        NANOS_PER_MILLI * VMRuntime.getRuntime().getFinalizerTimeoutMs();
                 // Temporary app backward compatibility. Remove eventually.
-                MAX_FINALIZE_NANOS = NANOS_PER_MILLI * finalizerTimeoutMs;
+                MAX_FINALIZE_NANOS = finalizerTimeoutNs;
             }
             long startCount = FinalizerDaemon.INSTANCE.progressCounter.get();
             // Avoid remembering object being finalized, so as not to keep it alive.
-            if (!sleepForMillis(finalizerTimeoutMs)) {
+            if (!sleepForNanos(finalizerTimeoutNs)) {
                 // Don't report possibly spurious timeout if we are interrupted.
                 return null;
             }
@@ -429,7 +437,7 @@
                 // just finished as we were timing out, in which case we may get null or a later
                 // one.  In this last case, we are very likely to discard it below.
                 Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject;
-                sleepForMillis(500);
+                sleepForNanos(500 * NANOS_PER_MILLI);
                 // Recheck to make it even less likely we report the wrong finalizing object in
                 // the case which a very slow finalization just finished as we were timing out.
                 if (getNeedToWork()
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index 7c4a6ed..e35a69d 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -32,13 +32,16 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import dalvik.annotation.optimization.FastNative;
 
 /**
  * A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile.
  */
 final class DexCache {
+    /** The classloader this dex cache is for. */
+    private ClassLoader classLoader;
+
     /** The location of the associated dex file. */
     private String location;
 
@@ -125,4 +128,3 @@
     // Only created by the VM.
     private DexCache() {}
 }
-
diff --git a/libart/src/main/java/java/lang/TEST_MAPPING b/libart/src/main/java/java/lang/TEST_MAPPING
new file mode 100644
index 0000000..06575f3
--- /dev/null
+++ b/libart/src/main/java/java/lang/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "tests.java.lang"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.lang"
+        },
+        {
+          "include-filter": "libcore.java.lang"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/libart/src/main/java/java/lang/invoke/TEST_MAPPING b/libart/src/main/java/java/lang/invoke/TEST_MAPPING
new file mode 100644
index 0000000..2b6135d
--- /dev/null
+++ b/libart/src/main/java/java/lang/invoke/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.lang.invoke"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "org.openjdk.tests.java.lang.invoke"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/android/compat/Compatibility.java b/luni/src/main/java/android/compat/Compatibility.java
new file mode 100644
index 0000000..9b4b1af
--- /dev/null
+++ b/luni/src/main/java/android/compat/Compatibility.java
@@ -0,0 +1,236 @@
+/*
+ * 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 android.compat;
+
+import android.compat.annotation.ChangeId;
+
+import libcore.api.CorePlatformApi;
+import libcore.api.IntraCoreApi;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Internal APIs for logging and gating compatibility changes.
+ *
+ * @see ChangeId
+ *
+ * @hide
+ */
+@CorePlatformApi
+@IntraCoreApi
+public final class Compatibility {
+
+    private Compatibility() {}
+
+    /**
+     * Reports that a compatibility change is affecting the current process now.
+     *
+     * <p>Calls to this method from a non-app process are ignored. This allows code implementing
+     * APIs that are used by apps and by other code (e.g. the system server) to report changes
+     * regardless of the process it's running in. When called in a non-app process, this method is
+     * a no-op.
+     *
+     * <p>Note: for changes that are gated using {@link #isChangeEnabled(long)}, you do not need to
+     * call this API directly. The change will be reported for you in the case that
+     * {@link #isChangeEnabled(long)} returns {@code true}.
+     *
+     * @param changeId The ID of the compatibility change taking effect.
+     */
+    @CorePlatformApi
+    @IntraCoreApi
+    public static void reportChange(@ChangeId long changeId) {
+        sCallbacks.reportChange(changeId);
+    }
+
+    /**
+     * Query if a given compatibility change is enabled for the current process. This method should
+     * only be called by code running inside a process of the affected app.
+     *
+     * <p>If this method returns {@code true}, the calling code should implement the compatibility
+     * change, resulting in differing behaviour compared to earlier releases. If this method returns
+     * {@code false}, the calling code should behave as it did in earlier releases.
+     *
+     * <p>When this method returns {@code true}, it will also report the change as
+     * {@link #reportChange(long)} would, so there is no need to call that method directly.
+     *
+     * @param changeId The ID of the compatibility change in question.
+     * @return {@code true} if the change is enabled for the current app.
+     */
+    @CorePlatformApi
+    @IntraCoreApi
+    public static boolean isChangeEnabled(@ChangeId long changeId) {
+        return sCallbacks.isChangeEnabled(changeId);
+    }
+
+    private volatile static Callbacks sCallbacks = new Callbacks();
+
+    @CorePlatformApi
+    public static void setCallbacks(Callbacks callbacks) {
+        sCallbacks = Objects.requireNonNull(callbacks);
+    }
+
+    @CorePlatformApi
+    public static void setOverrides(ChangeConfig overrides) {
+        // Setting overrides twice in a row does not need to be supported because
+        // this method is only for enabling/disabling changes for the duration of
+        // a single test.
+        // In production, the app is restarted when changes get enabled or disabled,
+        // and the ChangeConfig is then set exactly once on that app process.
+        if (sCallbacks instanceof OverrideCallbacks) {
+            throw new IllegalStateException("setOverrides has already been called!");
+        }
+        sCallbacks = new OverrideCallbacks(sCallbacks, overrides);
+    }
+
+    @CorePlatformApi
+    public static void clearOverrides() {
+        if (!(sCallbacks instanceof OverrideCallbacks)) {
+            throw new IllegalStateException("No overrides set");
+        }
+        sCallbacks = ((OverrideCallbacks) sCallbacks).delegate;
+    }
+
+    /**
+     * Base class for compatibility API implementations. The default implementation logs a warning
+     * to logcat.
+     *
+     * This is provided as a class rather than an interface to allow new methods to be added without
+     * breaking @CorePlatformApi binary compatibility.
+     */
+    @CorePlatformApi
+    public static class Callbacks {
+        @CorePlatformApi
+        protected Callbacks() {
+        }
+        @CorePlatformApi
+        protected void reportChange(long changeId) {
+            // Do not use String.format here (b/160912695)
+            System.logW("No Compatibility callbacks set! Reporting change " + changeId);
+        }
+        @CorePlatformApi
+        protected boolean isChangeEnabled(long changeId) {
+            // Do not use String.format here (b/160912695)
+            System.logW("No Compatibility callbacks set! Querying change " + changeId);
+            return true;
+        }
+    }
+
+    @CorePlatformApi
+    @IntraCoreApi
+    public static final class ChangeConfig {
+        private final Set<Long> enabled;
+        private final Set<Long> disabled;
+
+        public ChangeConfig(Set<Long> enabled, Set<Long> disabled) {
+            this.enabled = Objects.requireNonNull(enabled);
+            this.disabled = Objects.requireNonNull(disabled);
+            if (enabled.contains(null)) {
+                throw new NullPointerException();
+            }
+            if (disabled.contains(null)) {
+                throw new NullPointerException();
+            }
+            Set<Long> intersection = new HashSet<>(enabled);
+            intersection.retainAll(disabled);
+            if (!intersection.isEmpty()) {
+                throw new IllegalArgumentException("Cannot have changes " + intersection
+                        + " enabled and disabled!");
+            }
+        }
+
+        public boolean isEmpty() {
+            return enabled.isEmpty() && disabled.isEmpty();
+        }
+
+        private static long[] toLongArray(Set<Long> values) {
+            long[] result = new long[values.size()];
+            int idx = 0;
+            for (Long value: values) {
+                result[idx++] = value;
+            }
+            return result;
+        }
+
+        public long[] forceEnabledChangesArray() {
+            return toLongArray(enabled);
+        }
+
+        public long[] forceDisabledChangesArray() {
+            return toLongArray(disabled);
+        }
+
+        public Set<Long> forceEnabledSet() {
+            return Collections.unmodifiableSet(enabled);
+        }
+
+        public Set<Long> forceDisabledSet() {
+            return Collections.unmodifiableSet(disabled);
+        }
+
+        public boolean isForceEnabled(long changeId) {
+            return enabled.contains(changeId);
+        }
+
+        public boolean isForceDisabled(long changeId) {
+            return disabled.contains(changeId);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof ChangeConfig)) {
+                return false;
+            }
+            ChangeConfig that = (ChangeConfig) o;
+            return enabled.equals(that.enabled) &&
+                    disabled.equals(that.disabled);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(enabled, disabled);
+        }
+
+        @Override
+        public String toString() {
+            return "ChangeConfig{enabled=" + enabled + ", disabled=" + disabled + '}';
+        }
+    }
+
+    private static class OverrideCallbacks extends Callbacks {
+        private final Callbacks delegate;
+        private final ChangeConfig changeConfig;
+
+        private OverrideCallbacks(Callbacks delegate, ChangeConfig changeConfig) {
+            this.delegate = Objects.requireNonNull(delegate);
+            this.changeConfig = Objects.requireNonNull(changeConfig);
+        }
+        @Override
+        protected boolean isChangeEnabled(long changeId) {
+           if (changeConfig.isForceEnabled(changeId)) {
+               return true;
+           }
+           if (changeConfig.isForceDisabled(changeId)) {
+               return false;
+           }
+           return delegate.isChangeEnabled(changeId);
+        }
+    }
+}
diff --git a/luni/src/main/java/android/compat/TEST_MAPPING b/luni/src/main/java/android/compat/TEST_MAPPING
new file mode 100644
index 0000000..c8b07b4
--- /dev/null
+++ b/luni/src/main/java/android/compat/TEST_MAPPING
@@ -0,0 +1,17 @@
+{
+  "presubmit": [
+    // Unit tests for CoreCompatChangeRule
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.junit.util.compat"
+        }
+      ]
+    },
+    // CTS test for CompatChanges System
+    {
+      "name": "CtsAppCompatHostTestCases"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/android/system/ErrnoException.java b/luni/src/main/java/android/system/ErrnoException.java
index 02a529f..a5edf47 100644
--- a/luni/src/main/java/android/system/ErrnoException.java
+++ b/luni/src/main/java/android/system/ErrnoException.java
@@ -19,6 +19,7 @@
 import java.io.IOException;
 import java.net.SocketException;
 import libcore.io.Libcore;
+import libcore.util.NonNull;
 
 /**
  * A checked exception thrown when {@link Os} methods fail. This exception contains the native
@@ -65,21 +66,26 @@
     }
 
     /**
-     * @hide - internal use only.
+     * Throws an {@link IOException} with a message based on {@link #getMessage()} and with this
+     * instance as the cause.
+     *
+     * <p>This method always terminates by throwing the exception. Callers can write
+     * {@code throw e.rethrowAsIOException()} to make that clear to the compiler.
      */
-    @libcore.api.CorePlatformApi
-    public IOException rethrowAsIOException() throws IOException {
+    public @NonNull IOException rethrowAsIOException() throws IOException {
         IOException newException = new IOException(getMessage());
         newException.initCause(this);
         throw newException;
     }
 
     /**
-     * @hide - internal use only.
+     * Throws a {@link SocketException} with a message based on {@link #getMessage()} and with this
+     * instance as the cause.
+     *
+     * <p>This method always terminates by throwing the exception. Callers can write
+     * {@code throw e.rethrowAsIOException()} to make that clear to the compiler.
      */
-    @libcore.api.CorePlatformApi
-    @libcore.api.IntraCoreApi
-    public SocketException rethrowAsSocketException() throws SocketException {
+    public @NonNull SocketException rethrowAsSocketException() throws SocketException {
         throw new SocketException(getMessage(), this);
     }
 }
diff --git a/luni/src/main/java/android/system/StructIcmpHdr.java b/luni/src/main/java/android/system/IcmpHeaders.java
similarity index 62%
rename from luni/src/main/java/android/system/StructIcmpHdr.java
rename to luni/src/main/java/android/system/IcmpHeaders.java
index 87ae679..2203d40 100644
--- a/luni/src/main/java/android/system/StructIcmpHdr.java
+++ b/luni/src/main/java/android/system/IcmpHeaders.java
@@ -19,22 +19,26 @@
 import static android.system.OsConstants.ICMP6_ECHO_REQUEST;
 import static android.system.OsConstants.ICMP_ECHO;
 
+import java.io.FileDescriptor;
+import java.net.SocketAddress;
+
 /**
- * Corresponds to C's {@code struct icmphdr} from linux/icmp.h and {@code struct icmp6hdr} from
- * linux/icmpv6.h
+ * A utility class that can create ICMP header bytes corresponding to C's {@code struct icmphdr}
+ * from linux/icmp.h and {@code struct icmp6hdr} from linux/icmpv6.h. The bytes can be passed to
+ * methods like {@link Os#sendto(FileDescriptor, byte[], int, int, int, SocketAddress)}.
  *
  * @hide
  */
-public final class StructIcmpHdr {
-    private byte[] packet;
+public final class IcmpHeaders {
 
-    private StructIcmpHdr() {
-        packet =  new byte[8];
-    }
+    private IcmpHeaders() {}
 
-    /*
-     * Echo or Echo Reply Message
+    /**
+     * Creates the header bytes for an {@link OsConstants#ICMP_ECHO} or
+     * {@link OsConstants#ICMP6_ECHO_REQUEST} message. Code, checksum and identifier are left as
+     * zeros.
      *
+     * <pre>
      * 0                   1                   2                   3
      * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -42,21 +46,16 @@
      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      * |           Identifier          |        Sequence Number        |
      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-     * |     Data ...
-     * +-+-+-+-+-
+     * </pre>
      */
-    public static StructIcmpHdr IcmpEchoHdr(boolean ipv4, int seq) {
-        StructIcmpHdr hdr = new StructIcmpHdr();
-        hdr.packet[0] = ipv4 ? (byte) ICMP_ECHO : (byte) ICMP6_ECHO_REQUEST;
+    public static byte[] createIcmpEchoHdr(boolean ipv4, int seq) {
+        byte[] bytes = new byte[8];
+        bytes[0] = ipv4 ? (byte) ICMP_ECHO : (byte) ICMP6_ECHO_REQUEST;
         // packet[1]: Code is always zero.
         // packet[2,3]: Checksum is computed by kernel.
         // packet[4,5]: ID (= port) inserted by kernel.
-        hdr.packet[6] = (byte) (seq >> 8);
-        hdr.packet[7] = (byte) seq;
-        return hdr;
-    }
-
-    public byte[] getBytes() {
-        return packet.clone();
+        bytes[6] = (byte) (seq >> 8);
+        bytes[7] = (byte) seq;
+        return bytes;
     }
 }
diff --git a/luni/src/main/java/android/system/Int32Ref.java b/luni/src/main/java/android/system/Int32Ref.java
index 8f4a949..c43c796 100644
--- a/luni/src/main/java/android/system/Int32Ref.java
+++ b/luni/src/main/java/android/system/Int32Ref.java
@@ -16,7 +16,9 @@
 
 package android.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import libcore.util.Objects;
+
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * @hide
@@ -32,4 +34,8 @@
     public Int32Ref(int value) {
         this.value = value;
     }
+
+    @Override public String toString() {
+        return Objects.toString(this);
+    }
 }
diff --git a/luni/src/main/java/android/system/Int64Ref.java b/luni/src/main/java/android/system/Int64Ref.java
index f42450d8..77edaf0 100644
--- a/luni/src/main/java/android/system/Int64Ref.java
+++ b/luni/src/main/java/android/system/Int64Ref.java
@@ -16,6 +16,8 @@
 
 package android.system;
 
+import libcore.util.Objects;
+
 /**
  * A signed 64bit integer reference suitable for passing to lower-level system calls.
  */
@@ -25,4 +27,8 @@
     public Int64Ref(long value) {
         this.value = value;
     }
+
+    @Override public String toString() {
+        return Objects.toString(this);
+    }
 }
diff --git a/luni/src/main/java/android/system/NetlinkSocketAddress.java b/luni/src/main/java/android/system/NetlinkSocketAddress.java
index 64b0eab..b4f6e74 100644
--- a/luni/src/main/java/android/system/NetlinkSocketAddress.java
+++ b/luni/src/main/java/android/system/NetlinkSocketAddress.java
@@ -16,9 +16,10 @@
 
 package android.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import libcore.util.Objects;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.net.SocketAddress;
+import libcore.util.Objects;
 
 /**
  * Netlink socket address.
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java
index ded3b1c..70fdce5 100644
--- a/luni/src/main/java/android/system/Os.java
+++ b/luni/src/main/java/android/system/Os.java
@@ -16,11 +16,7 @@
 
 package android.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
-import libcore.io.Libcore;
-import libcore.util.NonNull;
-import libcore.util.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
 
 import java.io.FileDescriptor;
 import java.io.InterruptedIOException;
@@ -29,6 +25,9 @@
 import java.net.SocketAddress;
 import java.net.SocketException;
 import java.nio.ByteBuffer;
+import libcore.io.Libcore;
+import libcore.util.NonNull;
+import libcore.util.Nullable;
 
 /**
  * Access to low-level system functionality. Most of these are system calls. Most users will want
@@ -152,12 +151,10 @@
      */
     public static void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException { Libcore.os.fchown(fd, uid, gid); }
 
-    /** @hide */
-    public static int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException { return Libcore.os.fcntlFlock(fd, cmd, arg); }
-
-    /** @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); }
@@ -365,6 +362,11 @@
     public static StructStat lstat(String path) throws ErrnoException { return Libcore.os.lstat(path); }
 
     /**
+     * See <a href="http://man7.org/linux/man-pages/man2/memfd_create.2.html">memfd_create(2)</a>.
+     */
+    public static @NonNull FileDescriptor memfd_create(@NonNull String name, int flags) throws ErrnoException { return Libcore.os.memfd_create(name, flags); }
+
+    /**
      * See <a href="http://man7.org/linux/man-pages/man2/mincore.2.html">mincore(2)</a>.
      */
     public static void mincore(long address, long byteCount, byte[] vector) throws ErrnoException { Libcore.os.mincore(address, byteCount, vector); }
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index a119ec7..1b0dc16 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -16,7 +16,7 @@
 
 package android.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Constants and helper functions for use with {@link Os}.
@@ -130,6 +130,7 @@
     public static final int ARPHRD_ETHER = placeholder();
     /** @hide */
     @UnsupportedAppUsage
+    @libcore.api.CorePlatformApi
     public static final int ARPHRD_LOOPBACK = placeholder();
     public static final int CAP_AUDIT_CONTROL = placeholder();
     public static final int CAP_AUDIT_WRITE = placeholder();
@@ -358,6 +359,7 @@
     @libcore.api.CorePlatformApi
     public static final int _LINUX_CAPABILITY_VERSION_3 = placeholder();
     public static final int MAP_FIXED = placeholder();
+    public static final int MAP_ANONYMOUS = placeholder();
     /** @hide */
     @UnsupportedAppUsage
     @libcore.api.CorePlatformApi
@@ -372,6 +374,7 @@
     public static final int MCAST_UNBLOCK_SOURCE = placeholder();
     public static final int MCL_CURRENT = placeholder();
     public static final int MCL_FUTURE = placeholder();
+    public static final int MFD_CLOEXEC = placeholder();
     public static final int MSG_CTRUNC = placeholder();
     public static final int MSG_DONTROUTE = placeholder();
     public static final int MSG_EOR = placeholder();
@@ -382,9 +385,6 @@
     public static final int MS_ASYNC = placeholder();
     public static final int MS_INVALIDATE = placeholder();
     public static final int MS_SYNC = placeholder();
-    /** @hide */
-    @UnsupportedAppUsage
-    @libcore.api.CorePlatformApi
     public static final int NETLINK_NETFILTER = placeholder();
     public static final int NETLINK_ROUTE = placeholder();
     /**
diff --git a/luni/src/main/java/android/system/PacketSocketAddress.java b/luni/src/main/java/android/system/PacketSocketAddress.java
index d375226..c3f15a6 100644
--- a/luni/src/main/java/android/system/PacketSocketAddress.java
+++ b/luni/src/main/java/android/system/PacketSocketAddress.java
@@ -16,9 +16,10 @@
 
 package android.system;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import libcore.util.Objects;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.net.SocketAddress;
+import libcore.util.Objects;
 
 /**
  * Packet socket address.
@@ -29,24 +30,29 @@
  */
 @libcore.api.CorePlatformApi
 public final class PacketSocketAddress extends SocketAddress {
-    /** Protocol. An Ethernet protocol type, e.g., {@code ETH_P_IPV6}. */
-    public short sll_protocol;
+    /** Protocol. An Ethernet protocol type, e.g., {@link OsConstants#ETH_P_IPV6}. */
+    public final int sll_protocol;
 
     /** Interface index. */
-    public int sll_ifindex;
+    public final int sll_ifindex;
 
-    /** ARP hardware type. One of the {@code ARPHRD_*} constants. */
-    public short sll_hatype;
+    /**
+     * ARP hardware type. One of the {@code ARPHRD_*} constants, such as
+     * {@link OsConstants#ARPHRD_ETHER}.
+     */
+    public final int sll_hatype;
 
-    /** Packet type. One of the {@code PACKET_*} constants, such as {@code PACKET_OTHERHOST}. */
-    public byte sll_pkttype;
+    /**
+     * Packet type.
+     */
+    public final int sll_pkttype;
 
     /** Hardware address. */
-    public byte[] sll_addr;
+    public final byte[] sll_addr;
 
-    /** Constructs a new PacketSocketAddress. */
-    public PacketSocketAddress(short sll_protocol, int sll_ifindex,
-            short sll_hatype, byte sll_pkttype, byte[] sll_addr) {
+    /** Constructs a new PacketSocketAddress. Used from native code. */
+    public PacketSocketAddress(int sll_protocol, int sll_ifindex, int sll_hatype, int sll_pkttype,
+            byte[] sll_addr) {
         this.sll_protocol = sll_protocol;
         this.sll_ifindex = sll_ifindex;
         this.sll_hatype = sll_hatype;
@@ -54,17 +60,38 @@
         this.sll_addr = sll_addr;
     }
 
-    /** Constructs a new PacketSocketAddress suitable for binding to. */
-    @UnsupportedAppUsage
+    /** Constructs a new PacketSocketAddress with all the "in" parameters. */
     @libcore.api.CorePlatformApi
-    public PacketSocketAddress(short sll_protocol, int sll_ifindex) {
-        this(sll_protocol, sll_ifindex, (short) 0, (byte) 0, null);
+    public PacketSocketAddress(int sll_protocol, int sll_ifindex, byte[] sll_addr) {
+        this.sll_protocol = sll_protocol;
+        this.sll_ifindex = sll_ifindex;
+        this.sll_hatype = 0;
+        this.sll_pkttype = 0;
+        this.sll_addr = sll_addr;
     }
 
-    /** Constructs a new PacketSocketAddress suitable for sending to. */
+    /** Legacy constructor. Kept for @UnsupportedAppUsage only. */
     @UnsupportedAppUsage
-    @libcore.api.CorePlatformApi
+    public PacketSocketAddress(short sll_protocol, int sll_ifindex) {
+        this.sll_protocol = sll_protocol;
+        this.sll_ifindex = sll_ifindex;
+        this.sll_hatype = 0;
+        this.sll_pkttype = 0;
+        this.sll_addr = null;
+    }
+
+    /** Legacy constructor. Kept for @UnsupportedAppUsage only. */
+    @UnsupportedAppUsage
     public PacketSocketAddress(int sll_ifindex, byte[] sll_addr) {
-        this((short) 0, sll_ifindex, (short) 0, (byte) 0, sll_addr);
+        this.sll_protocol = 0;
+        this.sll_ifindex = sll_ifindex;
+        this.sll_hatype = 0;
+        this.sll_pkttype = 0;
+        this.sll_addr = sll_addr;
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toString(this);
     }
 }
diff --git a/luni/src/main/java/android/system/StructFlock.java b/luni/src/main/java/android/system/StructFlock.java
deleted file mode 100644
index 0d93425..0000000
--- a/luni/src/main/java/android/system/StructFlock.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.system;
-
-import libcore.util.Objects;
-
-/**
- * Information returned/taken by fcntl(2) F_GETFL and F_SETFL. Corresponds to C's
- * {@code struct flock} from
- * <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fcntl.h.html">&lt;fcntl.h&gt;</a>
- *
- * @hide
- */
-public final class StructFlock {
-    /** The operation type, one of F_RDLCK, F_WRLCK, or F_UNLCK. */
-    public short l_type;
-
-    /** How to interpret l_start, one of SEEK_CUR, SEEK_END, SEEK_SET. */
-    public short l_whence;
-
-    /** Start offset. */
-    public long l_start; /*off_t*/
-
-    /** Byte count to operate on. */
-    public long l_len; /*off_t*/
-
-    /** Process blocking our lock (filled in by F_GETLK, otherwise unused). */
-    public int l_pid; /*pid_t*/
-
-    @Override public String toString() {
-        return Objects.toString(this);
-    }
-}
diff --git a/luni/src/main/java/android/system/StructIfaddrs.java b/luni/src/main/java/android/system/StructIfaddrs.java
index 7769f28..81d180a 100644
--- a/luni/src/main/java/android/system/StructIfaddrs.java
+++ b/luni/src/main/java/android/system/StructIfaddrs.java
@@ -16,6 +16,8 @@
 
 package android.system;
 
+import libcore.util.Objects;
+
 import java.net.InetAddress;
 
 /**
@@ -44,4 +46,8 @@
         this.ifa_broadaddr = ifa_broadaddr;
         this.hwaddr = hwaddr;
     }
+
+    @Override public String toString() {
+        return Objects.toString(this);
+    }
 }
diff --git a/luni/src/main/java/android/system/TEST_MAPPING b/luni/src/main/java/android/system/TEST_MAPPING
new file mode 100644
index 0000000..66e8d78
--- /dev/null
+++ b/luni/src/main/java/android/system/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.android.system"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/android/system/UnixSocketAddress.java b/luni/src/main/java/android/system/UnixSocketAddress.java
index be689b3..993cc5b 100644
--- a/luni/src/main/java/android/system/UnixSocketAddress.java
+++ b/luni/src/main/java/android/system/UnixSocketAddress.java
@@ -35,7 +35,8 @@
     // 1) pathname: 0 < sun_path.length <= NAMED_PATH_LENGTH, sun_path[0] != 0.
     // 2) unnamed: sun_path = [].
     // 3) abstract: 0 < sun_path.length <= NAMED_PATH_LENGTH, sun_path[0] == 0.
-    private byte[] sun_path;
+    // Note that the array referenced by this field can be modified from JNI (libcore_io_Linux.cpp).
+    private final byte[] sun_path;
 
     /** This constructor is also used from JNI. */
     private UnixSocketAddress(byte[] sun_path) {
@@ -56,6 +57,9 @@
 
     /**
      * Creates a named, abstract AF_UNIX socket address.
+     *
+     * @throws NullPointerException if {@code name} is null
+     * @throws IllegalArgumentException if {@code name} is invalid, e.g. too long
      */
     public static UnixSocketAddress createAbstract(String name) {
         byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
@@ -67,6 +71,9 @@
 
     /**
      * Creates a named, filesystem AF_UNIX socket address.
+     *
+     * @throws NullPointerException if {@code name} is null
+     * @throws IllegalArgumentException if {@code name} is invalid, e.g. too long
      */
     @libcore.api.CorePlatformApi
     public static UnixSocketAddress createFileSystem(String pathName) {
diff --git a/luni/src/main/java/java/lang/TEST_MAPPING b/luni/src/main/java/java/lang/TEST_MAPPING
new file mode 100644
index 0000000..9374f92
--- /dev/null
+++ b/luni/src/main/java/java/lang/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/libart/src/main/java/java/lang"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/java/lang/ref/FinalizerReference.java b/luni/src/main/java/java/lang/ref/FinalizerReference.java
index 9589a9d..037af4a 100644
--- a/luni/src/main/java/java/lang/ref/FinalizerReference.java
+++ b/luni/src/main/java/java/lang/ref/FinalizerReference.java
@@ -16,7 +16,7 @@
 
 package java.lang.ref;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import dalvik.annotation.optimization.FastNative;
 
 /**
diff --git a/luni/src/main/java/java/lang/ref/TEST_MAPPING b/luni/src/main/java/java/lang/ref/TEST_MAPPING
new file mode 100644
index 0000000..0614a12
--- /dev/null
+++ b/luni/src/main/java/java/lang/ref/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.lang.ref"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.lang.ref"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/java/math/BigInteger.java b/luni/src/main/java/java/math/BigInteger.java
index f7c0be2..b96fdb2 100644
--- a/luni/src/main/java/java/math/BigInteger.java
+++ b/luni/src/main/java/java/math/BigInteger.java
@@ -885,6 +885,26 @@
      * @throws NullPointerException if {@code value == null}.
      */
     @NonNull public BigInteger gcd(@NonNull BigInteger value) {
+        // First optimize the case in which the two arguments have very different
+        // length.
+        int thisLen = bitLength();
+        int valueLen = value.bitLength();
+        final int gcdDirectRatio = 16;
+        if (thisLen > gcdDirectRatio * valueLen) {
+            // A division-based step reduces the length of this by a factor of at
+            // least gcdDirectRatio, thus ensuring that a division-based step will
+            // easily pay for itself.
+            if (value.signum() == 0) {
+                return this.abs();
+            }
+            return value.gcd(this.mod(value.abs()));
+        } else if (valueLen > gcdDirectRatio * thisLen) {
+            if (signum() == 0) {
+                return value.abs();
+            }
+            return this.gcd(value.mod(this.abs()));
+        }
+
         return new BigInteger(BigInt.gcd(getBigInt(), value.getBigInt()));
     }
 
diff --git a/luni/src/main/java/java/math/TEST_MAPPING b/luni/src/main/java/java/math/TEST_MAPPING
new file mode 100644
index 0000000..1038858
--- /dev/null
+++ b/luni/src/main/java/java/math/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.java.math"
+        },
+        {
+          "include-filter": "libcore.java.math"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/java/net/AddressCache.java b/luni/src/main/java/java/net/AddressCache.java
index ac5a029..3026923 100644
--- a/luni/src/main/java/java/net/AddressCache.java
+++ b/luni/src/main/java/java/net/AddressCache.java
@@ -16,7 +16,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import libcore.util.BasicLruCache;
 
 /**
diff --git a/luni/src/main/java/java/net/DefaultFileNameMap.java b/luni/src/main/java/java/net/DefaultFileNameMap.java
index 6222d75..da67d14 100644
--- a/luni/src/main/java/java/net/DefaultFileNameMap.java
+++ b/luni/src/main/java/java/net/DefaultFileNameMap.java
@@ -16,27 +16,40 @@
 
 package java.net;
 
-import java.util.Locale;
-import libcore.net.MimeUtils;
+import libcore.content.type.MimeMap;
 
 /**
- * Implements {@link FileNameMap} in terms of {@link libcore.net.MimeUtils}.
+ * Implements {@link FileNameMap} in terms of {@link MimeMap}.
  */
 class DefaultFileNameMap implements FileNameMap {
+
     public String getContentTypeFor(String filename) {
-        if (filename.endsWith("/")) {
-            // a directory, return html
-            return MimeUtils.guessMimeTypeFromExtension("html");
+        int fragmentIndex = filename.indexOf('#');
+        if (fragmentIndex >= 0) {
+            filename = filename.substring(0, fragmentIndex);
         }
-        int lastCharInExtension = filename.lastIndexOf('#');
-        if (lastCharInExtension < 0) {
-            lastCharInExtension = filename.length();
+        if (filename.endsWith("/")) { // a directory
+            return "text/html";
         }
-        int firstCharInExtension = filename.lastIndexOf('.') + 1;
-        String ext = "";
-        if (firstCharInExtension > filename.lastIndexOf('/')) {
-            ext = filename.substring(firstCharInExtension, lastCharInExtension);
+
+        int slashIndex = filename.lastIndexOf('/');
+        if (slashIndex >= 0) {
+            filename = filename.substring(slashIndex);
         }
-        return MimeUtils.guessMimeTypeFromExtension(ext);
+
+        MimeMap mimeMap = MimeMap.getDefault();
+        int dotIndex = -1;
+        do {
+            String ext = filename.substring(dotIndex + 1);
+            String result = mimeMap.guessMimeTypeFromExtension(ext);
+            if ((result != null) &&
+                    // Compat behavior: If there's a '/', then extension must not be the
+                    // whole string. http://b/144977800
+                    (slashIndex < 0 || dotIndex >= 0)) {
+                return result;
+            }
+            dotIndex = filename.indexOf('.', dotIndex + 1);
+        } while (dotIndex >= 0);
+        return null;
     }
 }
diff --git a/luni/src/main/java/java/net/TEST_MAPPING b/luni/src/main/java/java/net/TEST_MAPPING
new file mode 100644
index 0000000..3573294
--- /dev/null
+++ b/luni/src/main/java/java/net/TEST_MAPPING
@@ -0,0 +1,29 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.net"
+        },
+        {
+          "include-filter": "org.apache.harmony.luni.tests.internal.net.www.protocol.http"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.net"
+        },
+        {
+          "include-filter": "org.apache.harmony.luni.tests.java.net"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "test.java.net"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/java/nio/NIOAccess.java b/luni/src/main/java/java/nio/NIOAccess.java
index 7a07e3d..7345379 100644
--- a/luni/src/main/java/java/nio/NIOAccess.java
+++ b/luni/src/main/java/java/nio/NIOAccess.java
@@ -16,13 +16,15 @@
 
 package java.nio;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
- * This class is used via JNI by code in frameworks/base/.
+ * This class is used via JNI by code in frameworks/base/ and
+ * by the JniConstants cache in libnativehelper/.
  * @hide
  */
 // @VisibleForTesting : was default
+@libcore.api.CorePlatformApi
 public final class NIOAccess {
 
     /**
@@ -46,7 +48,8 @@
      * given Buffer, or null if the Buffer is not backed by a Java array.
      */
     @UnsupportedAppUsage
-    static Object getBaseArray(Buffer b) {
+    @libcore.api.CorePlatformApi
+    public static Object getBaseArray(Buffer b) {
         return b.hasArray() ? b.array() : null;
     }
 
@@ -58,7 +61,8 @@
      * meaningful if getBaseArray() returns non-null.
      */
     @UnsupportedAppUsage
-    static int getBaseArrayOffset(Buffer b) {
+    @libcore.api.CorePlatformApi
+    public static int getBaseArrayOffset(Buffer b) {
         return b.hasArray() ? ((b.arrayOffset() + b.position) << b._elementSizeShift) : 0;
     }
 }
diff --git a/luni/src/main/java/java/nio/NioUtils.java b/luni/src/main/java/java/nio/NioUtils.java
index 678382d..aca91b0 100644
--- a/luni/src/main/java/java/nio/NioUtils.java
+++ b/luni/src/main/java/java/nio/NioUtils.java
@@ -16,19 +16,19 @@
 
 package java.nio;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.io.Closeable;
 import java.io.FileDescriptor;
-import java.io.IOException;
-import java.nio.channels.ClosedChannelException;
 import java.nio.channels.FileChannel;
-import java.util.Set;
 
-import static android.system.OsConstants.*;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import sun.misc.Cleaner;
-import sun.nio.ch.DirectBuffer;
 import sun.nio.ch.FileChannelImpl;
 
+import static android.system.OsConstants.O_ACCMODE;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_WRONLY;
+
 /**
  * @hide internal use only
  */
@@ -64,8 +64,8 @@
      * Helps bridge between io and nio.
      */
     public static FileChannel newFileChannel(Closeable ioObject, FileDescriptor fd, int mode) {
-        boolean readable = (mode & (O_RDONLY | O_RDWR | O_SYNC)) != 0;
-        boolean writable = (mode & (O_WRONLY | O_RDWR | O_SYNC)) != 0;
+        boolean readable = (mode & O_ACCMODE) != O_WRONLY;
+        boolean writable = (mode & O_ACCMODE) != O_RDONLY;
         boolean append = (mode & O_APPEND) != 0;
         return FileChannelImpl.open(fd, null, readable, writable, append, ioObject);
     }
diff --git a/luni/src/main/java/java/nio/TEST_MAPPING b/luni/src/main/java/java/nio/TEST_MAPPING
new file mode 100644
index 0000000..3fe450e
--- /dev/null
+++ b/luni/src/main/java/java/nio/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.java.nio"
+        },
+        {
+          "include-filter": "libcore.java.nio"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
deleted file mode 100644
index f695694..0000000
--- a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
-*******************************************************************************
-*
-*******************************************************************************
-*/
- /**
-  * A JNI interface for ICU converters.
-  *
-  *
-  * @author Ram Viswanadha, IBM
-  */
-package java.nio.charset;
-
-import dalvik.annotation.optimization.ReachabilitySensitive;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import libcore.icu.ICU;
-import libcore.icu.NativeConverter;
-import libcore.util.EmptyArray;
-
-final class CharsetDecoderICU extends CharsetDecoder {
-    private static final int MAX_CHARS_PER_BYTE = 2;
-
-    private static final int INPUT_OFFSET = 0;
-    private static final int OUTPUT_OFFSET = 1;
-    private static final int INVALID_BYTE_COUNT = 2;
-    /*
-     * data[INPUT_OFFSET]   = on input contains the start of input and on output the number of input bytes consumed
-     * data[OUTPUT_OFFSET]  = on input contains the start of output and on output the number of output chars written
-     * data[INVALID_BYTE_COUNT]  = number of invalid bytes
-     */
-    private final int[] data = new int[3];
-
-    /* Handle to the ICU converter that is opened, cleaned up via NativeAllocationRegistry. */
-    @ReachabilitySensitive
-    private long converterHandle = 0;
-
-    private byte[] input = null;
-    private char[] output= null;
-
-    private byte[] allocatedInput = null;
-    private char[] allocatedOutput = null;
-
-    // These instance variables are always assigned in the methods before being used. This class
-    // is inherently thread-unsafe so we don't have to worry about synchronization.
-    private int inEnd;
-    private int outEnd;
-
-    public static CharsetDecoderICU newInstance(Charset cs, String icuCanonicalName) {
-        // This complexity is necessary to ensure that even if the constructor, superclass
-        // constructor, or call to updateCallback throw, we still free the native peer.
-        long address = 0;
-        CharsetDecoderICU result;
-        try {
-            address = NativeConverter.openConverter(icuCanonicalName);
-            float averageCharsPerByte = NativeConverter.getAveCharsPerByte(address);
-            result = new CharsetDecoderICU(cs, averageCharsPerByte, address);
-        } catch (Throwable t) {
-            if (address != 0) {
-                NativeConverter.closeConverter(address);
-            }
-            throw t;
-        }
-        // An exception in registerConverter() will deallocate address:
-        NativeConverter.registerConverter(result, address);
-        result.updateCallback();
-        return result;
-    }
-
-    private CharsetDecoderICU(Charset cs, float averageCharsPerByte, long address) {
-        super(cs, averageCharsPerByte, MAX_CHARS_PER_BYTE);
-        this.converterHandle = address;
-    }
-
-    @Override protected void implReplaceWith(String newReplacement) {
-        updateCallback();
-    }
-
-    @Override protected final void implOnMalformedInput(CodingErrorAction newAction) {
-        updateCallback();
-    }
-
-    @Override protected final void implOnUnmappableCharacter(CodingErrorAction newAction) {
-        updateCallback();
-    }
-
-    private void updateCallback() {
-        NativeConverter.setCallbackDecode(converterHandle, this);
-    }
-
-    @Override protected void implReset() {
-        NativeConverter.resetByteToChar(converterHandle);
-        data[INPUT_OFFSET] = 0;
-        data[OUTPUT_OFFSET] = 0;
-        data[INVALID_BYTE_COUNT] = 0;
-        output = null;
-        input = null;
-        allocatedInput = null;
-        allocatedOutput = null;
-        inEnd = 0;
-        outEnd = 0;
-    }
-
-    @Override protected final CoderResult implFlush(CharBuffer out) {
-        try {
-            // ICU needs to see an empty input.
-            input = EmptyArray.BYTE;
-            inEnd = 0;
-            data[INPUT_OFFSET] = 0;
-
-            data[OUTPUT_OFFSET] = getArray(out);
-            data[INVALID_BYTE_COUNT] = 0; // Make sure we don't see earlier errors.
-
-            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, true);
-            if (ICU.U_FAILURE(error)) {
-                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
-                    return CoderResult.OVERFLOW;
-                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
-                    if (data[INVALID_BYTE_COUNT] > 0) {
-                        return CoderResult.malformedForLength(data[INVALID_BYTE_COUNT]);
-                    }
-                }
-            }
-            return CoderResult.UNDERFLOW;
-       } finally {
-            setPosition(out);
-            implReset();
-       }
-    }
-
-    @Override protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
-        if (!in.hasRemaining()) {
-            return CoderResult.UNDERFLOW;
-        }
-
-        data[INPUT_OFFSET] = getArray(in);
-        data[OUTPUT_OFFSET]= getArray(out);
-
-        try {
-            int error = NativeConverter.decode(converterHandle, input, inEnd, output, outEnd, data, false);
-            if (ICU.U_FAILURE(error)) {
-                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
-                    return CoderResult.OVERFLOW;
-                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
-                    return CoderResult.unmappableForLength(data[INVALID_BYTE_COUNT]);
-                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
-                    return CoderResult.malformedForLength(data[INVALID_BYTE_COUNT]);
-                } else {
-                    throw new AssertionError(error);
-                }
-            }
-            // Decoding succeeded: give us more data.
-            return CoderResult.UNDERFLOW;
-        } finally {
-            setPosition(in);
-            setPosition(out);
-        }
-    }
-
-
-    private int getArray(CharBuffer out) {
-        if (out.hasArray()) {
-            output = out.array();
-            outEnd = out.arrayOffset() + out.limit();
-            return out.arrayOffset() + out.position();
-        } else {
-            outEnd = out.remaining();
-            if (allocatedOutput == null || outEnd > allocatedOutput.length) {
-                allocatedOutput = new char[outEnd];
-            }
-            // The array's start position is 0.
-            output = allocatedOutput;
-            return 0;
-        }
-    }
-
-    private  int getArray(ByteBuffer in) {
-        if (in.hasArray()) {
-            input = in.array();
-            inEnd = in.arrayOffset() + in.limit();
-            return in.arrayOffset() + in.position();
-        } else {
-            inEnd = in.remaining();
-            if (allocatedInput == null || inEnd > allocatedInput.length) {
-                allocatedInput = new byte[inEnd];
-            }
-            // Copy the input buffer into the allocated array.
-            int pos = in.position();
-            in.get(allocatedInput, 0, inEnd);
-            in.position(pos);
-            // The array's start position is 0.
-            input = allocatedInput;
-            return 0;
-        }
-    }
-
-    private void setPosition(CharBuffer out) {
-        if (out.hasArray()) {
-            out.position(out.position() + data[OUTPUT_OFFSET]);
-        } else {
-            out.put(output, 0, data[OUTPUT_OFFSET]);
-        }
-        // release reference to output array, which may not be ours
-        output = null;
-    }
-
-    private void setPosition(ByteBuffer in) {
-        in.position(in.position() + data[INPUT_OFFSET]);
-        // release reference to input array, which may not be ours
-        input = null;
-    }
-}
diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
deleted file mode 100644
index c57aafd..0000000
--- a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                  *
-*******************************************************************************
-*
-*******************************************************************************
-*/
-/**
- * A JNI interface for ICU converters.
- *
- *
- * @author Ram Viswanadha, IBM
- */
-package java.nio.charset;
-
-import dalvik.annotation.optimization.ReachabilitySensitive;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.util.HashMap;
-import java.util.Map;
-import libcore.icu.ICU;
-import libcore.icu.NativeConverter;
-import libcore.util.EmptyArray;
-
-final class CharsetEncoderICU extends CharsetEncoder {
-    private static final Map<String, byte[]> DEFAULT_REPLACEMENTS = new HashMap<String, byte[]>();
-    static {
-        // ICU has different default replacements to the RI in some cases. There are many
-        // additional cases, but this covers all the charsets that Java guarantees will be
-        // available, which is where compatibility seems most important. (The RI even uses
-        // the byte corresponding to '?' in ASCII as the replacement byte for charsets where that
-        // byte corresponds to an entirely different character.)
-        // It's odd that UTF-8 doesn't use U+FFFD, given that (unlike ISO-8859-1 and US-ASCII) it
-        // can represent it, but this is what the RI does...
-        byte[] questionMark = new byte[] { (byte) '?' };
-        DEFAULT_REPLACEMENTS.put("UTF-8",      questionMark);
-        DEFAULT_REPLACEMENTS.put("ISO-8859-1", questionMark);
-        DEFAULT_REPLACEMENTS.put("US-ASCII",   questionMark);
-    }
-
-    private static final int INPUT_OFFSET = 0;
-    private static final int OUTPUT_OFFSET = 1;
-    private static final int INVALID_CHAR_COUNT = 2;
-    /*
-     * data[INPUT_OFFSET]   = on input contains the start of input and on output the number of input chars consumed
-     * data[OUTPUT_OFFSET]  = on input contains the start of output and on output the number of output bytes written
-     * data[INVALID_CHARS]  = number of invalid chars
-     */
-    private int[] data = new int[3];
-
-    /* handle to the ICU converter that is opened */
-    @ReachabilitySensitive
-    private final long converterHandle;
-
-    private char[] input = null;
-    private byte[] output = null;
-
-    private char[] allocatedInput = null;
-    private byte[] allocatedOutput = null;
-
-    // These instance variables are always assigned in the methods before being used. This class
-    // is inherently thread-unsafe so we don't have to worry about synchronization.
-    private int inEnd;
-    private int outEnd;
-
-    public static CharsetEncoderICU newInstance(Charset cs, String icuCanonicalName) {
-        // This complexity is necessary to ensure that even if the constructor, superclass
-        // constructor, or call to updateCallback throw, we still free the native peer.
-        long address = 0;
-        CharsetEncoderICU result;
-        try {
-            address = NativeConverter.openConverter(icuCanonicalName);
-            float averageBytesPerChar = NativeConverter.getAveBytesPerChar(address);
-            float maxBytesPerChar = NativeConverter.getMaxBytesPerChar(address);
-            byte[] replacement = makeReplacement(icuCanonicalName, address);
-            result = new CharsetEncoderICU(cs, averageBytesPerChar, maxBytesPerChar, replacement, address);
-        } catch (Throwable t) {
-            if (address != 0) {
-                NativeConverter.closeConverter(address);
-            }
-            throw t;
-        }
-        // An exception in registerConverter() will deallocate address:
-        NativeConverter.registerConverter(result, address);
-        result.updateCallback();
-        return result;
-    }
-
-    private static byte[] makeReplacement(String icuCanonicalName, long address) {
-        // We have our own map of RI-compatible default replacements (where ICU disagrees)...
-        byte[] replacement = DEFAULT_REPLACEMENTS.get(icuCanonicalName);
-        if (replacement != null) {
-            return replacement.clone();
-        }
-        // ...but fall back to asking ICU.
-        return NativeConverter.getSubstitutionBytes(address);
-    }
-
-    private CharsetEncoderICU(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, long address) {
-        super(cs, averageBytesPerChar, maxBytesPerChar, replacement, true);
-        // Our native peer needs to know what just happened...
-        this.converterHandle = address;
-    }
-
-    @Override protected void implReplaceWith(byte[] newReplacement) {
-        updateCallback();
-    }
-
-    @Override protected void implOnMalformedInput(CodingErrorAction newAction) {
-        updateCallback();
-    }
-
-    @Override protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
-        updateCallback();
-    }
-
-    private void updateCallback() {
-        NativeConverter.setCallbackEncode(converterHandle, this);
-    }
-
-    @Override protected void implReset() {
-        NativeConverter.resetCharToByte(converterHandle);
-        data[INPUT_OFFSET] = 0;
-        data[OUTPUT_OFFSET] = 0;
-        data[INVALID_CHAR_COUNT] = 0;
-        output = null;
-        input = null;
-        allocatedInput = null;
-        allocatedOutput = null;
-        inEnd = 0;
-        outEnd = 0;
-    }
-
-    @Override protected CoderResult implFlush(ByteBuffer out) {
-        try {
-            // ICU needs to see an empty input.
-            input = EmptyArray.CHAR;
-            inEnd = 0;
-            data[INPUT_OFFSET] = 0;
-
-            data[OUTPUT_OFFSET] = getArray(out);
-            data[INVALID_CHAR_COUNT] = 0; // Make sure we don't see earlier errors.
-
-            int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, true);
-            if (ICU.U_FAILURE(error)) {
-                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
-                    return CoderResult.OVERFLOW;
-                } else if (error == ICU.U_TRUNCATED_CHAR_FOUND) {
-                    if (data[INVALID_CHAR_COUNT] > 0) {
-                        return CoderResult.malformedForLength(data[INVALID_CHAR_COUNT]);
-                    }
-                }
-            }
-            return CoderResult.UNDERFLOW;
-        } finally {
-            setPosition(out);
-            implReset();
-        }
-    }
-
-    @Override protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
-        if (!in.hasRemaining()) {
-            return CoderResult.UNDERFLOW;
-        }
-
-        data[INPUT_OFFSET] = getArray(in);
-        data[OUTPUT_OFFSET]= getArray(out);
-        data[INVALID_CHAR_COUNT] = 0; // Make sure we don't see earlier errors.
-
-        try {
-            int error = NativeConverter.encode(converterHandle, input, inEnd, output, outEnd, data, false);
-            if (ICU.U_FAILURE(error)) {
-                if (error == ICU.U_BUFFER_OVERFLOW_ERROR) {
-                    return CoderResult.OVERFLOW;
-                } else if (error == ICU.U_INVALID_CHAR_FOUND) {
-                    return CoderResult.unmappableForLength(data[INVALID_CHAR_COUNT]);
-                } else if (error == ICU.U_ILLEGAL_CHAR_FOUND) {
-                    return CoderResult.malformedForLength(data[INVALID_CHAR_COUNT]);
-                } else {
-                    throw new AssertionError(error);
-                }
-            }
-            // Decoding succeeded: give us more data.
-            return CoderResult.UNDERFLOW;
-        } finally {
-            setPosition(in);
-            setPosition(out);
-        }
-    }
-
-    private int getArray(ByteBuffer out) {
-        if (out.hasArray()) {
-            output = out.array();
-            outEnd = out.arrayOffset() + out.limit();
-            return out.arrayOffset() + out.position();
-        } else {
-            outEnd = out.remaining();
-            if (allocatedOutput == null || outEnd > allocatedOutput.length) {
-                allocatedOutput = new byte[outEnd];
-            }
-            // The array's start position is 0
-            output = allocatedOutput;
-            return 0;
-        }
-    }
-
-    private int getArray(CharBuffer in) {
-        if (in.hasArray()) {
-            input = in.array();
-            inEnd = in.arrayOffset() + in.limit();
-            return in.arrayOffset() + in.position();
-        } else {
-            inEnd = in.remaining();
-            if (allocatedInput == null || inEnd > allocatedInput.length) {
-                allocatedInput = new char[inEnd];
-            }
-            // Copy the input buffer into the allocated array.
-            int pos = in.position();
-            in.get(allocatedInput, 0, inEnd);
-            in.position(pos);
-            // The array's start position is 0
-            input = allocatedInput;
-            return 0;
-        }
-    }
-
-    private void setPosition(ByteBuffer out) {
-        if (out.hasArray()) {
-            out.position(data[OUTPUT_OFFSET] - out.arrayOffset());
-        } else {
-            out.put(output, 0, data[OUTPUT_OFFSET]);
-        }
-        // release reference to output array, which may not be ours
-        output = null;
-    }
-
-    private void setPosition(CharBuffer in) {
-        int position = in.position() + data[INPUT_OFFSET] - data[INVALID_CHAR_COUNT];
-        if (position < 0) {
-            // The calculated position might be negative if we encountered an
-            // invalid char that spanned input buffers. We adjust it to 0 in this case.
-            //
-            // NOTE: The API doesn't allow us to adjust the position of the previous
-            // input buffer. (Doing that wouldn't serve any useful purpose anyway.)
-            position = 0;
-        }
-
-        in.position(position);
-        // release reference to input array, which may not be ours
-        input = null;
-    }
-}
diff --git a/luni/src/main/java/java/nio/charset/CharsetICU.java b/luni/src/main/java/java/nio/charset/CharsetICU.java
deleted file mode 100644
index 63ffd3e..0000000
--- a/luni/src/main/java/java/nio/charset/CharsetICU.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2005, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
-*******************************************************************************
-*
-*******************************************************************************
-*/
-
-package java.nio.charset;
-
-import libcore.icu.NativeConverter;
-
-/**
- * This class is used from native code associated with {@link NativeConverter}.
- */
-final class CharsetICU extends Charset {
-    private final String icuCanonicalName;
-
-    protected CharsetICU(String canonicalName, String icuCanonName, String[] aliases) {
-         super(canonicalName, aliases);
-         icuCanonicalName = icuCanonName;
-    }
-
-    public CharsetDecoder newDecoder() {
-        return CharsetDecoderICU.newInstance(this, icuCanonicalName);
-    }
-
-    public CharsetEncoder newEncoder() {
-        return CharsetEncoderICU.newInstance(this, icuCanonicalName);
-    }
-
-    public boolean contains(Charset cs) {
-        if (cs == null) {
-            return false;
-        } else if (this.equals(cs)) {
-            return true;
-        }
-        return NativeConverter.contains(this.name(), cs.name());
-    }
-}
diff --git a/luni/src/main/java/java/nio/charset/ModifiedUtf8.java b/luni/src/main/java/java/nio/charset/ModifiedUtf8.java
deleted file mode 100644
index 51638ee..0000000
--- a/luni/src/main/java/java/nio/charset/ModifiedUtf8.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2015 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 java.nio.charset;
-
-import java.io.UTFDataFormatException;
-
-/**
- * Encoding and decoding methods for Modified UTF-8
- *
- * <p>Modified UTF-8 is a simple variation of UTF-8 in which {@code \u0000} is encoded as
- * 0xc0 0x80 . This avoids the presence of bytes 0 in the output.
- *
- * @hide
- */
-public class ModifiedUtf8 {
-
-    /**
-     * Count the number of bytes in the modified UTF-8 representation of {@code s}.
-     *
-     * <p>Additionally, if {@code shortLength} is true, throw a {@code UTFDataFormatException} if
-     * the size cannot be presented in an (unsigned) java short.
-     */
-    public static long countBytes(String s, boolean shortLength) throws UTFDataFormatException {
-        long counter = 0;
-        int strLen = s.length();
-        for (int i = 0; i < strLen; i++) {
-            char c = s.charAt(i);
-            if (c < '\u0080') {
-                counter++;
-                if (c == '\u0000') {
-                    counter++;
-                }
-            } else if (c < '\u0800') {
-                counter += 2;
-            } else {
-                counter += 3;
-            }
-        }
-        // Allow up to the maximum value of an unsigned short (as the value is known to be
-        // unsigned.
-        if (shortLength && counter > 0xffff) {
-            throw new UTFDataFormatException(
-                    "Size of the encoded string doesn't fit in two bytes");
-        }
-        return counter;
-    }
-
-    /**
-     * Encode {@code s} into {@code dst} starting at offset {@code offset}.
-     *
-     * <p>The output buffer is guaranteed to have enough space.
-     */
-    public static void encode(byte[] dst, int offset, String s) {
-        int strLen = s.length();
-        for (int i = 0; i < strLen; i++) {
-            char c = s.charAt(i);
-            if (c < '\u0080') {
-                if (c == 0) {
-                    dst[offset++] = (byte) 0xc0;
-                    dst[offset++] = (byte) 0x80;
-                } else {
-                    dst[offset++] = (byte) c;
-                }
-            } else if (c < '\u0800') {
-                dst[offset++] = (byte) ((c >>> 6) | 0xc0);
-                dst[offset++] = (byte) ((c & 0x3f) | 0x80);
-            } else {
-                dst[offset++] = (byte) ((c >>> 12) | 0xe0);
-                dst[offset++] = (byte) (((c >>> 6) & 0x3f) | 0x80);
-                dst[offset++] = (byte) ((c & 0x3f) | 0x80);
-            }
-        }
-    }
-
-    /**
-     * Encodes {@code s} into a buffer with the following format:
-     *
-     * <p>- the first two bytes of the buffer are the length of the modified-utf8 output
-     * (as a big endian short. A UTFDataFormatException is thrown if the encoded size cannot be
-     * represented as a short.
-     *
-     * <p>- the remainder of the buffer contains the modified-utf8 output (equivalent to
-     * {@code encode(buf, 2, s)}).
-     */
-    public static byte[] encode(String s) throws UTFDataFormatException {
-        long size = countBytes(s, true);
-        byte[] output = new byte[(int) size + 2];
-        encode(output, 2, s);
-        output[0] = (byte) (size >>> 8);
-        output[1] = (byte) size;
-        return output;
-    }
-
-    /**
-     * Decodes {@code length} utf-8 bytes from {@code in} starting at offset {@code offset} to
-     * {@code out},
-     *
-     * <p>A maximum of {@code length} chars are written to the output starting at offset 0.
-     * {@code out} is assumed to have enough space for the output (a standard
-     * {@code ArrayIndexOutOfBoundsException} is thrown otherwise).
-     *
-     * <p>If a ‘0’ byte is encountered, it is converted to U+0000.
-     */
-    public static String decode(byte[] in, char[] out, int offset, int length)
-            throws UTFDataFormatException {
-        if (offset < 0 || length < 0) {
-            throw new IllegalArgumentException("Illegal arguments: offset " + offset
-                    + ". Length: " + length);
-        }
-        int outputIndex = 0;
-        int limitIndex = offset + length;
-        while (offset < limitIndex) {
-            int i = in[offset] & 0xff;
-            offset++;
-            if (i < 0x80) {
-                out[outputIndex] = (char) i;
-                outputIndex++;
-                continue;
-            }
-            if (0xc0 <= i && i < 0xe0) {
-                // This branch covers the case 0 = 0xc080.
-
-                // The result is: 5 least-significant bits of i + 6 l-s bits of next input byte.
-                i = (i & 0x1f) << 6;
-                if(offset == limitIndex) {
-                    throw new UTFDataFormatException("unexpected end of input");
-                }
-                // Include 6 least-significant bits of the input byte.
-                if ((in[offset] & 0xc0) != 0x80) {
-                    throw new UTFDataFormatException("bad second byte at " + offset);
-                }
-                out[outputIndex] = (char) (i | (in[offset] & 0x3f));
-                offset++;
-                outputIndex++;
-            } else if(i < 0xf0) {
-                // The result is: 5 least-significant bits of i + 6 l-s bits of next input byte
-                // + 6 l-s of next to next input byte.
-                i = (i & 0x1f) << 12;
-                // Make sure there are are at least two bytes left.
-                if (offset + 1 >= limitIndex) {
-                    throw new UTFDataFormatException("unexpected end of input");
-                }
-                // Include 6 least-significant bits of the input byte, with 6 bits of room
-                // for the next byte.
-                if ((in[offset] & 0xc0) != 0x80) {
-                    throw new UTFDataFormatException("bad second byte at " + offset);
-                }
-                i = i | (in[offset] & 0x3f) << 6;
-                offset++;
-                // Include 6 least-significant bits of the input byte.
-                if ((in[offset] & 0xc0) != 0x80) {
-                    throw new UTFDataFormatException("bad third byte at " + offset);
-                }
-                out[outputIndex] = (char) (i | (in[offset] & 0x3f));
-                offset++;
-                outputIndex++;
-            } else {
-                throw new UTFDataFormatException("Invalid UTF8 byte "
-                        + (int) i + " at position " + (offset - 1));
-            }
-        }
-        return String.valueOf(out, 0, outputIndex);
-    }
-}
diff --git a/luni/src/main/java/javax/xml/TEST_MAPPING b/luni/src/main/java/javax/xml/TEST_MAPPING
new file mode 100644
index 0000000..d8c9759
--- /dev/null
+++ b/luni/src/main/java/javax/xml/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.xml"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/javax/xml/parsers/TEST_MAPPING b/luni/src/main/java/javax/xml/parsers/TEST_MAPPING
new file mode 100644
index 0000000..a630fe1
--- /dev/null
+++ b/luni/src/main/java/javax/xml/parsers/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.javax.xml.parsers"
+        },
+        {
+          "include-filter": "libcore.javax.xml.parsers"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/content/type/MimeMap.java b/luni/src/main/java/libcore/content/type/MimeMap.java
new file mode 100644
index 0000000..51e792f
--- /dev/null
+++ b/luni/src/main/java/libcore/content/type/MimeMap.java
@@ -0,0 +1,408 @@
+/*
+ * 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 libcore.content.type;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Supplier;
+import libcore.api.CorePlatformApi;
+import libcore.util.NonNull;
+import libcore.util.Nullable;
+
+/**
+ * Maps from MIME types to file extensions and back.
+ *
+ * @hide
+ */
+@libcore.api.CorePlatformApi
+public final class MimeMap {
+
+    @CorePlatformApi
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    @CorePlatformApi
+    public Builder buildUpon() {
+        return new Builder(mimeToExt, extToMime);
+    }
+
+    // Contain only lowercase, valid keys/values.
+    private final Map<String, String> mimeToExt;
+    private final Map<String, String> extToMime;
+
+    /**
+     * A basic implementation of MimeMap used if a new default isn't explicitly
+     * {@link MimeMap#setDefaultSupplier(Supplier) installed}. Hard-codes enough
+     * mappings to satisfy libcore tests. Android framework code is expected to
+     * replace this implementation during runtime initialization.
+     */
+    private static volatile MemoizingSupplier<@NonNull MimeMap> instanceSupplier =
+            new MemoizingSupplier<>(
+                    () -> builder()
+                            .put("application/pdf", "pdf")
+                            .put("image/jpeg", "jpg")
+                            .put("image/x-ms-bmp", "bmp")
+                            .put("text/html", Arrays.asList("htm", "html"))
+                            .put("text/plain", Arrays.asList("text", "txt"))
+                            .put("text/x-java", "java")
+                            .build());
+
+    private MimeMap(Map<String, String> mimeToExt, Map<String, String> extToMime) {
+        this.mimeToExt = Objects.requireNonNull(mimeToExt);
+        this.extToMime = Objects.requireNonNull(extToMime);
+        for (Map.Entry<String, String> entry : this.mimeToExt.entrySet()) {
+            checkValidMimeType(entry.getKey());
+            checkValidExtension(entry.getValue());
+        }
+        for (Map.Entry<String, String> entry : this.extToMime.entrySet()) {
+            checkValidExtension(entry.getKey());
+            checkValidMimeType(entry.getValue());
+        }
+    }
+
+    /**
+     * @return The system's current default {@link MimeMap}.
+     */
+    @libcore.api.CorePlatformApi
+    public static @NonNull MimeMap getDefault() {
+        return Objects.requireNonNull(instanceSupplier.get());
+    }
+
+    /**
+     * Sets the {@link Supplier} of the {@link #getDefault() default MimeMap
+     * instance} to be used from now on.
+     *
+     * {@code mimeMapSupplier.get()} will be invoked only the first time that
+     * {@link #getDefault()} is called after this method call; that
+     * {@link MimeMap} instance is memoized such that subsequent calls to
+     * {@link #getDefault()} without an intervening call to
+     * {@link #setDefaultSupplier(Supplier)} will return that same instance
+     * without consulting {@code mimeMapSupplier} a second time.
+     */
+    @libcore.api.CorePlatformApi
+    public static void setDefaultSupplier(@NonNull Supplier<@NonNull MimeMap> mimeMapSupplier) {
+        instanceSupplier = new MemoizingSupplier<>(Objects.requireNonNull(mimeMapSupplier));
+    }
+
+    /**
+     * Returns whether the given case insensitive extension has a registered MIME type.
+     *
+     * @param extension A file extension without the leading '.'
+     * @return Whether a MIME type has been registered for the given case insensitive file
+     *         extension.
+     */
+    @libcore.api.CorePlatformApi
+    public final boolean hasExtension(@Nullable String extension) {
+        return guessMimeTypeFromExtension(extension) != null;
+    }
+
+    /**
+     * Returns the MIME type for the given case insensitive file extension, or null
+     * if the extension isn't mapped to any.
+     *
+     * @param extension A file extension without the leading '.'
+     * @return The lower-case MIME type registered for the given case insensitive file extension,
+     *         or null if there is none.
+     */
+    @libcore.api.CorePlatformApi
+    public final @Nullable String guessMimeTypeFromExtension(@Nullable String extension) {
+        if (extension == null) {
+            return null;
+        }
+        extension = toLowerCase(extension);
+        return extToMime.get(extension);
+    }
+
+    /**
+     * @param mimeType A MIME type (i.e. {@code "text/plain")
+     * @return Whether the given case insensitive MIME type is
+     *         {@link #guessMimeTypeFromExtension(String) mapped} to a file extension.
+     */
+    @libcore.api.CorePlatformApi
+    public final boolean hasMimeType(@Nullable String mimeType) {
+        return guessExtensionFromMimeType(mimeType) != null;
+    }
+
+    /**
+     * Returns the registered extension for the given case insensitive MIME type. Note that some
+     * MIME types map to multiple extensions. This call will return the most
+     * common extension for the given MIME type.
+     * @param mimeType A MIME type (i.e. text/plain)
+     * @return The lower-case file extension (without the leading "." that has been registered for
+     *         the given case insensitive MIME type, or null if there is none.
+     */
+    @libcore.api.CorePlatformApi
+    public final @Nullable String guessExtensionFromMimeType(@Nullable String mimeType) {
+        if (mimeType == null) {
+            return null;
+        }
+        mimeType = toLowerCase(mimeType);
+        return mimeToExt.get(mimeType);
+    }
+
+    /**
+     * Returns the set of MIME types that this {@link MimeMap}
+     * {@link #hasMimeType(String) maps to some extension}. Note that the
+     * reverse mapping might not exist.
+     *
+     * @hide
+     */
+    @libcore.api.CorePlatformApi
+    public @NonNull Set<String> mimeTypes() {
+        return Collections.unmodifiableSet(mimeToExt.keySet());
+    }
+
+    /**
+     * Returns the set of extensions that this {@link MimeMap}
+     * {@link #hasExtension(String) maps to some MIME type}. Note that the
+     * reverse mapping might not exist.
+     *
+     * @hide
+     */
+    @libcore.api.CorePlatformApi
+    public @NonNull Set<String> extensions() {
+        return Collections.unmodifiableSet(extToMime.keySet());
+    }
+
+    /**
+     * Returns the canonical (lowercase) form of the given extension or MIME type.
+     */
+    private static @NonNull String toLowerCase(@NonNull String s) {
+        return s.toLowerCase(Locale.ROOT);
+    }
+
+    private volatile int hashCode = 0;
+
+    @Override
+    public int hashCode() {
+        if (hashCode == 0) { // potentially uninitialized
+            hashCode = mimeToExt.hashCode() + 31 * extToMime.hashCode();
+        }
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof MimeMap)) {
+            return false;
+        }
+        MimeMap that = (MimeMap) obj;
+        if (hashCode() != that.hashCode()) {
+            return false;
+        }
+        return mimeToExt.equals(that.mimeToExt) && extToMime.equals(that.extToMime);
+    }
+
+    @Override
+    public String toString() {
+        return "MimeMap[" + mimeToExt + ", " + extToMime + "]";
+    }
+
+    /**
+     * @hide
+     */
+    @libcore.api.CorePlatformApi
+    public static final class Builder {
+        private final Map<String, String> mimeToExt;
+        private final Map<String, String> extToMime;
+
+        /**
+         * Constructs a Builder that starts with an empty mapping.
+         */
+        Builder() {
+            this.mimeToExt = new HashMap<>();
+            this.extToMime = new HashMap<>();
+        }
+
+        /**
+         * Constructs a Builder that starts with the given mapping.
+         * @param mimeToExt
+         * @param extToMime
+         */
+        Builder(Map<String, String> mimeToExt, Map<String, String> extToMime) {
+            this.mimeToExt = new HashMap<>(mimeToExt);
+            this.extToMime = new HashMap<>(extToMime);
+        }
+
+        /**
+         * An element of a *mime.types file.
+         */
+        static class Element {
+            final String mimeOrExt;
+            final boolean keepExisting;
+
+            /**
+             * @param spec A MIME type or an extension, with an optional
+             *        prefix of "?" (if not overriding an earlier value).
+             * @param isMimeSpec whether this Element denotes a MIME type (as opposed to an
+             *        extension).
+             */
+            private Element(String spec, boolean isMimeSpec) {
+                if (spec.startsWith("?")) {
+                    this.keepExisting = true;
+                    this.mimeOrExt = toLowerCase(spec.substring(1));
+                } else {
+                    this.keepExisting = false;
+                    this.mimeOrExt = toLowerCase(spec);
+                }
+                if (isMimeSpec) {
+                    checkValidMimeType(mimeOrExt);
+                } else {
+                    checkValidExtension(mimeOrExt);
+                }
+            }
+
+            public static Element ofMimeSpec(String s) { return new Element(s, true); }
+            public static Element ofExtensionSpec(String s) { return new Element(s, false); }
+        }
+
+        private static String maybePut(Map<String, String> map, Element keyElement, String value) {
+            if (keyElement.keepExisting) {
+                return map.putIfAbsent(keyElement.mimeOrExt, value);
+            } else {
+                return map.put(keyElement.mimeOrExt, value);
+            }
+        }
+
+        /**
+         * Puts the mapping {@quote mimeType -> first extension}, and also the mappings
+         * {@quote extension -> mimeType} for each given extension.
+         *
+         * The values passed to this function are carry an optional  prefix of {@quote "?"}
+         * which is stripped off in any case before any such key/value is added to a mapping.
+         * The prefix {@quote "?"} controls whether the mapping <i>from></i> the corresponding
+         * value is added via {@link Map#putIfAbsent} semantics ({@quote "?"}
+         * present) vs. {@link Map#put} semantics ({@quote "?" absent}),
+         *
+         * For example, {@code put("text/html", "?htm", "html")} would add the following
+         * mappings:
+         * <ol>
+         *   <li>MIME type "text/html" -> extension "htm", overwriting any earlier mapping
+         *       from MIME type "text/html" that might already have existed.</li>
+         *   <li>extension "htm" -> MIME type "text/html", but only if no earlier mapping
+         *       for extension "htm" existed.</li>
+         *   <li>extension "html" -> MIME type "text/html", overwriting any earlier mapping
+         *       from extension "html" that might already have existed.</li>
+         * </ol>
+         * {@code put("?text/html", "?htm", "html")} would have the same effect except
+         * that an earlier mapping from MIME type {@code "text/html"} would not be
+         * overwritten.
+         *
+         * @param mimeSpec A MIME type carrying an optional prefix of {@code "?"}. If present,
+         *                 the {@code "?"} is stripped off and mapping for the resulting MIME
+         *                 type is only added to the map if no mapping had yet existed for that
+         *                 type.
+         * @param extensionSpecs The extensions from which to add mappings back to
+         *                 the {@code "?"} is stripped off and mapping for the resulting extension
+         *                 is only added to the map if no mapping had yet existed for that
+         *                 extension.
+         *                 If {@code extensionSpecs} is empty, then calling this method has no
+         *                 effect on the mapping that is being constructed.
+         * @throws IllegalArgumentException if {@code mimeSpec} or any of the {@code extensionSpecs}
+         *                 are invalid (null, empty, contain ' ', or '?' after an initial '?' has
+         *                 been stripped off).
+         * @return This builder.
+         */
+        @CorePlatformApi
+        public Builder put(@NonNull String mimeSpec, @NonNull List<@NonNull String> extensionSpecs)
+        {
+            Element mimeElement = Element.ofMimeSpec(mimeSpec); // validate mimeSpec unconditionally
+            if (extensionSpecs.isEmpty()) {
+                return this;
+            }
+            Element firstExtensionElement = Element.ofExtensionSpec(extensionSpecs.get(0));
+            maybePut(mimeToExt, mimeElement, firstExtensionElement.mimeOrExt);
+            maybePut(extToMime, firstExtensionElement, mimeElement.mimeOrExt);
+            for (String spec : extensionSpecs.subList(1, extensionSpecs.size())) {
+                Element element = Element.ofExtensionSpec(spec);
+                maybePut(extToMime, element, mimeElement.mimeOrExt);
+            }
+            return this;
+        }
+
+        /**
+         * Convenience method.
+         *
+         * @hide
+         */
+        public Builder put(@NonNull String mimeSpec, @NonNull String extensionSpec) {
+            return put(mimeSpec, Collections.singletonList(extensionSpec));
+        }
+
+        @CorePlatformApi
+        public MimeMap build() {
+            return new MimeMap(mimeToExt, extToMime);
+        }
+
+        @Override
+        public String toString() {
+            return "MimeMap.Builder[" + mimeToExt + ", " + extToMime + "]";
+        }
+    }
+
+    private static boolean isValidMimeTypeOrExtension(String s) {
+        return s != null
+                && !s.isEmpty()
+                && s.indexOf('?') < 0
+                && s.indexOf(' ') < 0
+                && s.indexOf('\t') < 0
+                && s.equals(toLowerCase(s));
+    }
+
+    static void checkValidMimeType(String s) {
+        if (!isValidMimeTypeOrExtension(s) || s.indexOf('/') < 0) {
+            throw new IllegalArgumentException("Invalid MIME type: " + s);
+        }
+    }
+
+    static void checkValidExtension(String s) {
+        if (!isValidMimeTypeOrExtension(s) || s.indexOf('/') >= 0) {
+            throw new IllegalArgumentException("Invalid extension: " + s);
+        }
+    }
+
+    private static final class MemoizingSupplier<T> implements Supplier<T> {
+        private volatile Supplier<T> mDelegate;
+        private volatile T mInstance;
+        private volatile boolean mInitialized = false;
+
+        public MemoizingSupplier(Supplier<T> delegate) {
+            this.mDelegate = delegate;
+        }
+
+        @Override
+        public T get() {
+            if (!mInitialized) {
+                synchronized (this) {
+                    if (!mInitialized) {
+                        mInstance = mDelegate.get();
+                        mDelegate = null;
+                        mInitialized = true;
+                    }
+                }
+            }
+            return mInstance;
+        }
+    }
+}
diff --git a/luni/src/main/java/libcore/content/type/TEST_MAPPING b/luni/src/main/java/libcore/content/type/TEST_MAPPING
new file mode 100644
index 0000000..712f4a2
--- /dev/null
+++ b/luni/src/main/java/libcore/content/type/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.content.type"
+        }
+      ]
+    },
+    {
+      "name": "CtsMimeMapTestCases"
+    }
+  ]
+}
diff --git a/luni/src/main/java/libcore/icu/DateIntervalFormat.java b/luni/src/main/java/libcore/icu/DateIntervalFormat.java
index 9a4f9a0..74aca08 100644
--- a/luni/src/main/java/libcore/icu/DateIntervalFormat.java
+++ b/luni/src/main/java/libcore/icu/DateIntervalFormat.java
@@ -16,10 +16,10 @@
 
 package libcore.icu;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.icu.util.Calendar;
 import android.icu.util.ULocale;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import java.text.FieldPosition;
 import java.util.TimeZone;
 import libcore.util.BasicLruCache;
diff --git a/luni/src/main/java/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index d8d878d..f6e5fed 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -16,7 +16,9 @@
 
 package libcore.icu;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.icu.util.ULocale;
+
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -266,34 +268,6 @@
     return availableLocalesCache.clone();
   }
 
-  public static Locale[] getAvailableBreakIteratorLocales() {
-    return localesFromStrings(getAvailableBreakIteratorLocalesNative());
-  }
-
-  public static Locale[] getAvailableCalendarLocales() {
-    return localesFromStrings(getAvailableCalendarLocalesNative());
-  }
-
-  public static Locale[] getAvailableCollatorLocales() {
-    return localesFromStrings(getAvailableCollatorLocalesNative());
-  }
-
-  public static Locale[] getAvailableDateFormatLocales() {
-    return localesFromStrings(getAvailableDateFormatLocalesNative());
-  }
-
-  public static Locale[] getAvailableDateFormatSymbolsLocales() {
-    return getAvailableDateFormatLocales();
-  }
-
-  public static Locale[] getAvailableDecimalFormatSymbolsLocales() {
-    return getAvailableNumberFormatLocales();
-  }
-
-  public static Locale[] getAvailableNumberFormatLocales() {
-    return localesFromStrings(getAvailableNumberFormatLocalesNative());
-  }
-
   @UnsupportedAppUsage
   @libcore.api.CorePlatformApi
   public static String getBestDateTimePattern(String skeleton, Locale locale) {
@@ -355,115 +329,38 @@
     return result;
   }
 
-  /**
-   * Returns the version of the CLDR data in use, such as "22.1.1".
-   */
-  public static native String getCldrVersion();
-
-  /**
-   * Returns the icu4c version in use, such as "50.1.1".
-   */
-  public static native String getIcuVersion();
-
-  /**
-   * Returns the Unicode version our ICU supports, such as "6.2".
-   */
-  public static native String getUnicodeVersion();
-
-  // --- Case mapping.
-
-  public static String toLowerCase(String s, Locale locale) {
-    return toLowerCase(s, locale.toLanguageTag());
-  }
-
-  private static native String toLowerCase(String s, String languageTag);
-
-  public static String toUpperCase(String s, Locale locale) {
-    return toUpperCase(s, locale.toLanguageTag());
-  }
-
-  private static native String toUpperCase(String s, String languageTag);
-
   // --- Errors.
 
-  // Just the subset of error codes needed by CharsetDecoderICU/CharsetEncoderICU.
-  public static final int U_ZERO_ERROR = 0;
-  public static final int U_INVALID_CHAR_FOUND = 10;
-  public static final int U_TRUNCATED_CHAR_FOUND = 11;
-  public static final int U_ILLEGAL_CHAR_FOUND = 12;
-  public static final int U_BUFFER_OVERFLOW_ERROR = 15;
-
-  public static boolean U_FAILURE(int error) {
-    return error > U_ZERO_ERROR;
-  }
-
   // --- Native methods accessing ICU's database.
 
-  private static native String[] getAvailableBreakIteratorLocalesNative();
-  private static native String[] getAvailableCalendarLocalesNative();
-  private static native String[] getAvailableCollatorLocalesNative();
-  private static native String[] getAvailableDateFormatLocalesNative();
   private static native String[] getAvailableLocalesNative();
-  private static native String[] getAvailableNumberFormatLocalesNative();
 
-  public static native String[] getAvailableCurrencyCodes();
   public static native String getCurrencyCode(String countryCode);
 
-  public static String getCurrencyDisplayName(Locale locale, String currencyCode) {
-    return getCurrencyDisplayName(locale.toLanguageTag(), currencyCode);
-  }
-
-  private static native String getCurrencyDisplayName(String languageTag, String currencyCode);
-
-  public static native int getCurrencyFractionDigits(String currencyCode);
-  public static native int getCurrencyNumericCode(String currencyCode);
-
-  public static String getCurrencySymbol(Locale locale, String currencyCode) {
-    return getCurrencySymbol(locale.toLanguageTag(), currencyCode);
-  }
-
-  private static native String getCurrencySymbol(String languageTag, String currencyCode);
-
-  public static String getDisplayCountry(Locale targetLocale, Locale locale) {
-    return getDisplayCountryNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
-  }
-
-  private static native String getDisplayCountryNative(String targetLanguageTag, String languageTag);
-
-  public static String getDisplayLanguage(Locale targetLocale, Locale locale) {
-    return getDisplayLanguageNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
-  }
-
-  private static native String getDisplayLanguageNative(String targetLanguageTag, String languageTag);
-
-  public static String getDisplayVariant(Locale targetLocale, Locale locale) {
-    return getDisplayVariantNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
-  }
-
-  private static native String getDisplayVariantNative(String targetLanguageTag, String languageTag);
-
-  public static String getDisplayScript(Locale targetLocale, Locale locale) {
-    return getDisplayScriptNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
-  }
-
-  private static native String getDisplayScriptNative(String targetLanguageTag, String languageTag);
-
   public static native String getISO3Country(String languageTag);
 
   public static native String getISO3Language(String languageTag);
 
-  @UnsupportedAppUsage
-  @libcore.api.CorePlatformApi
-  public static Locale addLikelySubtags(Locale locale) {
-      return Locale.forLanguageTag(addLikelySubtags(locale.toLanguageTag()).replace('_', '-'));
-  }
-
   /**
-   * @deprecated use {@link #addLikelySubtags(java.util.Locale)} instead.
+   * @deprecated Use {@link android.icu.util.ULocale#addLikelySubtags(ULocale)} instead.
+   * The method is only kept for @UnsupportedAppUsage.
    */
   @UnsupportedAppUsage
   @Deprecated
-  public static native String addLikelySubtags(String locale);
+  public static Locale addLikelySubtags(Locale locale) {
+      return ULocale.addLikelySubtags(ULocale.forLocale(locale)).toLocale();
+  }
+
+  /**
+   * @return ICU localeID
+   * @deprecated Use {@link android.icu.util.ULocale#addLikelySubtags(ULocale)} instead.
+   * The method is only kept for @UnsupportedAppUsage.
+   */
+  @UnsupportedAppUsage
+  @Deprecated
+  public static String addLikelySubtags(String locale) {
+      return ULocale.addLikelySubtags(new ULocale(locale)).getName();
+  }
 
   /**
    * @deprecated use {@link java.util.Locale#getScript()} instead. This has been kept
@@ -487,8 +384,4 @@
    * Returns a locale name, not a BCP-47 language tag. e.g. en_US not en-US.
    */
   public static native String getDefaultLocale();
-
-  /** Returns the TZData version as reported by ICU4C. */
-  @libcore.api.CorePlatformApi
-  public static native String getTZDataVersion();
 }
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index cf3fec0..12b978de 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -16,11 +16,17 @@
 
 package libcore.icu;
 
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.compat.Compatibility;
 import android.icu.impl.ICUData;
 import android.icu.impl.ICUResourceBundle;
 import android.icu.text.NumberingSystem;
 import android.icu.util.UResourceBundle;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+
+import dalvik.system.VMRuntime;
+
 import java.text.DateFormat;
 import java.util.HashMap;
 import java.util.Locale;
@@ -37,6 +43,44 @@
  */
 @libcore.api.CorePlatformApi
 public final class LocaleData {
+
+    /**
+     * @see #USE_REAL_ROOT_LOCALE
+     */
+    private static final Locale LOCALE_EN_US_POSIX = new Locale("en", "US", "POSIX");
+
+    // In Android Q or before, when this class tries to load {@link Locale#ROOT} data, en_US_POSIX
+    // locale data is incorrectly loaded due to a bug b/159514442 (public bug b/159047832).
+    //
+    // This class used to pass "und" string as BCP47 language tag to our jni code, which then
+    // passes the string as as ICU Locale ID to ICU4C. ICU4C 63 or older version doesn't recognize
+    // "und" as a valid locale id, and fallback the default locale. The default locale is
+    // normally selected in the Locale picker in the Settings app by the user and set via
+    // frameworks. But this class statically cached the ROOT locale data before the
+    // default locale being set by framework, and without initialization, ICU4C uses en_US_POSIX
+    // as default locale. Thus, in Q or before, en_US_POSIX data is loaded.
+    //
+    // ICU version 64.1 resolved inconsistent behavior of
+    // "root", "und" and "" (empty) Locale ID which libcore previously relied on, and they are
+    // recognized correctly as {@link Locale#ROOT} since Android R. This ChangeId gated the change,
+    // and fallback to the old behavior by checking targetSdkVersion version.
+    //
+    // The below javadoc is shown in http://developer.android.com for consumption by app developers.
+    /**
+     * Since Android 11, formatter classes, e.g. java.text.SimpleDateFormat, no longer
+     * provide English data when Locale.ROOT format is requested. Please use
+     * Locale.ENGLISH to format in English.
+     *
+     * Note that Locale.ROOT is used as language/country neutral locale or fallback locale,
+     * and does not guarantee to represent English locale.
+     *
+     * This flag is only for documentation and can't be overridden by app. Please use
+     * {@code targetSdkVersion} to enable the new behavior.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion=29 /* Android Q */)
+    public static final long USE_REAL_ROOT_LOCALE = 159047832L;
+
     // A cache for the locale-specific data.
     private static final HashMap<String, LocaleData> localeDataCache = new HashMap<String, LocaleData>();
     static {
@@ -170,6 +214,25 @@
     }
 
     /**
+     * Normally, this utility function is used by secondary cache above {@link LocaleData},
+     * because the cache needs a correct key.
+     * @see #USE_REAL_ROOT_LOCALE
+     * @return a compatible locale for the bug b/159514442
+     */
+    public static Locale getCompatibleLocaleForBug159514442(Locale locale) {
+        if (Locale.ROOT.equals(locale)) {
+            int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+            // Don't use Compatibility.isChangeEnabled(USE_REAL_ROOT_LOCALE) because the app compat
+            // framework lives in libcore and can depend on this class via various format methods,
+            // e.g. String.format(). See b/160912695.
+            if (targetSdkVersion <= 29 /* Android Q */) {
+                locale = LOCALE_EN_US_POSIX;
+            }
+        }
+        return locale;
+    }
+
+    /**
      * Returns a shared LocaleData for the given locale.
      */
     @UnsupportedAppUsage
@@ -179,6 +242,8 @@
             throw new NullPointerException("locale == null");
         }
 
+        locale = getCompatibleLocaleForBug159514442(locale);
+
         final String languageTag = locale.toLanguageTag();
         synchronized (localeDataCache) {
             LocaleData localeData = localeDataCache.get(languageTag);
diff --git a/luni/src/main/java/libcore/icu/NativeConverter.java b/luni/src/main/java/libcore/icu/NativeConverter.java
deleted file mode 100644
index 956c701..0000000
--- a/luni/src/main/java/libcore/icu/NativeConverter.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
-*******************************************************************************
-*
-*******************************************************************************
-*/
-
-package libcore.icu;
-
-import libcore.util.NativeAllocationRegistry;
-
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CodingErrorAction;
-
-public final class NativeConverter {
-    private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
-            NativeConverter.class.getClassLoader(), getNativeFinalizer(), getNativeSize());
-
-    public static native int decode(long converterHandle, byte[] input, int inEnd,
-            char[] output, int outEnd, int[] data, boolean flush);
-
-    public static native int encode(long converterHandle, char[] input, int inEnd,
-            byte[] output, int outEnd, int[] data, boolean flush);
-
-    public static native long openConverter(String charsetName);
-    public static native void closeConverter(long converterHandle);
-
-    public static void registerConverter(Object referrent, long converterHandle) {
-        registry.registerNativeAllocation(referrent, converterHandle);
-    }
-
-    public static native void resetByteToChar(long converterHandle);
-    public static native void resetCharToByte(long converterHandle);
-
-    public static native byte[] getSubstitutionBytes(long converterHandle);
-
-    public static native int getMaxBytesPerChar(long converterHandle);
-    public static native int getMinBytesPerChar(long converterHandle);
-    public static native float getAveBytesPerChar(long converterHandle);
-    public static native float getAveCharsPerByte(long converterHandle);
-
-    public static native boolean contains(String converterName1, String converterName2);
-
-    public static native String[] getAvailableCharsetNames();
-    public static native Charset charsetForName(String charsetName);
-
-    // Translates from Java's enum to the magic numbers #defined in "NativeConverter.cpp".
-    private static int translateCodingErrorAction(CodingErrorAction action) {
-        if (action == CodingErrorAction.REPORT) {
-            return 0;
-        } else if (action == CodingErrorAction.IGNORE) {
-            return 1;
-        } else if (action == CodingErrorAction.REPLACE) {
-            return 2;
-        } else {
-            throw new AssertionError(); // Someone changed the enum.
-        }
-    }
-
-    public static void setCallbackDecode(long converterHandle, CharsetDecoder decoder) {
-        setCallbackDecode(converterHandle,
-                          translateCodingErrorAction(decoder.malformedInputAction()),
-                          translateCodingErrorAction(decoder.unmappableCharacterAction()),
-                          decoder.replacement());
-    }
-    private static native void setCallbackDecode(long converterHandle, int onMalformedInput, int onUnmappableInput, String subChars);
-
-    public static void setCallbackEncode(long converterHandle, CharsetEncoder encoder) {
-        setCallbackEncode(converterHandle,
-                          translateCodingErrorAction(encoder.malformedInputAction()),
-                          translateCodingErrorAction(encoder.unmappableCharacterAction()),
-                          encoder.replacement());
-    }
-    private static native void setCallbackEncode(long converterHandle, int onMalformedInput, int onUnmappableInput, byte[] subBytes);
-
-    public static native long getNativeFinalizer();
-    public static native long getNativeSize();
-}
diff --git a/luni/src/main/java/libcore/icu/TEST_MAPPING b/luni/src/main/java/libcore/icu/TEST_MAPPING
new file mode 100644
index 0000000..f3a0de8
--- /dev/null
+++ b/luni/src/main/java/libcore/icu/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.icu"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/icu/TimeZoneNames.java b/luni/src/main/java/libcore/icu/TimeZoneNames.java
index caeaefd..ec0fb8e 100644
--- a/luni/src/main/java/libcore/icu/TimeZoneNames.java
+++ b/luni/src/main/java/libcore/icu/TimeZoneNames.java
@@ -16,7 +16,6 @@
 
 package libcore.icu;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -24,7 +23,6 @@
 import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
 import libcore.util.BasicLruCache;
-import libcore.timezone.ZoneInfoDB;
 
 /**
  * Provides access to ICU's time zone name data.
@@ -36,17 +34,16 @@
     /*
      * Offsets into the arrays returned by DateFormatSymbols.getZoneStrings.
      */
-    public static final int OLSON_NAME = 0;
-    public static final int LONG_NAME = 1;
-    public static final int SHORT_NAME = 2;
-    public static final int LONG_NAME_DST = 3;
-    public static final int SHORT_NAME_DST = 4;
-    public static final int NAME_COUNT = 5;
+    private static final int OLSON_NAME = 0;
+    private static final int LONG_NAME = 1;
+    private static final int SHORT_NAME = 2;
+    private static final int LONG_NAME_DST = 3;
+    private static final int SHORT_NAME_DST = 4;
+    private static final int NAME_COUNT = 5;
 
     private static final ZoneStringsCache cachedZoneStrings = new ZoneStringsCache();
 
-    /** @hide */
-    public static class ZoneStringsCache extends BasicLruCache<Locale, String[][]> {
+    private static class ZoneStringsCache extends BasicLruCache<Locale, String[][]> {
         public ZoneStringsCache() {
             super(5); // Room for a handful of locales.
         }
diff --git a/luni/src/main/java/libcore/internal/TEST_MAPPING b/luni/src/main/java/libcore/internal/TEST_MAPPING
new file mode 100644
index 0000000..3ddd13a
--- /dev/null
+++ b/luni/src/main/java/libcore/internal/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.internal"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java b/luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java
index 76ef5e4..49d71a0 100644
--- a/luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java
+++ b/luni/src/main/java/libcore/io/AsynchronousCloseMonitor.java
@@ -16,13 +16,21 @@
 
 package libcore.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+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/io/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index bd95a93..f3793d6 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -16,6 +16,7 @@
 
 package libcore.io;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 import android.system.GaiException;
 import android.system.Int64Ref;
@@ -25,9 +26,7 @@
 import android.system.StructPollfd;
 import android.system.StructStat;
 import android.system.StructStatVfs;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.BlockGuard;
-import dalvik.system.SocketTagger;
+
 import java.io.FileDescriptor;
 import java.io.InterruptedIOException;
 import java.net.InetAddress;
@@ -36,6 +35,9 @@
 import java.net.SocketException;
 import java.nio.ByteBuffer;
 
+import dalvik.system.BlockGuard;
+import dalvik.system.SocketTagger;
+
 import static android.system.OsConstants.*;
 
 /**
diff --git a/luni/src/main/java/libcore/io/BufferIterator.java b/luni/src/main/java/libcore/io/BufferIterator.java
index b7c5b38..fb97250 100644
--- a/luni/src/main/java/libcore/io/BufferIterator.java
+++ b/luni/src/main/java/libcore/io/BufferIterator.java
@@ -16,7 +16,7 @@
 
 package libcore.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Iterates over big- or little-endian bytes. See {@link MemoryMappedFile#bigEndianIterator} and
@@ -44,13 +44,13 @@
     public abstract int pos();
 
     /**
-     * Copies {@code byteCount} bytes from the current position into {@code dst}, starting at
-     * {@code dstOffset}, and advances the current position {@code byteCount} bytes.
+     * Copies {@code byteCount} bytes from the current position into {@code bytes}, starting at
+     * {@code arrayOffset}, and advances the current position {@code byteCount} bytes.
      *
      * @throws IndexOutOfBoundsException if the read / write would be outside of the buffer / array
      */
     @UnsupportedAppUsage
-    public abstract void readByteArray(byte[] dst, int dstOffset, int byteCount);
+    public abstract void readByteArray(byte[] bytes, int arrayOffset, int byteCount);
 
     /**
      * Returns the byte at the current position, and advances the current position one byte.
@@ -69,13 +69,21 @@
     public abstract int readInt();
 
     /**
-     * Copies {@code intCount} 32-bit ints from the current position into {@code dst}, starting at
-     * {@code dstOffset}, and advances the current position {@code 4 * intCount} bytes.
+     * Copies {@code intCount} 32-bit ints from the current position into {@code ints}, starting at
+     * {@code arrayOffset}, and advances the current position {@code 4 * intCount} bytes.
      *
      * @throws IndexOutOfBoundsException if the read / write would be outside of the buffer / array
      */
     @UnsupportedAppUsage
-    public abstract void readIntArray(int[] dst, int dstOffset, int intCount);
+    public abstract void readIntArray(int[] ints, int arrayOffset, int intCount);
+
+    /**
+     * Copies {@code longCount} 64-bit ints from the current position into {@code longs}, starting
+     * at {@code arrayOffset}, and advances the current position {@code 8 * longCount} bytes.
+     *
+     * @throws IndexOutOfBoundsException if the read / write would be outside of the buffer / array
+     */
+    public abstract void readLongArray(long[] longs, int arrayOffset, int longCount);
 
     /**
      * Returns the 16-bit short at the current position, and advances the current position two bytes.
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index 1c1dec2..f9fb2d4 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -23,7 +23,6 @@
 import android.system.StructAddrinfo;
 import android.system.StructCapUserData;
 import android.system.StructCapUserHeader;
-import android.system.StructFlock;
 import android.system.StructGroupReq;
 import android.system.StructIfaddrs;
 import android.system.StructLinger;
@@ -36,7 +35,7 @@
 import android.system.StructUcred;
 import android.system.StructUtsname;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.io.FileDescriptor;
 import java.io.InterruptedIOException;
 import java.net.InetAddress;
@@ -101,7 +100,6 @@
     public void execve(String filename, String[] argv, String[] envp) throws ErrnoException { os.execve(filename, argv, envp); }
     public void fchmod(FileDescriptor fd, int mode) throws ErrnoException { os.fchmod(fd, mode); }
     public void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException { os.fchown(fd, uid, gid); }
-    public int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException { return os.fcntlFlock(fd, cmd, arg); }
     public int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException { return os.fcntlInt(fd, cmd, arg); }
     public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException { return os.fcntlVoid(fd, cmd); }
     public void fdatasync(FileDescriptor fd) throws ErrnoException { os.fdatasync(fd); }
@@ -152,6 +150,7 @@
     public long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException { return os.lseek(fd, offset, whence); }
     @UnsupportedAppUsage
     public StructStat lstat(String path) throws ErrnoException { return os.lstat(path); }
+    public FileDescriptor memfd_create(String name, int flags) throws ErrnoException { return os.memfd_create(name, flags); }
     public void mincore(long address, long byteCount, byte[] vector) throws ErrnoException { os.mincore(address, byteCount, vector); }
     @UnsupportedAppUsage
     public void mkdir(String path, int mode) throws ErrnoException { os.mkdir(path, mode); }
diff --git a/luni/src/main/java/libcore/io/IoBridge.java b/luni/src/main/java/libcore/io/IoBridge.java
index 0631176..0554d6d 100644
--- a/luni/src/main/java/libcore/io/IoBridge.java
+++ b/luni/src/main/java/libcore/io/IoBridge.java
@@ -16,6 +16,7 @@
 
 package libcore.io;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 import android.system.Int32Ref;
 import android.system.StructGroupReq;
@@ -23,9 +24,6 @@
 import android.system.StructPollfd;
 import android.system.StructTimeval;
 
-import libcore.util.ArrayUtils;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -46,6 +44,7 @@
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.util.concurrent.TimeUnit;
+import libcore.util.ArrayUtils;
 
 import static android.system.OsConstants.*;
 
@@ -470,16 +469,13 @@
     /**
      * java.io only throws FileNotFoundException when opening files, regardless of what actually
      * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening
-     * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also
-     * have an Android-specific hack to alter the default permissions.
+     * directories: POSIX says read-only is okay, but java.io doesn't even allow that.
      */
     @libcore.api.CorePlatformApi
     public static FileDescriptor open(String path, int flags) throws FileNotFoundException {
         FileDescriptor fd = null;
         try {
-            // On Android, we don't want default permissions to allow global access.
-            int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600;
-            fd = Libcore.os.open(path, flags, mode);
+            fd = Libcore.os.open(path, flags, 0666);
             // Posix open(2) fails with EISDIR only if you ask for write permission.
             // Java disallows reading directories too.
             if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) {
diff --git a/luni/src/main/java/libcore/io/IoUtils.java b/luni/src/main/java/libcore/io/IoUtils.java
index 564393b..4b4870b 100644
--- a/luni/src/main/java/libcore/io/IoUtils.java
+++ b/luni/src/main/java/libcore/io/IoUtils.java
@@ -16,8 +16,10 @@
 
 package libcore.io;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
 import android.system.StructStat;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
@@ -27,10 +29,12 @@
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.Objects;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import libcore.util.NonNull;
-import static android.system.OsConstants.*;
+
+import static android.system.OsConstants.F_GETFL;
+import static android.system.OsConstants.F_SETFL;
+import static android.system.OsConstants.O_NONBLOCK;
+import static android.system.OsConstants.O_RDONLY;
 
 /** @hide */
 @libcore.api.CorePlatformApi
@@ -257,23 +261,6 @@
     }
 
     /**
-     * Creates a unique new temporary directory under "java.io.tmpdir".
-     *
-     * @deprecated Use {@link TestIoUtils#createTemporaryDirectory} instead.
-     */
-    @libcore.api.CorePlatformApi
-    @Deprecated
-    public static File createTemporaryDirectory(String prefix) {
-        while (true) {
-            String candidateName = prefix + Math.randomIntInternal();
-            File result = new File(System.getProperty("java.io.tmpdir"), candidateName);
-            if (result.mkdir()) {
-                return result;
-            }
-        }
-    }
-
-    /**
      * Do not use. This is for System.loadLibrary use only.
      *
      * Checks whether {@code path} can be opened read-only. Similar to File.exists, but doesn't
diff --git a/luni/src/main/java/libcore/io/Libcore.java b/luni/src/main/java/libcore/io/Libcore.java
index 823d866..29b5f7f 100644
--- a/luni/src/main/java/libcore/io/Libcore.java
+++ b/luni/src/main/java/libcore/io/Libcore.java
@@ -16,7 +16,7 @@
 
 package libcore.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.util.Objects;
 
 /** @hide */
diff --git a/luni/src/main/java/libcore/io/Linux.java b/luni/src/main/java/libcore/io/Linux.java
index 3766ac1..74608d3 100644
--- a/luni/src/main/java/libcore/io/Linux.java
+++ b/luni/src/main/java/libcore/io/Linux.java
@@ -23,7 +23,6 @@
 import android.system.StructAddrinfo;
 import android.system.StructCapUserData;
 import android.system.StructCapUserHeader;
-import android.system.StructFlock;
 import android.system.StructGroupReq;
 import android.system.StructIfaddrs;
 import android.system.StructLinger;
@@ -76,7 +75,6 @@
     public native void execve(String filename, String[] argv, String[] envp) throws ErrnoException;
     public native void fchmod(FileDescriptor fd, int mode) throws ErrnoException;
     public native void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException;
-    public native int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException;
     public native int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException;
     public native int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
     public native void fdatasync(FileDescriptor fd) throws ErrnoException;
@@ -123,6 +121,7 @@
     public native String[] listxattr(String path) throws ErrnoException;
     public native long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException;
     public native StructStat lstat(String path) throws ErrnoException;
+    public native FileDescriptor memfd_create(String name, int flags) throws ErrnoException;
     public native void mincore(long address, long byteCount, byte[] vector) throws ErrnoException;
     public native void mkdir(String path, int mode) throws ErrnoException;
     public native void mkfifo(String path, int mode) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Memory.java b/luni/src/main/java/libcore/io/Memory.java
index 4042300..9e7f4ea 100644
--- a/luni/src/main/java/libcore/io/Memory.java
+++ b/luni/src/main/java/libcore/io/Memory.java
@@ -17,13 +17,12 @@
 
 package libcore.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.annotation.optimization.FastNative;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.nio.ByteBuffer;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.nio.ByteOrder;
 
+import dalvik.annotation.optimization.FastNative;
+
 /**
  * Unsafe access to memory.
  *
diff --git a/luni/src/main/java/libcore/io/MemoryMappedFile.java b/luni/src/main/java/libcore/io/MemoryMappedFile.java
index 20b08e5..5e003ea 100644
--- a/luni/src/main/java/libcore/io/MemoryMappedFile.java
+++ b/luni/src/main/java/libcore/io/MemoryMappedFile.java
@@ -16,17 +16,15 @@
 
 package libcore.io;
 
+import android.compat.annotation.UnsupportedAppUsage;
 import android.system.ErrnoException;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.RandomAccessFile;
 import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
-import java.nio.NioUtils;
-import libcore.io.Libcore;
-import libcore.io.Memory;
-import static android.system.OsConstants.*;
+
+import static android.system.OsConstants.MAP_SHARED;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.PROT_READ;
 
 /**
  * A memory-mapped file. Use {@link #mmapRO} to map a file, {@link #close} to unmap a file,
diff --git a/luni/src/main/java/libcore/io/NioBufferIterator.java b/luni/src/main/java/libcore/io/NioBufferIterator.java
index 263666d..1554519 100644
--- a/luni/src/main/java/libcore/io/NioBufferIterator.java
+++ b/luni/src/main/java/libcore/io/NioBufferIterator.java
@@ -50,10 +50,12 @@
         this.swap = swap;
     }
 
+    @Override
     public void seek(int offset) {
         position = offset;
     }
 
+    @Override
     public void skip(int byteCount) {
         position += byteCount;
     }
@@ -63,14 +65,16 @@
         return position;
     }
 
-    public void readByteArray(byte[] dst, int dstOffset, int byteCount) {
-        checkDstBounds(dstOffset, dst.length, byteCount);
+    @Override
+    public void readByteArray(byte[] bytes, int arrayOffset, int byteCount) {
+        checkArrayBounds(arrayOffset, bytes.length, byteCount);
         file.checkNotClosed();
         checkReadBounds(position, length, byteCount);
-        Memory.peekByteArray(address + position, dst, dstOffset, byteCount);
+        Memory.peekByteArray(address + position, bytes, arrayOffset, byteCount);
         position += byteCount;
     }
 
+    @Override
     public byte readByte() {
         file.checkNotClosed();
         checkReadBounds(position, length, 1);
@@ -79,6 +83,7 @@
         return result;
     }
 
+    @Override
     public int readInt() {
         file.checkNotClosed();
         checkReadBounds(position, length, Integer.BYTES);
@@ -87,15 +92,27 @@
         return result;
     }
 
-    public void readIntArray(int[] dst, int dstOffset, int intCount) {
-        checkDstBounds(dstOffset, dst.length, intCount);
+    @Override
+    public void readIntArray(int[] ints, int arrayOffset, int intCount) {
+        checkArrayBounds(arrayOffset, ints.length, intCount);
         file.checkNotClosed();
         final int byteCount = Integer.BYTES * intCount;
         checkReadBounds(position, length, byteCount);
-        Memory.peekIntArray(address + position, dst, dstOffset, intCount, swap);
+        Memory.peekIntArray(address + position, ints, arrayOffset, intCount, swap);
         position += byteCount;
     }
 
+    @Override
+    public void readLongArray(long[] longs, int arrayOffset, int longCount) {
+        checkArrayBounds(arrayOffset, longs.length, longCount);
+        file.checkNotClosed();
+        final int byteCount = Long.BYTES * longCount;
+        checkReadBounds(position, length, byteCount);
+        Memory.peekLongArray(address + position, longs, arrayOffset, longCount, swap);
+        position += byteCount;
+    }
+
+    @Override
     public short readShort() {
         file.checkNotClosed();
         checkReadBounds(position, length, Short.BYTES);
@@ -118,18 +135,18 @@
         }
     }
 
-    private static void checkDstBounds(int dstOffset, int dstLength, int count) {
-        if (dstOffset < 0 || count < 0) {
+    private static void checkArrayBounds(int arrayOffset, int arrayLength, int count) {
+        if (arrayOffset < 0 || count < 0) {
             throw new IndexOutOfBoundsException(
-                    "Invalid dst args: offset=" + dstLength + ", count=" + count);
+                    "Invalid args: arrayOffset=" + arrayOffset + ", count=" + count);
         }
-        // Use of int here relies on dstLength being an int <= Integer.MAX_VALUE, which it has to
+        // Use of int here relies on arrayLength being an int <= Integer.MAX_VALUE, which it has to
         // be because it's an array length.
-        final int targetPos = dstOffset + count;
-        if (targetPos < 0 || targetPos > dstLength) {
+        final int targetPos = arrayOffset + count;
+        if (targetPos < 0 || targetPos > arrayLength) {
             throw new IndexOutOfBoundsException(
-                    "Write outside range: dst.length=" + dstLength + ", offset="
-                            + dstOffset + ", count=" + count);
+                    "Write outside range: arrayLength=" + arrayLength + ", arrayOffset="
+                            + arrayOffset + ", count=" + count);
         }
     }
 }
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index e1ffa48..4953186 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -23,7 +23,6 @@
 import android.system.StructAddrinfo;
 import android.system.StructCapUserData;
 import android.system.StructCapUserHeader;
-import android.system.StructFlock;
 import android.system.StructGroupReq;
 import android.system.StructIfaddrs;
 import android.system.StructLinger;
@@ -36,7 +35,7 @@
 import android.system.StructUcred;
 import android.system.StructUtsname;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.io.FileDescriptor;
 import java.io.InterruptedIOException;
 import java.net.InetAddress;
@@ -76,7 +75,6 @@
     public void execve(String filename, String[] argv, String[] envp) throws ErrnoException;
     public void fchmod(FileDescriptor fd, int mode) throws ErrnoException;
     public void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException;
-    public int fcntlFlock(FileDescriptor fd, int cmd, StructFlock arg) throws ErrnoException, InterruptedIOException;
     public int fcntlInt(FileDescriptor fd, int cmd, int arg) throws ErrnoException;
     public int fcntlVoid(FileDescriptor fd, int cmd) throws ErrnoException;
     public void fdatasync(FileDescriptor fd) throws ErrnoException;
@@ -125,6 +123,7 @@
     public String[] listxattr(String path) throws ErrnoException;
     public long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException;
     public StructStat lstat(String path) throws ErrnoException;
+    public FileDescriptor memfd_create(String name, int flags) throws ErrnoException;
     public void mincore(long address, long byteCount, byte[] vector) throws ErrnoException;
     public void mkdir(String path, int mode) throws ErrnoException;
     public void mkfifo(String path, int mode) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Streams.java b/luni/src/main/java/libcore/io/Streams.java
index 4274399..f83f5c1 100644
--- a/luni/src/main/java/libcore/io/Streams.java
+++ b/luni/src/main/java/libcore/io/Streams.java
@@ -16,9 +16,8 @@
 
 package libcore.io;
 
-import libcore.util.ArrayUtils;
+import android.compat.annotation.UnsupportedAppUsage;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
 import java.io.IOException;
@@ -27,6 +26,7 @@
 import java.io.Reader;
 import java.io.StringWriter;
 import java.util.concurrent.atomic.AtomicReference;
+import libcore.util.ArrayUtils;
 
 /** @hide */
 @libcore.api.CorePlatformApi
diff --git a/luni/src/main/java/libcore/io/TEST_MAPPING b/luni/src/main/java/libcore/io/TEST_MAPPING
new file mode 100644
index 0000000..1e25459
--- /dev/null
+++ b/luni/src/main/java/libcore/io/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.io"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/net/MimeUtils.java b/luni/src/main/java/libcore/net/MimeUtils.java
deleted file mode 100644
index 8cd0147..0000000
--- a/luni/src/main/java/libcore/net/MimeUtils.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2010 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.net;
-
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-/**
- * Utilities for dealing with MIME types.
- * Used to implement java.net.URLConnection and android.webkit.MimeTypeMap.
- * @hide
- */
-@libcore.api.CorePlatformApi
-public final class MimeUtils {
-
-    private static final Pattern splitPattern = Pattern.compile("\\s+");
-
-    /**
-     * Note: These maps only contain lowercase keys/values, regarded as the
-     * {@link #canonicalize(String) canonical form}.
-     *
-     * <p>This is the case for both extensions and MIME types. The mime.types
-     * data file contains examples of mixed-case MIME types, but some applications
-     * use the lowercase version of these same types. RFC 2045 section 2 states
-     * that MIME types are case insensitive.
-     */
-    private static final Map<String, String> mimeTypeToExtensionMap = new HashMap<>();
-    private static final Map<String, String> extensionToMimeTypeMap = new HashMap<>();
-
-    static {
-        parseTypes("mime.types");
-        parseTypes("android.mime.types");
-    }
-
-    private static void parseTypes(String resource) {
-        try (BufferedReader r = new BufferedReader(
-                new InputStreamReader(MimeUtils.class.getResourceAsStream(resource)))) {
-            String line;
-            while ((line = r.readLine()) != null) {
-                int commentPos = line.indexOf('#');
-                if (commentPos >= 0) {
-                    line = line.substring(0, commentPos);
-                }
-                line = line.trim();
-                if (line.equals("")) {
-                    continue;
-                }
-
-                final String[] split = splitPattern.split(line);
-                final String mimeType = canonicalize(split[0]);
-                if (!allowedInMap(mimeType)) {
-                    throw new IllegalArgumentException(
-                            "Invalid mimeType " + mimeType + " in: " + line);
-                }
-                for (int i = 1; i < split.length; i++) {
-                    String extension = canonicalize(split[i]);
-                    if (!allowedInMap(extension)) {
-                        throw new IllegalArgumentException(
-                                "Invalid extension " + extension + " in: " + line);
-                    }
-
-                    // Normally the first MIME type definition wins, and the
-                    // last extension definition wins. However, a file can
-                    // override a MIME type definition by adding the "!" suffix
-                    // to an extension.
-
-                    if (extension.endsWith("!")) {
-                        extension = extension.substring(0, extension.length() - 1);
-
-                        // Overriding MIME definition wins
-                        mimeTypeToExtensionMap.put(mimeType, extension);
-                    } else {
-                        // First MIME definition wins
-                        if (!mimeTypeToExtensionMap.containsKey(mimeType)) {
-                            mimeTypeToExtensionMap.put(mimeType, extension);
-                        }
-                    }
-
-                    // Last extension definition wins
-                    extensionToMimeTypeMap.put(extension, mimeType);
-                }
-            }
-        } catch (IOException e) {
-            throw new RuntimeException("Failed to parse " + resource, e);
-        }
-    }
-
-    private MimeUtils() {
-    }
-
-    /**
-     * Returns the canonical (lowercase) form of the given extension or MIME type.
-     */
-    private static String canonicalize(String s) {
-        return s.toLowerCase(Locale.ROOT);
-    }
-
-    /**
-     * Checks whether the given extension or MIME type might be valid and
-     * therefore may appear in the mimeType <-> extension maps.
-     */
-    private static boolean allowedInMap(String s) {
-        return s != null && !s.isEmpty();
-    }
-
-    /**
-     * Returns true if the given case insensitive MIME type has an entry in the map.
-     * @param mimeType A MIME type (i.e. text/plain)
-     * @return True if a extension has been registered for
-     * the given case insensitive MIME type.
-     */
-    @libcore.api.CorePlatformApi
-    public static boolean hasMimeType(String mimeType) {
-        return (guessExtensionFromMimeType(mimeType) != null);
-    }
-
-    /**
-     * Returns the MIME type for the given case insensitive file extension.
-     * @param extension A file extension without the leading '.'
-     * @return The MIME type has been registered for
-     * the given case insensitive file extension or null if there is none.
-     */
-    @UnsupportedAppUsage
-    @libcore.api.CorePlatformApi
-    public static String guessMimeTypeFromExtension(String extension) {
-        if (!allowedInMap(extension)) {
-            return null;
-        }
-        extension = canonicalize(extension);
-        return extensionToMimeTypeMap.get(extension);
-    }
-
-    /**
-     * Returns true if the given case insensitive extension has a registered MIME type.
-     * @param extension A file extension without the leading '.'
-     * @return True if a MIME type has been registered for
-     * the given case insensitive file extension.
-     */
-    @libcore.api.CorePlatformApi
-    public static boolean hasExtension(String extension) {
-        return (guessMimeTypeFromExtension(extension) != null);
-    }
-
-    /**
-     * Returns the registered extension for the given case insensitive MIME type. Note that some
-     * MIME types map to multiple extensions. This call will return the most
-     * common extension for the given MIME type.
-     * @param mimeType A MIME type (i.e. text/plain)
-     * @return The extension has been registered for
-     * the given case insensitive MIME type or null if there is none.
-     */
-    @UnsupportedAppUsage
-    @libcore.api.CorePlatformApi
-    public static String guessExtensionFromMimeType(String mimeType) {
-        if (!allowedInMap(mimeType)) {
-            return null;
-        }
-        mimeType = canonicalize(mimeType);
-        return mimeTypeToExtensionMap.get(mimeType);
-    }
-}
diff --git a/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java b/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java
index 3a3a5d9..1ce58d9 100644
--- a/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java
+++ b/luni/src/main/java/libcore/net/NetworkSecurityPolicy.java
@@ -16,7 +16,7 @@
 
 package libcore.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Network security policy for this process/application.
diff --git a/luni/src/main/java/libcore/net/TEST_MAPPING b/luni/src/main/java/libcore/net/TEST_MAPPING
new file mode 100644
index 0000000..f31705e
--- /dev/null
+++ b/luni/src/main/java/libcore/net/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.net"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.net"
+        }
+      ]
+    }
+  ]
+}
diff --git a/luni/src/main/java/libcore/net/android.mime.types b/luni/src/main/java/libcore/net/android.mime.types
deleted file mode 100644
index 6332489..0000000
--- a/luni/src/main/java/libcore/net/android.mime.types
+++ /dev/null
@@ -1,99 +0,0 @@
-
-###############################################################################
-#
-#  Android-specific MIME type mappings
-#
-#  MIME types that Android has manually added or historically chosen to
-#  override, and which take precidence over any upstream mime.types.
-#
-###############################################################################
-
-application/epub+zip epub
-application/pkix-cert cer
-application/rss+xml rss
-application/vnd.apple.mpegurl m3u8
-application/vnd.ms-pki.stl stl
-application/vnd.ms-powerpoint pot
-application/vnd.ms-wpl wpl
-application/vnd.stardivision.impress sdp
-application/vnd.stardivision.writer vor
-application/vnd.youtube.yt yt
-application/x-android-drm-fl fl
-application/x-flac flac
-application/x-font pcf
-application/x-mpegurl m3u m3u8
-application/x-pem-file pem
-application/x-pkcs12 p12 pfx
-application/x-webarchive webarchive
-application/x-webarchive-xml webarchivexml
-# Note: We rely here on the fact that we're declaring this mapping before the
-# line "text/xml xml" below, because we don't want to change the mapping from
-# extension "xml" back to MIME type "text/xml".
-application/x-wifi-config xml
-application/x-x509-server-cert crt
-application/x-x509-user-cert crt
-
-audio/3gpp 3gpp
-audio/aac-adts aac
-audio/imelody imy
-audio/midi ota rtttl xmf
-audio/mobile-xmf mxmf
-audio/mp4 m4a
-audio/mpegurl m3u
-audio/sp-midi smf
-audio/x-matroska mka
-audio/x-pn-realaudio ra
-
-image/bmp bmp
-image/heic heic
-image/heic-sequence heics
-image/heif heif hif
-image/heif-sequence heifs
-image/ico cur
-image/webp webp
-image/x-adobe-dng dng
-image/x-fuji-raf raf
-image/x-icon ico
-image/x-nikon-nrw nrw
-image/x-panasonic-rw2 rw2
-image/x-pentax-pef pef
-image/x-samsung-srw srw
-image/x-sony-arw arw
-
-text/comma-separated-values csv
-text/plain diff po
-text/rtf rtf
-text/text phps
-text/xml xml
-text/x-vcard vcf
-
-video/3gpp2 3gpp2 3g2
-video/3gpp 3gpp
-video/avi avi
-video/m4v m4v
-video/mp2p mpeg
-video/mp2ts ts
-video/MP2T m2ts MTS
-video/x-webex wrf
-
-# Special cases where Android has a strong opinion about mappings, so we
-# define them very last and use "!" to ensure that we force the mapping
-# in both directions.
-application/pgp-signature pgp!
-application/x-x509-ca-cert crt!
-audio/aac aac!
-audio/basic snd!
-audio/flac flac!
-audio/midi rtx!
-audio/mpeg mp3! m4a m4r
-audio/x-mpegurl m3u8! m3u!
-image/jpeg jpg!
-image/x-ms-bmp bmp!
-text/plain txt!
-text/x-c++hdr hpp!
-text/x-c++src cpp!
-video/3gpp 3gpp!
-video/mpeg mpeg!
-video/quicktime mov!
-video/vnd.youtube.yt yt
-video/x-matroska mkv!
diff --git a/luni/src/main/java/libcore/net/event/NetworkEventDispatcher.java b/luni/src/main/java/libcore/net/event/NetworkEventDispatcher.java
index 5399e89..4c2acee 100644
--- a/luni/src/main/java/libcore/net/event/NetworkEventDispatcher.java
+++ b/luni/src/main/java/libcore/net/event/NetworkEventDispatcher.java
@@ -16,7 +16,7 @@
 
 package libcore.net.event;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
diff --git a/luni/src/main/java/libcore/net/event/NetworkEventListener.java b/luni/src/main/java/libcore/net/event/NetworkEventListener.java
index d7d011b..07c62c5 100644
--- a/luni/src/main/java/libcore/net/event/NetworkEventListener.java
+++ b/luni/src/main/java/libcore/net/event/NetworkEventListener.java
@@ -16,7 +16,7 @@
 
 package libcore.net.event;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * A base class for objects interested in network events.
diff --git a/luni/src/main/java/libcore/net/event/TEST_MAPPING b/luni/src/main/java/libcore/net/event/TEST_MAPPING
new file mode 100644
index 0000000..866b320
--- /dev/null
+++ b/luni/src/main/java/libcore/net/event/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.net.event"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/net/http/HttpDate.java b/luni/src/main/java/libcore/net/http/HttpDate.java
index c295503..de05cea 100644
--- a/luni/src/main/java/libcore/net/http/HttpDate.java
+++ b/luni/src/main/java/libcore/net/http/HttpDate.java
@@ -16,7 +16,7 @@
 
 package libcore.net.http;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
diff --git a/luni/src/main/java/libcore/net/http/ResponseUtils.java b/luni/src/main/java/libcore/net/http/ResponseUtils.java
deleted file mode 100644
index c892b53..0000000
--- a/luni/src/main/java/libcore/net/http/ResponseUtils.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2014 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.net.http;
-
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.StandardCharsets;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @hide
- */
-public class ResponseUtils {
-  /**
-   * Returns the response charset of a HTTP response based on the {@code Content-Type} of
-   * the response (see RFC 7230). If the {@code Content-Type} header is missing or invalid,
-   * the response is assumed to be encoded as {@code UTF-8}. Note that a charset usually
-   * makes sense only for {@code "text/plain"} and other "text based" responses.
-   *
-   * @throws IllegalCharsetNameException if the response specified charset is illegal.
-   * @throws UnsupportedCharsetException if the response specified charset is unsupported.
-   */
-  public static Charset responseCharset(String contentTypeHeader)
-      throws IllegalCharsetNameException, UnsupportedCharsetException {
-    Charset responseCharset = StandardCharsets.UTF_8;
-    if (contentTypeHeader != null) {
-      Map<String, String> contentTypeParams = parseContentTypeParameters(contentTypeHeader);
-      String charsetParameter = contentTypeParams.get("charset");
-      if (charsetParameter != null) {
-        responseCharset = Charset.forName(charsetParameter);
-      }
-    }
-
-    return responseCharset;
-  }
-
-  /**
-   * Parse content-type parameters. The format of this header is roughly :
-   * {@code type/subtype; param1=value1; param2=value2 ...} where each of the
-   * parameters are optional. Parsing is lenient, malformed parameters are ignored.
-   *
-   * Parameter keys & values are trimmed of whitespace and keys are converted to
-   * lower case.
-   */
-  private static Map<String, String> parseContentTypeParameters(String contentTypeHeader) {
-    Map<String, String> parameters = Collections.EMPTY_MAP;
-
-    String[] fields = contentTypeHeader.split(";");
-    if (fields.length > 1) {
-      parameters = new HashMap<>();
-      // Ignore the first element in the array (the type/subtype).
-      for (int i = 1; i < fields.length; ++i) {
-        final String parameter = fields[i];
-        if (!parameter.isEmpty()) {
-          final String[] components = parameter.split("=");
-          if (components.length != 2) {
-            continue;
-          }
-
-          final String key = components[0].trim().toLowerCase();
-          final String value = components[1].trim();
-          if (key.isEmpty() || value.isEmpty()) {
-            continue;
-          }
-
-          parameters.put(key, value);
-        }
-      }
-    }
-
-    return parameters;
-  }
-}
diff --git a/luni/src/main/java/libcore/net/mime.types b/luni/src/main/java/libcore/net/mime.types
deleted file mode 100644
index dfa7a42..0000000
--- a/luni/src/main/java/libcore/net/mime.types
+++ /dev/null
@@ -1,844 +0,0 @@
-###############################################################################
-#
-#  MIME media types and the extensions that represent them.
-#
-#  The format of this file is a media type on the left and zero or more
-#  filename extensions on the right.  Programs using this file will map
-#  files ending with those extensions to the associated type.
-#
-#  This file is part of the "mime-support" package.  Please report a bug using
-#  the "reportbug" command of the "reportbug" package if you would like new
-#  types or extensions to be added.
-#
-#  The reason that all types are managed by the mime-support package instead
-#  allowing individual packages to install types in much the same way as they
-#  add entries in to the mailcap file is so these types can be referenced by
-#  other programs (such as a web server) even if the specific support package
-#  for that type is not installed.
-#
-#  Users can add their own types if they wish by creating a ".mime.types"
-#  file in their home directory.  Definitions included there will take
-#  precedence over those listed here.
-#
-###############################################################################
-
-
-application/activemessage
-application/andrew-inset			ez
-application/annodex				anx
-application/applefile
-application/atom+xml				atom
-application/atomcat+xml				atomcat
-application/atomicmail
-application/atomserv+xml			atomsrv
-application/batch-SMTP
-application/bbolin				lin
-application/beep+xml
-application/cals-1840
-application/commonground
-application/cu-seeme				cu
-application/cybercash
-application/davmount+xml			davmount
-application/dca-rft
-application/dec-dx
-application/dicom				dcm
-application/docbook+xml
-application/dsptype				tsp
-application/dvcs
-application/ecmascript				es
-application/edi-consent
-application/edi-x12
-application/edifact
-application/epub+zip				epub
-application/eshop
-application/font-sfnt				otf ttf
-application/font-tdpfr				pfr
-application/font-woff				woff
-application/futuresplash			spl
-application/ghostview
-application/gzip				gz
-application/hta					hta
-application/http
-application/hyperstudio
-application/iges
-application/index
-application/index.cmd
-application/index.obj
-application/index.response
-application/index.vnd
-application/iotp
-application/ipp
-application/isup
-application/java-archive			jar
-application/java-serialized-object		ser
-application/java-vm				class
-application/javascript				js
-application/json				json
-application/m3g					m3g
-application/mac-binhex40			hqx
-application/mac-compactpro			cpt
-application/macwriteii
-application/marc
-application/mathematica				nb nbp
-application/mbox				mbox
-application/ms-tnef
-application/msaccess				mdb
-application/msword				doc dot
-application/mxf					mxf
-application/news-message-id
-application/news-transmission
-application/ocsp-request
-application/ocsp-response
-application/octet-stream			bin deploy msu msp
-application/oda					oda
-application/oebps-package+xml			opf
-application/ogg					ogx
-application/onenote				one onetoc2 onetmp onepkg
-application/parityfec
-application/pdf					pdf
-application/pgp-encrypted			pgp
-application/pgp-keys				key
-application/pgp-signature			sig
-application/pics-rules				prf
-application/pkcs10
-application/pkcs7-mime
-application/pkcs7-signature
-application/pkix-cert
-application/pkix-crl
-application/pkixcmp
-application/postscript				ps ai eps epsi epsf eps2 eps3
-application/prs.alvestrand.titrax-sheet
-application/prs.cww
-application/prs.nprend
-application/qsig
-application/rar					rar
-application/rdf+xml				rdf
-application/remote-printing
-application/riscos
-application/rtf					rtf
-application/sdp
-application/set-payment
-application/set-payment-initiation
-application/set-registration
-application/set-registration-initiation
-application/sgml
-application/sgml-open-catalog
-application/sieve
-application/sla					stl
-application/slate
-application/smil+xml				smi smil
-application/timestamp-query
-application/timestamp-reply
-application/vemmi
-application/whoispp-query
-application/whoispp-response
-application/wita
-application/x400-bp
-application/xhtml+xml				xhtml xht
-application/xml					xml xsd
-application/xml-dtd
-application/xml-external-parsed-entity
-application/xslt+xml				xsl xslt
-application/xspf+xml				xspf
-application/zip					zip
-application/vnd.3M.Post-it-Notes
-application/vnd.accpac.simply.aso
-application/vnd.accpac.simply.imp
-application/vnd.acucobol
-application/vnd.aether.imp
-application/vnd.android.package-archive						apk
-application/vnd.anser-web-certificate-issue-initiation
-application/vnd.anser-web-funds-transfer-initiation
-application/vnd.audiograph
-application/vnd.bmi
-application/vnd.businessobjects
-application/vnd.canon-cpdl
-application/vnd.canon-lips
-application/vnd.cinderella							cdy
-application/vnd.claymore
-application/vnd.commerce-battelle
-application/vnd.commonspace
-application/vnd.comsocaller
-application/vnd.contact.cmsg
-application/vnd.cosmocaller
-application/vnd.ctc-posml
-application/vnd.cups-postscript
-application/vnd.cups-raster
-application/vnd.cups-raw
-application/vnd.cybank
-application/vnd.debian.binary-package						deb ddeb udeb
-application/vnd.dna
-application/vnd.dpgraph
-application/vnd.dxr
-application/vnd.ecdis-update
-application/vnd.ecowin.chart
-application/vnd.ecowin.filerequest
-application/vnd.ecowin.fileupdate
-application/vnd.ecowin.series
-application/vnd.ecowin.seriesrequest
-application/vnd.ecowin.seriesupdate
-application/vnd.enliven
-application/vnd.epson.esf
-application/vnd.epson.msf
-application/vnd.epson.quickanime
-application/vnd.epson.salt
-application/vnd.epson.ssf
-application/vnd.ericsson.quickcall
-application/vnd.eudora.data
-application/vnd.fdf
-application/vnd.ffsns
-application/vnd.flographit
-application/vnd.font-fontforge-sfd						sfd
-application/vnd.framemaker
-application/vnd.fsc.weblaunch
-application/vnd.fujitsu.oasys
-application/vnd.fujitsu.oasys2
-application/vnd.fujitsu.oasys3
-application/vnd.fujitsu.oasysgp
-application/vnd.fujitsu.oasysprs
-application/vnd.fujixerox.ddd
-application/vnd.fujixerox.docuworks
-application/vnd.fujixerox.docuworks.binder
-application/vnd.fut-misnet
-application/vnd.google-earth.kml+xml						kml
-application/vnd.google-earth.kmz						kmz
-application/vnd.grafeq
-application/vnd.groove-account
-application/vnd.groove-identity-message
-application/vnd.groove-injector
-application/vnd.groove-tool-message
-application/vnd.groove-tool-template
-application/vnd.groove-vcard
-application/vnd.hhe.lesson-player
-application/vnd.hp-HPGL
-application/vnd.hp-PCL
-application/vnd.hp-PCLXL
-application/vnd.hp-hpid
-application/vnd.hp-hps
-application/vnd.httphone
-application/vnd.hzn-3d-crossword
-application/vnd.ibm.MiniPay
-application/vnd.ibm.afplinedata
-application/vnd.ibm.modcap
-application/vnd.informix-visionary
-application/vnd.intercon.formnet
-application/vnd.intertrust.digibox
-application/vnd.intertrust.nncp
-application/vnd.intu.qbo
-application/vnd.intu.qfx
-application/vnd.irepository.package+xml
-application/vnd.is-xpr
-application/vnd.japannet-directory-service
-application/vnd.japannet-jpnstore-wakeup
-application/vnd.japannet-payment-wakeup
-application/vnd.japannet-registration
-application/vnd.japannet-registration-wakeup
-application/vnd.japannet-setstore-wakeup
-application/vnd.japannet-verification
-application/vnd.japannet-verification-wakeup
-application/vnd.koan
-application/vnd.lotus-1-2-3
-application/vnd.lotus-approach
-application/vnd.lotus-freelance
-application/vnd.lotus-notes
-application/vnd.lotus-organizer
-application/vnd.lotus-screencam
-application/vnd.lotus-wordpro
-application/vnd.mcd
-application/vnd.mediastation.cdkey
-application/vnd.meridian-slingshot
-application/vnd.mif
-application/vnd.minisoft-hp3000-save
-application/vnd.mitsubishi.misty-guard.trustweb
-application/vnd.mobius.daf
-application/vnd.mobius.dis
-application/vnd.mobius.msl
-application/vnd.mobius.plc
-application/vnd.mobius.txf
-application/vnd.motorola.flexsuite
-application/vnd.motorola.flexsuite.adsi
-application/vnd.motorola.flexsuite.fis
-application/vnd.motorola.flexsuite.gotap
-application/vnd.motorola.flexsuite.kmr
-application/vnd.motorola.flexsuite.ttc
-application/vnd.motorola.flexsuite.wem
-application/vnd.mozilla.xul+xml							xul
-application/vnd.ms-artgalry
-application/vnd.ms-asf
-application/vnd.ms-excel							xls xlb xlt
-application/vnd.ms-excel.addin.macroEnabled.12					xlam
-application/vnd.ms-excel.sheet.binary.macroEnabled.12				xlsb
-application/vnd.ms-excel.sheet.macroEnabled.12					xlsm
-application/vnd.ms-excel.template.macroEnabled.12				xltm
-application/vnd.ms-fontobject							eot
-application/vnd.ms-lrm
-application/vnd.ms-officetheme							thmx
-application/vnd.ms-pki.seccat							cat
-#application/vnd.ms-pki.stl							stl
-application/vnd.ms-powerpoint							ppt pps
-application/vnd.ms-powerpoint.addin.macroEnabled.12				ppam
-application/vnd.ms-powerpoint.presentation.macroEnabled.12			pptm
-application/vnd.ms-powerpoint.slide.macroEnabled.12				sldm
-application/vnd.ms-powerpoint.slideshow.macroEnabled.12				ppsm
-application/vnd.ms-powerpoint.template.macroEnabled.12				potm
-application/vnd.ms-project
-application/vnd.ms-tnef
-application/vnd.ms-word.document.macroEnabled.12				docm
-application/vnd.ms-word.template.macroEnabled.12				dotm
-application/vnd.ms-works
-application/vnd.mseq
-application/vnd.msign
-application/vnd.music-niff
-application/vnd.musician
-application/vnd.netfpx
-application/vnd.noblenet-directory
-application/vnd.noblenet-sealer
-application/vnd.noblenet-web
-application/vnd.novadigm.EDM
-application/vnd.novadigm.EDX
-application/vnd.novadigm.EXT
-application/vnd.oasis.opendocument.chart					odc
-application/vnd.oasis.opendocument.database					odb
-application/vnd.oasis.opendocument.formula					odf
-application/vnd.oasis.opendocument.graphics					odg
-application/vnd.oasis.opendocument.graphics-template				otg
-application/vnd.oasis.opendocument.image					odi
-application/vnd.oasis.opendocument.presentation					odp
-application/vnd.oasis.opendocument.presentation-template			otp
-application/vnd.oasis.opendocument.spreadsheet					ods
-application/vnd.oasis.opendocument.spreadsheet-template				ots
-application/vnd.oasis.opendocument.text						odt
-application/vnd.oasis.opendocument.text-master					odm
-application/vnd.oasis.opendocument.text-template				ott
-application/vnd.oasis.opendocument.text-web					oth
-application/vnd.openxmlformats-officedocument.presentationml.presentation	pptx
-application/vnd.openxmlformats-officedocument.presentationml.slide		sldx
-application/vnd.openxmlformats-officedocument.presentationml.slideshow		ppsx
-application/vnd.openxmlformats-officedocument.presentationml.template		potx
-application/vnd.openxmlformats-officedocument.spreadsheetml.sheet		xlsx
-application/vnd.openxmlformats-officedocument.spreadsheetml.template		xltx
-application/vnd.openxmlformats-officedocument.wordprocessingml.document		docx
-application/vnd.openxmlformats-officedocument.wordprocessingml.template		dotx
-application/vnd.osa.netdeploy
-application/vnd.palm
-application/vnd.pg.format
-application/vnd.pg.osasli
-application/vnd.powerbuilder6
-application/vnd.powerbuilder6-s
-application/vnd.powerbuilder7
-application/vnd.powerbuilder7-s
-application/vnd.powerbuilder75
-application/vnd.powerbuilder75-s
-application/vnd.previewsystems.box
-application/vnd.publishare-delta-tree
-application/vnd.pvi.ptid1
-application/vnd.pwg-xhtml-print+xml
-application/vnd.rapid
-application/vnd.rim.cod								cod
-application/vnd.s3sms
-application/vnd.seemail
-application/vnd.shana.informed.formdata
-application/vnd.shana.informed.formtemplate
-application/vnd.shana.informed.interchange
-application/vnd.shana.informed.package
-application/vnd.smaf								mmf
-application/vnd.sss-cod
-application/vnd.sss-dtf
-application/vnd.sss-ntf
-application/vnd.stardivision.calc						sdc
-application/vnd.stardivision.chart						sds
-application/vnd.stardivision.draw						sda
-application/vnd.stardivision.impress						sdd
-application/vnd.stardivision.math						sdf
-application/vnd.stardivision.writer						sdw
-application/vnd.stardivision.writer-global					sgl
-application/vnd.street-stream
-application/vnd.sun.xml.calc							sxc
-application/vnd.sun.xml.calc.template						stc
-application/vnd.sun.xml.draw							sxd
-application/vnd.sun.xml.draw.template						std
-application/vnd.sun.xml.impress							sxi
-application/vnd.sun.xml.impress.template					sti
-application/vnd.sun.xml.math							sxm
-application/vnd.sun.xml.writer							sxw
-application/vnd.sun.xml.writer.global						sxg
-application/vnd.sun.xml.writer.template						stw
-application/vnd.svd
-application/vnd.swiftview-ics
-application/vnd.symbian.install							sis
-application/vnd.tcpdump.pcap							cap pcap
-application/vnd.triscape.mxs
-application/vnd.trueapp
-application/vnd.truedoc
-application/vnd.tve-trigger
-application/vnd.ufdl
-application/vnd.uplanet.alert
-application/vnd.uplanet.alert-wbxml
-application/vnd.uplanet.bearer-choice
-application/vnd.uplanet.bearer-choice-wbxml
-application/vnd.uplanet.cacheop
-application/vnd.uplanet.cacheop-wbxml
-application/vnd.uplanet.channel
-application/vnd.uplanet.channel-wbxml
-application/vnd.uplanet.list
-application/vnd.uplanet.list-wbxml
-application/vnd.uplanet.listcmd
-application/vnd.uplanet.listcmd-wbxml
-application/vnd.uplanet.signal
-application/vnd.vcx
-application/vnd.vectorworks
-application/vnd.vidsoft.vidconference
-application/vnd.visio								vsd vst vsw vss
-application/vnd.vividence.scriptfile
-application/vnd.wap.sic
-application/vnd.wap.slc
-application/vnd.wap.wbxml							wbxml
-application/vnd.wap.wmlc							wmlc
-application/vnd.wap.wmlscriptc							wmlsc
-application/vnd.webturbo
-application/vnd.wordperfect							wpd
-application/vnd.wordperfect5.1							wp5
-application/vnd.wrq-hp3000-labelled
-application/vnd.wt.stf
-application/vnd.xara
-application/vnd.xfdl
-application/vnd.yellowriver-custom-menu
-application/zlib
-application/x-123				wk
-application/x-7z-compressed			7z
-application/x-abiword				abw
-application/x-apple-diskimage			dmg
-application/x-bcpio				bcpio
-application/x-bittorrent			torrent
-application/x-cab				cab
-application/x-cbr				cbr
-application/x-cbz				cbz
-application/x-cdf				cdf cda
-application/x-cdlink				vcd
-application/x-chess-pgn				pgn
-application/x-comsol				mph
-application/x-core
-application/x-cpio				cpio
-application/x-csh				csh
-application/x-debian-package			deb udeb
-application/x-director				dcr dir dxr
-application/x-dms				dms
-application/x-doom				wad
-application/x-dvi				dvi
-application/x-executable
-application/x-font				pfa pfb gsf
-application/x-font-pcf				pcf pcf.Z
-application/x-freemind				mm
-application/x-futuresplash			spl
-application/x-ganttproject			gan
-application/x-gnumeric				gnumeric
-application/x-go-sgf				sgf
-application/x-graphing-calculator		gcf
-application/x-gtar				gtar
-application/x-gtar-compressed			tgz taz
-application/x-hdf				hdf
-#application/x-httpd-eruby			rhtml
-#application/x-httpd-php			phtml pht php
-#application/x-httpd-php-source			phps
-#application/x-httpd-php3			php3
-#application/x-httpd-php3-preprocessed		php3p
-#application/x-httpd-php4			php4
-#application/x-httpd-php5			php5
-application/x-hwp				hwp
-application/x-ica				ica
-application/x-info				info
-application/x-internet-signup			ins isp
-application/x-iphone				iii
-application/x-iso9660-image			iso
-application/x-jam				jam
-application/x-java-applet
-application/x-java-bean
-application/x-java-jnlp-file			jnlp
-application/x-jmol				jmz
-application/x-kchart				chrt
-application/x-kdelnk
-application/x-killustrator			kil
-application/x-koan				skp skd skt skm
-application/x-kpresenter			kpr kpt
-application/x-kspread				ksp
-application/x-kword				kwd kwt
-application/x-latex				latex
-application/x-lha				lha
-application/x-lyx				lyx
-application/x-lzh				lzh
-application/x-lzx				lzx
-application/x-maker				frm maker frame fm fb book fbdoc
-application/x-mif				mif
-application/x-mpegURL				m3u8
-application/x-ms-application			application
-application/x-ms-manifest			manifest
-application/x-ms-wmd				wmd
-application/x-ms-wmz				wmz
-application/x-msdos-program			com exe bat dll
-application/x-msi				msi
-application/x-netcdf				nc
-application/x-ns-proxy-autoconfig		pac
-application/x-nwc				nwc
-application/x-object				o
-application/x-oz-application			oza
-application/x-pkcs7-certreqresp			p7r
-application/x-pkcs7-crl				crl
-application/x-python-code			pyc pyo
-application/x-qgis				qgs shp shx
-application/x-quicktimeplayer			qtl
-application/x-rdp				rdp
-application/x-redhat-package-manager		rpm
-application/x-rss+xml				rss
-application/x-ruby				rb
-application/x-rx
-application/x-scilab				sci sce
-application/x-scilab-xcos			xcos
-application/x-sh				sh
-application/x-shar				shar
-application/x-shellscript
-application/x-shockwave-flash			swf swfl
-application/x-silverlight			scr
-application/x-sql				sql
-application/x-stuffit				sit sitx
-application/x-sv4cpio				sv4cpio
-application/x-sv4crc				sv4crc
-application/x-tar				tar
-application/x-tcl				tcl
-application/x-tex-gf				gf
-application/x-tex-pk				pk
-application/x-texinfo				texinfo texi
-application/x-trash				~ % bak old sik
-application/x-troff				t tr roff
-application/x-troff-man				man
-application/x-troff-me				me
-application/x-troff-ms				ms
-application/x-ustar				ustar
-application/x-videolan
-application/x-wais-source			src
-application/x-wingz				wz
-application/x-x509-ca-cert			crt
-application/x-xcf				xcf
-application/x-xfig				fig
-application/x-xpinstall				xpi
-application/x-xz				xz
-
-audio/32kadpcm
-audio/3gpp
-audio/amr					amr
-audio/amr-wb					awb
-audio/annodex					axa
-audio/basic					au snd
-audio/csound					csd orc sco
-audio/flac					flac
-audio/g.722.1
-audio/l16
-audio/midi					mid midi kar
-audio/mp4a-latm
-audio/mpa-robust
-audio/mpeg					mpga mpega mp2 mp3 m4a
-audio/mpegurl					m3u
-audio/ogg					oga ogg opus spx
-audio/parityfec
-audio/prs.sid					sid
-audio/telephone-event
-audio/tone
-audio/vnd.cisco.nse
-audio/vnd.cns.anp1
-audio/vnd.cns.inf1
-audio/vnd.digital-winds
-audio/vnd.everad.plj
-audio/vnd.lucent.voice
-audio/vnd.nortel.vbk
-audio/vnd.nuera.ecelp4800
-audio/vnd.nuera.ecelp7470
-audio/vnd.nuera.ecelp9600
-audio/vnd.octel.sbc
-audio/vnd.qcelp
-audio/vnd.rhetorex.32kadpcm
-audio/vnd.vmx.cvsd
-audio/x-aiff					aif aiff aifc
-audio/x-gsm					gsm
-audio/x-mpegurl					m3u
-audio/x-ms-wma					wma
-audio/x-ms-wax					wax
-audio/x-pn-realaudio-plugin
-audio/x-pn-realaudio				ra rm ram
-audio/x-realaudio				ra
-audio/x-scpls					pls
-audio/x-sd2					sd2
-audio/x-wav					wav
-
-chemical/x-alchemy				alc
-chemical/x-cache				cac cache
-chemical/x-cache-csf				csf
-chemical/x-cactvs-binary			cbin cascii ctab
-chemical/x-cdx					cdx
-chemical/x-cerius				cer
-chemical/x-chem3d				c3d
-chemical/x-chemdraw				chm
-chemical/x-cif					cif
-chemical/x-cmdf					cmdf
-chemical/x-cml					cml
-chemical/x-compass				cpa
-chemical/x-crossfire				bsd
-chemical/x-csml					csml csm
-chemical/x-ctx					ctx
-chemical/x-cxf					cxf cef
-#chemical/x-daylight-smiles			smi
-chemical/x-embl-dl-nucleotide			emb embl
-chemical/x-galactic-spc				spc
-chemical/x-gamess-input				inp gam gamin
-chemical/x-gaussian-checkpoint			fch fchk
-chemical/x-gaussian-cube			cub
-chemical/x-gaussian-input			gau gjc gjf
-chemical/x-gaussian-log				gal
-chemical/x-gcg8-sequence			gcg
-chemical/x-genbank				gen
-chemical/x-hin					hin
-chemical/x-isostar				istr ist
-chemical/x-jcamp-dx				jdx dx
-chemical/x-kinemage				kin
-chemical/x-macmolecule				mcm
-chemical/x-macromodel-input			mmd mmod
-chemical/x-mdl-molfile				mol
-chemical/x-mdl-rdfile				rd
-chemical/x-mdl-rxnfile				rxn
-chemical/x-mdl-sdfile				sd sdf
-chemical/x-mdl-tgf				tgf
-#chemical/x-mif					mif
-chemical/x-mmcif				mcif
-chemical/x-mol2					mol2
-chemical/x-molconn-Z				b
-chemical/x-mopac-graph				gpt
-chemical/x-mopac-input				mop mopcrt mpc zmt
-chemical/x-mopac-out				moo
-chemical/x-mopac-vib				mvb
-chemical/x-ncbi-asn1				asn
-chemical/x-ncbi-asn1-ascii			prt ent
-chemical/x-ncbi-asn1-binary			val aso
-chemical/x-ncbi-asn1-spec			asn
-chemical/x-pdb					pdb ent
-chemical/x-rosdal				ros
-chemical/x-swissprot				sw
-chemical/x-vamas-iso14976			vms
-chemical/x-vmd					vmd
-chemical/x-xtel					xtel
-chemical/x-xyz					xyz
-
-font/collection					ttc
-font/otf					ttf otf
-font/sfnt					ttf otf
-font/ttf					ttf otf
-font/woff					woff
-font/woff2					woff2
-
-image/cgm
-image/g3fax
-image/gif					gif
-image/ief					ief
-image/jp2					jp2 jpg2
-image/jpeg					jpeg jpg jpe
-image/jpm					jpm
-image/jpx					jpx jpf
-image/naplps
-image/pcx					pcx
-image/png					png
-image/prs.btif
-image/prs.pti
-image/svg+xml					svg svgz
-image/tiff					tiff tif
-image/vnd.cns.inf2
-image/vnd.djvu					djvu djv
-image/vnd.dwg
-image/vnd.dxf
-image/vnd.fastbidsheet
-image/vnd.fpx
-image/vnd.fst
-image/vnd.fujixerox.edmics-mmr
-image/vnd.fujixerox.edmics-rlc
-image/vnd.microsoft.icon			ico
-image/vnd.mix
-image/vnd.net-fpx
-image/vnd.svf
-image/vnd.wap.wbmp				wbmp
-image/vnd.xiff
-image/x-canon-cr2				cr2
-image/x-canon-crw				crw
-image/x-cmu-raster				ras
-image/x-coreldraw				cdr
-image/x-coreldrawpattern			pat
-image/x-coreldrawtemplate			cdt
-image/x-corelphotopaint				cpt
-image/x-epson-erf				erf
-image/x-icon
-image/x-jg					art
-image/x-jng					jng
-image/x-ms-bmp					bmp
-image/x-nikon-nef				nef
-image/x-olympus-orf				orf
-image/x-photoshop				psd
-image/x-portable-anymap				pnm
-image/x-portable-bitmap				pbm
-image/x-portable-graymap			pgm
-image/x-portable-pixmap				ppm
-image/x-rgb					rgb
-image/x-xbitmap					xbm
-image/x-xpixmap					xpm
-image/x-xwindowdump				xwd
-
-inode/chardevice
-inode/blockdevice
-inode/directory-locked
-inode/directory
-inode/fifo
-inode/socket
-
-message/delivery-status
-message/disposition-notification
-message/external-body
-message/http
-message/s-http
-message/news
-message/partial
-message/rfc822					eml
-
-model/iges					igs iges
-model/mesh					msh mesh silo
-model/vnd.dwf
-model/vnd.flatland.3dml
-model/vnd.gdl
-model/vnd.gs-gdl
-model/vnd.gtw
-model/vnd.mts
-model/vnd.vtu
-model/vrml					wrl vrml
-model/x3d+vrml					x3dv
-model/x3d+xml					x3d
-model/x3d+binary				x3db
-
-multipart/alternative
-multipart/appledouble
-multipart/byteranges
-multipart/digest
-multipart/encrypted
-multipart/form-data
-multipart/header-set
-multipart/mixed
-multipart/parallel
-multipart/related
-multipart/report
-multipart/signed
-multipart/voice-message
-
-text/cache-manifest				appcache
-text/calendar					ics icz
-text/css					css
-text/csv					csv
-text/directory
-text/english
-text/enriched
-text/h323					323
-text/html					html htm shtml
-text/iuls					uls
-text/mathml					mml
-text/markdown                                   md markdown
-text/parityfec
-text/plain					asc txt text pot brf srt
-text/prs.lines.tag
-text/rfc822-headers
-text/richtext					rtx
-text/rtf
-text/scriptlet					sct wsc
-text/t140
-text/texmacs					tm
-text/tab-separated-values			tsv
-text/turtle					ttl
-text/uri-list
-text/vcard					vcf vcard
-text/vnd.abc
-text/vnd.curl
-text/vnd.debian.copyright
-text/vnd.DMClientScript
-text/vnd.flatland.3dml
-text/vnd.fly
-text/vnd.fmi.flexstor
-text/vnd.in3d.3dml
-text/vnd.in3d.spot
-text/vnd.IPTC.NewsML
-text/vnd.IPTC.NITF
-text/vnd.latex-z
-text/vnd.motorola.reflex
-text/vnd.ms-mediapackage
-text/vnd.sun.j2me.app-descriptor		jad
-text/vnd.wap.si
-text/vnd.wap.sl
-text/vnd.wap.wml				wml
-text/vnd.wap.wmlscript				wmls
-text/x-bibtex					bib
-text/x-boo					boo
-text/x-c++hdr					h++ hpp hxx hh
-text/x-c++src					c++ cpp cxx cc
-text/x-chdr					h
-text/x-component				htc
-text/x-crontab
-text/x-csh					csh
-text/x-csrc					c
-text/x-dsrc					d
-text/x-diff					diff patch
-text/x-haskell					hs
-text/x-java					java
-text/x-lilypond					ly
-text/x-literate-haskell				lhs
-text/x-makefile
-text/x-moc					moc
-text/x-pascal					p pas
-text/x-pcs-gcd					gcd
-text/x-perl					pl pm
-text/x-python					py
-text/x-scala					scala
-text/x-server-parsed-html
-text/x-setext					etx
-text/x-sfv					sfv
-text/x-sh					sh
-text/x-tcl					tcl tk
-text/x-tex					tex ltx sty cls
-text/x-vcalendar				vcs
-
-video/3gpp					3gp
-video/annodex					axv
-video/dl					dl
-video/dv					dif dv
-video/fli					fli
-video/gl					gl
-video/mpeg					mpeg mpg mpe
-video/MP2T					ts
-video/mp4					mp4
-video/quicktime					qt mov
-video/mp4v-es
-video/ogg					ogv
-video/parityfec
-video/pointer
-video/webm					webm
-video/vnd.fvt
-video/vnd.motorola.video
-video/vnd.motorola.videop
-video/vnd.mpegurl				mxu
-video/vnd.mts
-video/vnd.nokia.interleaved-multimedia
-video/vnd.vivo
-video/x-flv					flv
-video/x-la-asf					lsf lsx
-video/x-mng					mng
-video/x-ms-asf					asf asx
-video/x-ms-wm					wm
-video/x-ms-wmv					wmv
-video/x-ms-wmx					wmx
-video/x-ms-wvx					wvx
-video/x-msvideo					avi
-video/x-sgi-movie				movie
-video/x-matroska				mpv mkv
-
-x-conference/x-cooltalk				ice
-
-x-epoc/x-sisx-app				sisx
-x-world/x-vrml					vrm vrml wrl
diff --git a/luni/src/main/java/libcore/net/mime.types.README b/luni/src/main/java/libcore/net/mime.types.README
deleted file mode 100644
index 3479703..0000000
--- a/luni/src/main/java/libcore/net/mime.types.README
+++ /dev/null
@@ -1,13 +0,0 @@
-
-Debian is the upstream for this mapping file:
-https://salsa.debian.org/debian/mime-support
-
-Last updated as of commit d4bbcca4ba04582ad1d253d82fc139bb23841a43.
-
-Copyright: public-domain
-License: ad-hoc
- This package was written by Brian White <bcwhite@pobox.com> and others.
- It contains public information compiled from around the 'net and many people.
- .
- The "update-mime" program was written by Brian White and has been
- placed in the public domain.
diff --git a/luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java b/luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java
index 5919a19..5593ad4 100644
--- a/luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java
+++ b/luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java
@@ -28,11 +28,10 @@
     }
 
     public Type getGenericComponentType() {
-        try {
+        if (componentType instanceof ParameterizedTypeImpl) {
             return ((ParameterizedTypeImpl)componentType).getResolvedType();
-        } catch (ClassCastException e) {
-            return componentType;
         }
+        return componentType;
     }
 
     @Override
diff --git a/luni/src/main/java/libcore/reflect/GenericSignatureParser.java b/luni/src/main/java/libcore/reflect/GenericSignatureParser.java
index 5e86c49..2216cd6 100644
--- a/luni/src/main/java/libcore/reflect/GenericSignatureParser.java
+++ b/luni/src/main/java/libcore/reflect/GenericSignatureParser.java
@@ -315,18 +315,18 @@
         qualIdent.append(this.identifier);
 
         ListOfTypes typeArgs = parseOptTypeArguments();
-        ParameterizedTypeImpl parentType =
-                new ParameterizedTypeImpl(null, qualIdent.toString(), typeArgs, loader);
-        ParameterizedTypeImpl type = parentType;
+        ParameterizedTypeImpl type = new ParameterizedTypeImpl(
+                null /* ownerType */, qualIdent.toString(), typeArgs, loader);
 
+        ParameterizedTypeImpl ownerType;
         while (symbol == '.') {
             // Deal with Member Classes:
             scanSymbol();
             scanIdentifier();
             qualIdent.append("$").append(identifier); // FIXME: is "$" correct?
             typeArgs = parseOptTypeArguments();
-            type = new ParameterizedTypeImpl(parentType, qualIdent.toString(), typeArgs,
-                    loader);
+            ownerType = type;
+            type = new ParameterizedTypeImpl(ownerType, qualIdent.toString(), typeArgs, loader);
         }
 
         expect(';');
diff --git a/luni/src/main/java/libcore/reflect/ParameterizedTypeImpl.java b/luni/src/main/java/libcore/reflect/ParameterizedTypeImpl.java
index 2cd5ac3..47f64a8 100644
--- a/luni/src/main/java/libcore/reflect/ParameterizedTypeImpl.java
+++ b/luni/src/main/java/libcore/reflect/ParameterizedTypeImpl.java
@@ -40,11 +40,12 @@
         this.loader = loader;
     }
 
-
+    @Override
     public Type[] getActualTypeArguments() {
         return args.getResolvedTypes().clone();
     }
 
+    @Override
     public Type getOwnerType() {
         if (ownerTypeRes == null) {
             if (ownerType0 != null) {
@@ -56,6 +57,7 @@
         return ownerTypeRes;
     }
 
+    @Override
     public Class getRawType() {
         if (rawType == null) {
             // Here the actual loading of the class has to be performed and the
@@ -70,9 +72,8 @@
         return rawType;
     }
 
-
     Type getResolvedType() {
-        if (args.getResolvedTypes().length == 0) {
+        if (ownerType0 == null && args.getResolvedTypes().length == 0) {
             return getRawType();
         } else {
             return this;
@@ -99,7 +100,15 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append(rawTypeName);
+        if (ownerType0 != null) {
+            // For nested types, use the ownerType because it or its parents may have their own
+            // type arguments.
+            sb.append(ownerType0);
+            sb.append('$');
+            sb.append(getRawType().getSimpleName());
+        } else {
+            sb.append(rawTypeName);
+        }
         if (args.length() > 0) {
             sb.append("<").append(args).append(">");
         }
diff --git a/luni/src/main/java/libcore/reflect/TEST_MAPPING b/luni/src/main/java/libcore/reflect/TEST_MAPPING
new file mode 100644
index 0000000..b57dc55
--- /dev/null
+++ b/luni/src/main/java/libcore/reflect/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.reflect"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/timezone/CountryTimeZones.java b/luni/src/main/java/libcore/timezone/CountryTimeZones.java
index 66119d7..4ff8470 100644
--- a/luni/src/main/java/libcore/timezone/CountryTimeZones.java
+++ b/luni/src/main/java/libcore/timezone/CountryTimeZones.java
@@ -38,27 +38,35 @@
      * @hide
      */
     @libcore.api.CorePlatformApi
-    public final static class OffsetResult {
+    public static final class OffsetResult {
 
-        /** A zone that matches the supplied criteria. See also {@link #mOneMatch}. */
-        @libcore.api.CorePlatformApi
-        public final TimeZone mTimeZone;
+        /** A zone that matches the supplied criteria. See also {@link #isOnlyMatch}. */
+        private final TimeZone timeZone;
 
         /** True if there is one match for the supplied criteria */
-        @libcore.api.CorePlatformApi
-        public final boolean mOneMatch;
+        private final boolean isOnlyMatch;
 
-        public OffsetResult(TimeZone timeZone, boolean oneMatch) {
-            mTimeZone = java.util.Objects.requireNonNull(timeZone);
-            mOneMatch = oneMatch;
+        public OffsetResult(TimeZone timeZone, boolean isOnlyMatch) {
+            this.timeZone = java.util.Objects.requireNonNull(timeZone);
+            this.isOnlyMatch = isOnlyMatch;
+        }
+
+        @libcore.api.CorePlatformApi
+        public TimeZone getTimeZone() {
+            return timeZone;
+        }
+
+        @libcore.api.CorePlatformApi
+        public boolean isOnlyMatch() {
+            return isOnlyMatch;
         }
 
         @Override
         public String toString() {
-            return "Result{" +
-                    "mTimeZone='" + mTimeZone + '\'' +
-                    ", mOneMatch=" + mOneMatch +
-                    '}';
+            return "Result{"
+                    + "timeZone='" + timeZone + '\''
+                    + ", isOnlyMatch=" + isOnlyMatch
+                    + '}';
         }
     }
 
@@ -68,20 +76,66 @@
      * @hide
      */
     @libcore.api.CorePlatformApi
-    public final static class TimeZoneMapping {
-        @libcore.api.CorePlatformApi
-        public final String timeZoneId;
-        @libcore.api.CorePlatformApi
-        public final boolean showInPicker;
-        @libcore.api.CorePlatformApi
-        public final Long notUsedAfter;
+    public static final class TimeZoneMapping {
+        private final String timeZoneId;
+        private final boolean shownInPicker;
+        private final Long notUsedAfter;
 
-        TimeZoneMapping(String timeZoneId, boolean showInPicker, Long notUsedAfter) {
-            this.timeZoneId = timeZoneId;
-            this.showInPicker = showInPicker;
+        /** Memoized TimeZone object for {@link #timeZoneId}. */
+        private TimeZone timeZone;
+
+        TimeZoneMapping(String timeZoneId, boolean shownInPicker, Long notUsedAfter) {
+            this.timeZoneId = Objects.requireNonNull(timeZoneId);
+            this.shownInPicker = shownInPicker;
             this.notUsedAfter = notUsedAfter;
         }
 
+        @libcore.api.CorePlatformApi
+        public String getTimeZoneId() {
+            return timeZoneId;
+        }
+
+        @libcore.api.CorePlatformApi
+        public boolean isShownInPicker() {
+            return shownInPicker;
+        }
+
+        @libcore.api.CorePlatformApi
+        public Long getNotUsedAfter() {
+            return notUsedAfter;
+        }
+
+        /**
+         * Returns a {@link TimeZone} object for this mapping, or {@code null} if the ID is unknown.
+         */
+        @libcore.api.CorePlatformApi
+        public TimeZone getTimeZone() {
+            synchronized (this) {
+                if (timeZone == null) {
+                    TimeZone tz = TimeZone.getFrozenTimeZone(timeZoneId);
+                    timeZone = tz;
+                    if (TimeZone.UNKNOWN_ZONE_ID.equals(timeZone.getID())) {
+                        // This shouldn't happen given the validation that takes place in
+                        // createValidatedCountryTimeZones().
+                        throw new IllegalStateException("Invalid zone in TimeZoneMapping: " + this);
+                    }
+                }
+            }
+
+            return TimeZone.UNKNOWN_ZONE_ID.equals(timeZone.getID()) ? null : timeZone;
+        }
+
+        /**
+         * Returns {@code true} if the mapping is "effective" after {@code whenMillis}, i.e.
+         * it is distinct from other "effective" times zones used in the country at/after that
+         * time. This uses the {@link #notUsedAfter} metadata which ensures there is one time
+         * zone remaining when there are multiple candidate zones with the same rules. The one
+         * kept is based on country specific factors like population covered.
+         */
+        boolean isEffectiveAt(long whenMillis) {
+            return notUsedAfter == null || whenMillis <= notUsedAfter;
+        }
+
         // VisibleForTesting
         @libcore.api.CorePlatformApi
         public static TimeZoneMapping createForTests(
@@ -98,21 +152,21 @@
                 return false;
             }
             TimeZoneMapping that = (TimeZoneMapping) o;
-            return showInPicker == that.showInPicker &&
+            return shownInPicker == that.shownInPicker &&
                     Objects.equals(timeZoneId, that.timeZoneId) &&
                     Objects.equals(notUsedAfter, that.notUsedAfter);
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(timeZoneId, showInPicker, notUsedAfter);
+            return Objects.hash(timeZoneId, shownInPicker, notUsedAfter);
         }
 
         @Override
         public String toString() {
             return "TimeZoneMapping{"
                     + "timeZoneId='" + timeZoneId + '\''
-                    + ", showInPicker=" + showInPicker
+                    + ", shownInPicker=" + shownInPicker
                     + ", notUsedAfter=" + notUsedAfter
                     + '}';
         }
@@ -121,7 +175,7 @@
          * Returns {@code true} if one of the supplied {@link TimeZoneMapping} objects is for the
          * specified time zone ID.
          */
-        public static boolean containsTimeZoneId(
+        static boolean containsTimeZoneId(
                 List<TimeZoneMapping> timeZoneMappings, String timeZoneId) {
             for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
                 if (timeZoneMapping.timeZoneId.equals(timeZoneId)) {
@@ -134,18 +188,26 @@
 
     private final String countryIso;
     private final String defaultTimeZoneId;
+    /**
+     * {@code true} indicates the default time zone for a country is a good choice if a time zone
+     * cannot be determined by other means.
+     */
+    private final boolean defaultTimeZoneBoosted;
     private final List<TimeZoneMapping> timeZoneMappings;
     private final boolean everUsesUtc;
 
-    // Memoized frozen ICU TimeZone object for the default.
-    private TimeZone icuDefaultTimeZone;
-    // Memoized frozen ICU TimeZone objects for the timeZoneIds.
-    private List<TimeZone> icuTimeZones;
+    /**
+     * Memoized frozen ICU TimeZone object for the default. Can be {@link TimeZone#UNKNOWN_ZONE} if
+     * the {@link #defaultTimeZoneId} is missing or unrecognized.
+     */
+    private TimeZone defaultTimeZone;
 
-    private CountryTimeZones(String countryIso, String defaultTimeZoneId, boolean everUsesUtc,
+    private CountryTimeZones(String countryIso, String defaultTimeZoneId,
+            boolean defaultTimeZoneBoosted, boolean everUsesUtc,
             List<TimeZoneMapping> timeZoneMappings) {
         this.countryIso = java.util.Objects.requireNonNull(countryIso);
         this.defaultTimeZoneId = defaultTimeZoneId;
+        this.defaultTimeZoneBoosted = defaultTimeZoneBoosted;
         this.everUsesUtc = everUsesUtc;
         // Create a defensive copy of the mapping list.
         this.timeZoneMappings = Collections.unmodifiableList(new ArrayList<>(timeZoneMappings));
@@ -155,12 +217,13 @@
      * Creates a {@link CountryTimeZones} object containing only known time zone IDs.
      */
     public static CountryTimeZones createValidated(String countryIso, String defaultTimeZoneId,
-            boolean everUsesUtc, List<TimeZoneMapping> timeZoneMappings, String debugInfo) {
+            boolean defaultTimeZoneBoosted, boolean everUsesUtc,
+            List<TimeZoneMapping> timeZoneMappings, String debugInfo) {
 
         // We rely on ZoneInfoDB to tell us what the known valid time zone IDs are. ICU may
         // recognize more but we want to be sure that zone IDs can be used with java.util as well as
         // android.icu and ICU is expected to have a superset.
-        String[] validTimeZoneIdsArray = ZoneInfoDB.getInstance().getAvailableIDs();
+        String[] validTimeZoneIdsArray = ZoneInfoDb.getInstance().getAvailableIDs();
         HashSet<String> validTimeZoneIdsSet = new HashSet<>(Arrays.asList(validTimeZoneIdsArray));
         List<TimeZoneMapping> validCountryTimeZoneMappings = new ArrayList<>();
         for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
@@ -184,7 +247,8 @@
 
         String normalizedCountryIso = normalizeCountryIso(countryIso);
         return new CountryTimeZones(
-                normalizedCountryIso, defaultTimeZoneId, everUsesUtc, validCountryTimeZoneMappings);
+                normalizedCountryIso, defaultTimeZoneId, defaultTimeZoneBoosted, everUsesUtc,
+                validCountryTimeZoneMappings);
     }
 
     /**
@@ -204,27 +268,28 @@
     }
 
     /**
-     * Returns the default time zone ID for the country. Can return null in cases when no data is
+     * Returns the default time zone for the country. Can return null in cases when no data is
      * available or the time zone ID provided to
-     * {@link #createValidated(String, String, boolean, List, String)} was not recognized.
+     * {@link #createValidated(String, String, boolean, boolean, List, String)} was not recognized.
      */
+    @libcore.api.CorePlatformApi
     public synchronized TimeZone getDefaultTimeZone() {
-        if (icuDefaultTimeZone == null) {
-            TimeZone defaultTimeZone;
+        if (defaultTimeZone == null) {
+            TimeZone timeZone;
             if (defaultTimeZoneId == null) {
-                defaultTimeZone = null;
+                timeZone = TimeZone.UNKNOWN_ZONE;
             } else {
-                defaultTimeZone = getValidFrozenTimeZoneOrNull(defaultTimeZoneId);
+                timeZone = TimeZone.getFrozenTimeZone(defaultTimeZoneId);
             }
-            icuDefaultTimeZone = defaultTimeZone;
+            this.defaultTimeZone = timeZone;
         }
-        return icuDefaultTimeZone;
+        return TimeZone.UNKNOWN_ZONE_ID.equals(defaultTimeZone.getID()) ? null : defaultTimeZone;
     }
 
     /**
      * Returns the default time zone ID for the country. Can return null in cases when no data is
      * available or the time zone ID provided to
-     * {@link #createValidated(String, String, boolean, List, String)} was not recognized.
+     * {@link #createValidated(String, String, boolean, boolean, List, String)} was not recognized.
      */
     @libcore.api.CorePlatformApi
     public String getDefaultTimeZoneId() {
@@ -232,6 +297,15 @@
     }
 
     /**
+     * Qualifier for a country's default time zone. {@code true} indicates whether the default
+     * would be a good choice <em>generally</em> when there's no other information available.
+     */
+    @libcore.api.CorePlatformApi
+    public boolean isDefaultTimeZoneBoosted() {
+        return defaultTimeZoneBoosted;
+    }
+
+    /**
      * Returns an immutable, ordered list of time zone mappings for the country in an undefined but
      * "priority" order. The list can be empty if there were no zones configured or the configured
      * zone IDs were not recognized.
@@ -241,6 +315,24 @@
         return timeZoneMappings;
     }
 
+    /**
+     * Returns an immutable, ordered list of time zone mappings for the country in an undefined but
+     * "priority" order, filtered so that only "effective" time zone IDs are returned. An
+     * "effective" time zone is one that differs from another time zone used in the country after
+     * {@code whenMillis}. The list can be empty if there were no zones configured or the configured
+     * zone IDs were not recognized.
+     */
+    @libcore.api.CorePlatformApi
+    public List<TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long whenMillis) {
+        ArrayList<TimeZoneMapping> filteredList = new ArrayList<>(timeZoneMappings.size());
+        for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
+            if (timeZoneMapping.isEffectiveAt(whenMillis)) {
+                filteredList.add(timeZoneMapping);
+            }
+        }
+        return Collections.unmodifiableList(filteredList);
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -249,58 +341,30 @@
         if (o == null || getClass() != o.getClass()) {
             return false;
         }
-
         CountryTimeZones that = (CountryTimeZones) o;
-
-        if (everUsesUtc != that.everUsesUtc) {
-            return false;
-        }
-        if (!countryIso.equals(that.countryIso)) {
-            return false;
-        }
-        if (defaultTimeZoneId != null ? !defaultTimeZoneId.equals(that.defaultTimeZoneId)
-                : that.defaultTimeZoneId != null) {
-            return false;
-        }
-        return timeZoneMappings.equals(that.timeZoneMappings);
+        return defaultTimeZoneBoosted == that.defaultTimeZoneBoosted
+                && everUsesUtc == that.everUsesUtc
+                && countryIso.equals(that.countryIso)
+                && Objects.equals(defaultTimeZoneId, that.defaultTimeZoneId)
+                && timeZoneMappings.equals(that.timeZoneMappings);
     }
 
     @Override
     public int hashCode() {
-        int result = countryIso.hashCode();
-        result = 31 * result + (defaultTimeZoneId != null ? defaultTimeZoneId.hashCode() : 0);
-        result = 31 * result + timeZoneMappings.hashCode();
-        result = 31 * result + (everUsesUtc ? 1 : 0);
-        return result;
+        return Objects.hash(
+                countryIso, defaultTimeZoneId, defaultTimeZoneBoosted, timeZoneMappings,
+                everUsesUtc);
     }
 
-    /**
-     * Returns an ordered list of time zones for the country in an undefined but "priority"
-     * order for a country. The list can be empty if there were no zones configured or the
-     * configured zone IDs were not recognized.
-     */
-    public synchronized List<TimeZone> getIcuTimeZones() {
-        if (icuTimeZones == null) {
-            ArrayList<TimeZone> mutableList = new ArrayList<>(timeZoneMappings.size());
-            for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
-                String timeZoneId = timeZoneMapping.timeZoneId;
-                TimeZone timeZone;
-                if (timeZoneId.equals(defaultTimeZoneId)) {
-                    timeZone = getDefaultTimeZone();
-                } else {
-                    timeZone = getValidFrozenTimeZoneOrNull(timeZoneId);
-                }
-                // This shouldn't happen given the validation that takes place in
-                // createValidatedCountryTimeZones().
-                if (timeZone == null) {
-                    System.logW("Skipping invalid zone: " + timeZoneId);
-                    continue;
-                }
-                mutableList.add(timeZone);
-            }
-            icuTimeZones = Collections.unmodifiableList(mutableList);
-        }
-        return icuTimeZones;
+    @Override
+    public String toString() {
+        return "CountryTimeZones{"
+                + "countryIso='" + countryIso + '\''
+                + ", defaultTimeZoneId='" + defaultTimeZoneId + '\''
+                + ", defaultTimeZoneBoosted=" + defaultTimeZoneBoosted
+                + ", timeZoneMappings=" + timeZoneMappings
+                + ", everUsesUtc=" + everUsesUtc
+                + '}';
     }
 
     /**
@@ -313,8 +377,9 @@
             return false;
         }
 
-        for (TimeZone zone : getIcuTimeZones()) {
-            if (zone.getOffset(whenMillis) == 0) {
+        for (TimeZoneMapping timeZoneMapping : getEffectiveTimeZoneMappingsAt(whenMillis)) {
+            TimeZone timeZone = timeZoneMapping.getTimeZone();
+            if (timeZone != null && timeZone.getOffset(whenMillis) == 0) {
                 return true;
             }
         }
@@ -322,68 +387,70 @@
     }
 
     /**
-     * Returns {@code true} if the default time zone for the country is either the only zone used or
-     * if it has the same offsets as all other zones used by the country <em>at the specified time
-     * </em> making the default equivalent to all other zones used by the country <em>at that time
-     * </em>.
+     * Returns a time zone for the country, if there is one, that matches the supplied properties.
+     * If there are multiple matches and the {@code bias} is one of them then it is returned,
+     * otherwise an arbitrary match is returned based on the {@link
+     * #getEffectiveTimeZoneMappingsAt(long)} ordering.
+     *
+     * @param whenMillis the UTC time to match against
+     * @param bias the time zone to prefer, can be {@code null} to indicate there is no preference
+     * @param totalOffsetMillis the offset from UTC at {@code whenMillis}
+     * @param isDst the Daylight Savings Time state at {@code whenMillis}. {@code true} means DST,
+     *     {@code false} means not DST
+     * @return an {@link OffsetResult} with information about a matching zone, or {@code null} if
+     *     there is no match
      */
     @libcore.api.CorePlatformApi
-    public boolean isDefaultOkForCountryTimeZoneDetection(long whenMillis) {
+    public OffsetResult lookupByOffsetWithBias(long whenMillis, TimeZone bias,
+            int totalOffsetMillis, boolean isDst) {
+        return lookupByOffsetWithBiasInternal(whenMillis, bias, totalOffsetMillis, isDst);
+    }
+
+    /**
+     * Returns a time zone for the country, if there is one, that matches the supplied properties.
+     * If there are multiple matches and the {@code bias} is one of them then it is returned,
+     * otherwise an arbitrary match is returned based on the {@link
+     * #getEffectiveTimeZoneMappingsAt(long)} ordering.
+     *
+     * @param whenMillis the UTC time to match against
+     * @param bias the time zone to prefer, can be {@code null} to indicate there is no preference
+     * @param totalOffsetMillis the offset from UTC at {@code whenMillis}
+     * @return an {@link OffsetResult} with information about a matching zone, or {@code null} if
+     *     there is no match
+     */
+    @libcore.api.CorePlatformApi
+    public OffsetResult lookupByOffsetWithBias(long whenMillis, TimeZone bias,
+            int totalOffsetMillis) {
+        final Boolean isDst = null;
+        return lookupByOffsetWithBiasInternal(whenMillis, bias, totalOffsetMillis, isDst);
+    }
+
+    /**
+     * Returns a time zone for the country, if there is one, that matches the supplied properties.
+     * If there are multiple matches and the {@code bias} is one of them then it is returned,
+     * otherwise an arbitrary match is returned based on the {@link
+     * #getEffectiveTimeZoneMappingsAt(long)} ordering.
+     *
+     * @param whenMillis the UTC time to match against
+     * @param bias the time zone to prefer, can be {@code null}
+     * @param totalOffsetMillis the offset from UTC at {@code whenMillis}
+     * @param isDst the Daylight Savings Time state at {@code whenMillis}. {@code true} means DST,
+     *     {@code false} means not DST, {@code null} means unknown
+     */
+    private OffsetResult lookupByOffsetWithBiasInternal(long whenMillis, TimeZone bias,
+            int totalOffsetMillis, Boolean isDst) {
+        List<TimeZoneMapping> timeZoneMappings = getEffectiveTimeZoneMappingsAt(whenMillis);
         if (timeZoneMappings.isEmpty()) {
-            // Should never happen unless there's been an error loading the data.
-            return false;
-        } else if (timeZoneMappings.size() == 1) {
-            // The default is the only zone so it's a good candidate.
-            return true;
-        } else {
-            TimeZone countryDefault = getDefaultTimeZone();
-            if (countryDefault == null) {
-                return false;
-            }
-
-            int countryDefaultOffset = countryDefault.getOffset(whenMillis);
-            List<TimeZone> candidates = getIcuTimeZones();
-            for (TimeZone candidate : candidates) {
-                if (candidate == countryDefault) {
-                    continue;
-                }
-
-                int candidateOffset = candidate.getOffset(whenMillis);
-                if (countryDefaultOffset != candidateOffset) {
-                    // Multiple different offsets means the default should not be used.
-                    return false;
-                }
-            }
-            return true;
-        }
-    }
-
-    /**
-     * Returns a time zone for the country, if there is one, that has the desired properties. If
-     * there are multiple matches and the {@code bias} is one of them then it is returned, otherwise
-     * an arbitrary match is returned based on the {@link #getTimeZoneMappings()} ordering.
-     *
-     * @param offsetMillis the offset from UTC at {@code whenMillis}
-     * @param isDst whether the zone is in DST
-     * @param whenMillis the UTC time to match against
-     * @param bias the time zone to prefer, can be null
-     * @deprecated Use {@link #lookupByOffsetWithBias(int, Integer, long, TimeZone)} instead
-     */
-    @libcore.api.CorePlatformApi
-    @Deprecated
-    public OffsetResult lookupByOffsetWithBias(int offsetMillis, boolean isDst, long whenMillis,
-            TimeZone bias) {
-        if (timeZoneMappings == null || timeZoneMappings.isEmpty()) {
             return null;
         }
 
-        List<TimeZone> candidates = getIcuTimeZones();
-
         TimeZone firstMatch = null;
         boolean biasMatched = false;
         boolean oneMatch = true;
-        for (TimeZone match : candidates) {
-            if (!offsetMatchesAtTime(match, offsetMillis, isDst, whenMillis)) {
+        for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
+            TimeZone match = timeZoneMapping.getTimeZone();
+            if (match == null
+                    || !offsetMatchesAtTime(whenMillis, match, totalOffsetMillis, isDst)) {
                 continue;
             }
 
@@ -408,92 +475,23 @@
     }
 
     /**
-     * Returns {@code true} if the specified offset, DST state and time would be valid in the
-     * timeZone.
+     * Returns {@code true} if the specified {@code totalOffset} and {@code isDst} would be valid in
+     * the {@code timeZone} at time {@code whenMillis}.
+     * {@code totalOffetMillis} is always matched.
+     * If {@code isDst} is {@code null}, this means the DST state is unknown.
+     * If {@code isDst} is {@code false}, this means the zone must not be in DST.
+     * If {@code isDst} is {@code true}, this means the zone must be in DST.
      */
-    private static boolean offsetMatchesAtTime(TimeZone timeZone, int offsetMillis, boolean isDst,
-            long whenMillis) {
+    private static boolean offsetMatchesAtTime(long whenMillis, TimeZone timeZone,
+            int totalOffsetMillis, Boolean isDst) {
         int[] offsets = new int[2];
         timeZone.getOffset(whenMillis, false /* local */, offsets);
 
-        // offsets[1] == 0 when the zone is not in DST.
-        boolean zoneIsDst = offsets[1] != 0;
-        if (isDst != zoneIsDst) {
+        if (totalOffsetMillis != (offsets[0] + offsets[1])) {
             return false;
         }
-        return offsetMillis == (offsets[0] + offsets[1]);
-    }
 
-    /**
-     * Returns a time zone for the country, if there is one, that has the desired properties. If
-     * there are multiple matches and the {@code bias} is one of them then it is returned, otherwise
-     * an arbitrary match is returned based on the {@link #getTimeZoneMappings()} ordering.
-     *
-     * @param offsetMillis the offset from UTC at {@code whenMillis}
-     * @param dstOffsetMillis the part of {@code offsetMillis} contributed by DST, {@code null}
-     *                        means unknown
-     * @param whenMillis the UTC time to match against
-     * @param bias the time zone to prefer, can be null
-     */
-    public OffsetResult lookupByOffsetWithBias(int offsetMillis, Integer dstOffsetMillis,
-            long whenMillis, TimeZone bias) {
-        if (timeZoneMappings == null || timeZoneMappings.isEmpty()) {
-            return null;
-        }
-
-        List<TimeZone> candidates = getIcuTimeZones();
-
-        TimeZone firstMatch = null;
-        boolean biasMatched = false;
-        boolean oneMatch = true;
-        for (TimeZone match : candidates) {
-            if (!offsetMatchesAtTime(match, offsetMillis, dstOffsetMillis, whenMillis)) {
-                continue;
-            }
-
-            if (firstMatch == null) {
-                firstMatch = match;
-            } else {
-                oneMatch = false;
-            }
-            if (bias != null && match.getID().equals(bias.getID())) {
-                biasMatched = true;
-            }
-            if (firstMatch != null && !oneMatch && (bias == null || biasMatched)) {
-                break;
-            }
-        }
-        if (firstMatch == null) {
-            return null;
-        }
-
-        TimeZone toReturn = biasMatched ? bias : firstMatch;
-        return new OffsetResult(toReturn, oneMatch);
-    }
-
-    /**
-     * Returns {@code true} if the specified offset, DST and time would be valid in the
-     * timeZone.
-     */
-    private static boolean offsetMatchesAtTime(TimeZone timeZone, int offsetMillis,
-            Integer dstOffsetMillis, long whenMillis) {
-        int[] offsets = new int[2];
-        timeZone.getOffset(whenMillis, false /* local */, offsets);
-
-        if (dstOffsetMillis != null) {
-            if (dstOffsetMillis.intValue() != offsets[1]) {
-                return false;
-            }
-        }
-        return offsetMillis == (offsets[0] + offsets[1]);
-    }
-
-    private static TimeZone getValidFrozenTimeZoneOrNull(String timeZoneId) {
-        TimeZone timeZone = TimeZone.getFrozenTimeZone(timeZoneId);
-        if (timeZone.getID().equals(TimeZone.UNKNOWN_ZONE_ID)) {
-            return null;
-        }
-        return timeZone;
+        return isDst == null || (isDst == (offsets[1] != 0));
     }
 
     private static String normalizeCountryIso(String countryIso) {
diff --git a/luni/src/main/java/libcore/timezone/CountryZonesFinder.java b/luni/src/main/java/libcore/timezone/CountryZonesFinder.java
index 92f6631..1a9d6a6 100644
--- a/luni/src/main/java/libcore/timezone/CountryZonesFinder.java
+++ b/luni/src/main/java/libcore/timezone/CountryZonesFinder.java
@@ -16,6 +16,8 @@
 
 package libcore.timezone;
 
+import static libcore.timezone.XmlUtils.normalizeCountryIso;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -76,7 +78,7 @@
      */
     @libcore.api.CorePlatformApi
     public CountryTimeZones lookupCountryTimeZones(String countryIso) {
-        String normalizedCountryIso = TimeZoneFinder.normalizeCountryIso(countryIso);
+        String normalizedCountryIso = normalizeCountryIso(countryIso);
         for (CountryTimeZones countryTimeZones : countryTimeZonesList) {
             if (countryTimeZones.getCountryIso().equals(normalizedCountryIso)) {
                 return countryTimeZones;
diff --git a/luni/src/main/java/libcore/timezone/TEST_MAPPING b/luni/src/main/java/libcore/timezone/TEST_MAPPING
new file mode 100644
index 0000000..7f731bb
--- /dev/null
+++ b/luni/src/main/java/libcore/timezone/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.timezone"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/timezone/TelephonyLookup.java b/luni/src/main/java/libcore/timezone/TelephonyLookup.java
new file mode 100644
index 0000000..10d9a35
--- /dev/null
+++ b/luni/src/main/java/libcore/timezone/TelephonyLookup.java
@@ -0,0 +1,325 @@
+/*
+ * 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 libcore.timezone;
+
+import static libcore.timezone.XmlUtils.checkOnEndTag;
+import static libcore.timezone.XmlUtils.consumeUntilEndTag;
+import static libcore.timezone.XmlUtils.findNextStartTagOrEndTagNoRecurse;
+import static libcore.timezone.XmlUtils.findNextStartTagOrThrowNoRecurse;
+import static libcore.timezone.XmlUtils.normalizeCountryIso;
+
+import libcore.timezone.TelephonyNetwork.MccMnc;
+import libcore.timezone.XmlUtils.ReaderSupplier;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A class that can find time zone-related information about telephony networks by loading data from
+ * the telephonylookup.xml file.
+ *
+ * @hide
+ */
+@libcore.api.CorePlatformApi
+public final class TelephonyLookup {
+
+    // VisibleForTesting
+    public static final String TELEPHONYLOOKUP_FILE_NAME = "telephonylookup.xml";
+
+    // Root element. e.g. <telephony_lookup>
+    private static final String TELEPHONY_LOOKUP_ELEMENT = "telephony_lookup";
+
+    // Networks section. e.g. <networks>
+    private static final String NETWORKS_ELEMENT = "networks";
+
+    // Network data. e.g.
+    // <network mcc="310" mnc="370" country="gu">
+    private static final String NETWORK_ELEMENT = "network";
+    private static final String MOBILE_COUNTRY_CODE_ATTRIBUTE = "mcc";
+    private static final String MOBILE_NETWORK_CODE_ATTRIBUTE = "mnc";
+    // This is the ISO 3166 alpha-2 code (in lower case).
+    private static final String COUNTRY_ISO_CODE_ATTRIBUTE = "country";
+
+    private static TelephonyLookup instance;
+
+    private final ReaderSupplier xmlSource;
+
+    private TelephonyLookup(ReaderSupplier xmlSource) {
+        this.xmlSource = xmlSource;
+    }
+
+    /**
+     * Obtains an instance for use when resolving networks. This method handles using the correct
+     * file when there are several to choose from. This method never returns {@code null}. No
+     * in-depth validation is performed on the file content, see {@link #validate()}.
+     */
+    @libcore.api.CorePlatformApi
+    public static TelephonyLookup getInstance() {
+        synchronized(TelephonyLookup.class) {
+            if (instance == null) {
+                String[] telephonyLookupFilePaths =
+                        TimeZoneDataFiles.getTimeZoneFilePaths(TELEPHONYLOOKUP_FILE_NAME);
+                instance = createInstanceWithFallback(telephonyLookupFilePaths);
+            }
+        }
+        return instance;
+    }
+
+    // VisibleForTesting
+    public static TelephonyLookup createInstanceWithFallback(String... telephonyLookupFilePaths) {
+        IOException lastException = null;
+        for (String tzLookupFilePath : telephonyLookupFilePaths) {
+            try {
+                // We assume that any file in /data was validated before install, and the system
+                // file was validated before the device shipped. Therefore, we do not pay the
+                // validation cost here.
+                return createInstance(tzLookupFilePath);
+            } catch (IOException e) {
+                // There's expected to be two files, and it's normal for the first file not to
+                // exist so we don't log, but keep the lastException so we can log it if there
+                // are no valid files available.
+                if (lastException != null) {
+                    e.addSuppressed(lastException);
+                }
+                lastException = e;
+            }
+        }
+
+        System.logE("No valid file found in set: " + Arrays.toString(telephonyLookupFilePaths)
+                + " Printing exceptions and falling back to empty map.", lastException);
+        return createInstanceForTests("<telephony_lookup><networks /></telephony_lookup>");
+    }
+
+    /**
+     * Obtains an instance using a specific data file, throwing an IOException if the file does not
+     * exist or is not readable. This method never returns {@code null}. No in-depth validation is
+     * performed on the file content, see {@link #validate()}.
+     */
+    @libcore.api.CorePlatformApi
+    public static TelephonyLookup createInstance(String path) throws IOException {
+        ReaderSupplier xmlSupplier = ReaderSupplier.forFile(path, StandardCharsets.UTF_8);
+        return new TelephonyLookup(xmlSupplier);
+    }
+
+    /** Used to create an instance using an in-memory XML String instead of a file. */
+    // VisibleForTesting
+    public static TelephonyLookup createInstanceForTests(String xml) {
+        return new TelephonyLookup(ReaderSupplier.forString(xml));
+    }
+
+    /**
+     * Parses the data file, throws an exception if it is invalid or cannot be read.
+     */
+    @libcore.api.CorePlatformApi
+    public void validate() throws IOException {
+        try {
+            processXml(new TelephonyNetworkValidator());
+        } catch (XmlPullParserException e) {
+            throw new IOException("Parsing error", e);
+        }
+    }
+
+    /**
+     * Loads all the network &lt;-&gt; country mapping data into memory. This method can return
+     * {@code null} in the event of an error while reading the underlying data files.
+     */
+    @libcore.api.CorePlatformApi
+    public TelephonyNetworkFinder getTelephonyNetworkFinder() {
+        TelephonyNetworksExtractor extractor = new TelephonyNetworksExtractor();
+        try {
+            processXml(extractor);
+
+            return extractor.getTelephonyNetworkFinder();
+        } catch (XmlPullParserException | IOException e) {
+            System.logW("Error reading telephony networks", e);
+            return null;
+        }
+    }
+
+    /**
+     * Processes the XML, applying the {@link TelephonyNetworkProcessor} to the &lt;countryzones&gt;
+     * element. Processing can terminate early if {@link TelephonyNetworkProcessor
+     * #processNetwork(int, int, String, String)} it throws an exception.
+     */
+    private void processXml(TelephonyNetworkProcessor processor)
+            throws XmlPullParserException, IOException {
+        try (Reader reader = xmlSource.get()) {
+            XmlPullParserFactory xmlPullParserFactory = XmlPullParserFactory.newInstance();
+            xmlPullParserFactory.setNamespaceAware(false);
+
+            XmlPullParser parser = xmlPullParserFactory.newPullParser();
+            parser.setInput(reader);
+
+            /*
+             * The expected XML structure is:
+             * <telephony_lookup>
+             *   <networks>
+             *     <network mcc="123" mnc="456" country="ab"/>
+             *     <network mcc="123" mnc="567" country="cd"/>
+             *   </networks>
+             * </telephony_lookup>
+             */
+
+            findNextStartTagOrThrowNoRecurse(parser, TELEPHONY_LOOKUP_ELEMENT);
+
+            // There is only one expected sub-element <telephony_lookup> in the format currently,
+            // skip over anything before it.
+            findNextStartTagOrThrowNoRecurse(parser, NETWORKS_ELEMENT);
+
+            processNetworks(parser, processor);
+
+            // Make sure we are on the </networks> tag.
+            checkOnEndTag(parser, NETWORKS_ELEMENT);
+
+            // Advance to the next event.
+            parser.next();
+
+            // Skip anything until </telephony_lookup>, and make sure the file is not truncated and
+            // we can find the end.
+            consumeUntilEndTag(parser, TELEPHONY_LOOKUP_ELEMENT);
+
+            // Make sure we are on the </telephony_lookup> tag.
+            checkOnEndTag(parser, TELEPHONY_LOOKUP_ELEMENT);
+        }
+    }
+
+    private static void processNetworks(XmlPullParser parser,
+            TelephonyNetworkProcessor processor) throws IOException, XmlPullParserException {
+
+        // Skip over any unexpected elements and process <network> elements.
+        while (findNextStartTagOrEndTagNoRecurse(parser, NETWORK_ELEMENT)) {
+            String mcc = parser.getAttributeValue(
+                    null /* namespace */, MOBILE_COUNTRY_CODE_ATTRIBUTE);
+            if (mcc == null) {
+                throw new XmlPullParserException(
+                        "Unable to find mcc: " + parser.getPositionDescription());
+            }
+
+            String mnc = parser.getAttributeValue(
+                    null /* namespace */, MOBILE_NETWORK_CODE_ATTRIBUTE);
+            if (mnc == null) {
+                throw new XmlPullParserException(
+                        "Unable to find mnc: " + parser.getPositionDescription());
+            }
+
+            String countryCode =
+                    parser.getAttributeValue(null /* namespace */, COUNTRY_ISO_CODE_ATTRIBUTE);
+            if (countryCode == null) {
+                throw new XmlPullParserException(
+                        "Unable to find country: " + parser.getPositionDescription());
+            }
+
+            String debugInfo = parser.getPositionDescription();
+            processor.processNetwork(mcc, mnc, countryCode, debugInfo);
+            // Advance to the next event.
+            parser.next();
+
+            // Skip anything until </network>.
+            consumeUntilEndTag(parser, NETWORK_ELEMENT);
+        }
+    }
+
+    /**
+     * Processes &lt;network&gt; data.
+     */
+    private interface TelephonyNetworkProcessor {
+
+        boolean CONTINUE = true;
+        boolean HALT = false;
+
+        /**
+         * Process network data. Problems with the data are reported as an exception.
+         */
+        void processNetwork(String mcc, String mnc, String countryIso, String debugInfo)
+                throws XmlPullParserException;
+    }
+
+    /**
+     * Validates &lt;network&gt; elements. Intended to be used before a proposed installation of new
+     * data. To be valid the MCC + MNC combination must generate a unique ID, country ISO code must
+     * be normalized.
+     */
+    private static class TelephonyNetworkValidator implements TelephonyNetworkProcessor {
+
+        private final Set<MccMnc> knownMccMncs = new HashSet<>();
+
+        @Override
+        public void processNetwork(String mcc, String mnc, String countryIso, String debugInfo)
+                throws XmlPullParserException {
+            if (mcc == null || mcc.length() != 3 || !isAsciiNumeric(mcc)) {
+                throw new XmlPullParserException(
+                        "MCC is not valid: mcc=" + mcc + " at " + debugInfo);
+            }
+
+            if (mnc == null || !(mnc.length() == 2 || mnc.length() == 3) || !isAsciiNumeric(mnc)) {
+                throw new XmlPullParserException(
+                        "MNC is not valid: mnc=" + mnc + " at " + debugInfo);
+            }
+
+            if (!normalizeCountryIso(countryIso).equals(countryIso)) {
+                throw new XmlPullParserException("Country code: " + countryIso
+                        + " is not normalized at " + debugInfo);
+            }
+
+            MccMnc mccMnc = new MccMnc(mcc, mnc);
+            if (knownMccMncs.contains(mccMnc)) {
+                throw new XmlPullParserException("Second entry for MCC + MNC: " + mccMnc
+                        + " at " + debugInfo);
+            }
+            knownMccMncs.add(mccMnc);
+        }
+
+        private static boolean isAsciiNumeric(String string) {
+            for (int i = 0; i < string.length(); i++) {
+                char character = string.charAt(i);
+                if (character < '0' || character > '9') {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Reads all telephony network time zone information into memory and makes it available as a
+     * {@link TelephonyNetworkFinder}.
+     */
+    private static class TelephonyNetworksExtractor implements TelephonyNetworkProcessor {
+        private List<TelephonyNetwork> networksList = new ArrayList<>(10 /* default */);
+
+        @Override
+        public void processNetwork(String mcc, String mnc, String countryIso, String debugInfo)
+                throws XmlPullParserException {
+            TelephonyNetwork network = TelephonyNetwork.create(mcc, mnc, countryIso);
+            networksList.add(network);
+        }
+
+        TelephonyNetworkFinder getTelephonyNetworkFinder() {
+            return TelephonyNetworkFinder.create(networksList);
+        }
+    }
+}
diff --git a/luni/src/main/java/libcore/timezone/TelephonyNetwork.java b/luni/src/main/java/libcore/timezone/TelephonyNetwork.java
new file mode 100644
index 0000000..e0f26ad
--- /dev/null
+++ b/luni/src/main/java/libcore/timezone/TelephonyNetwork.java
@@ -0,0 +1,130 @@
+/*
+ * 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 libcore.timezone;
+
+import static libcore.timezone.XmlUtils.normalizeCountryIso;
+
+import java.util.Objects;
+
+/**
+ * Information about a telephony network.
+ *
+ * @hide
+ */
+@libcore.api.CorePlatformApi
+public final class TelephonyNetwork {
+
+    /**
+     * A numeric network identifier consisting of the Mobile Country Code (MCC) and the Mobile
+     * Network Code (MNC).
+     *
+     * @hide
+     */
+    public static final class MccMnc {
+        final String mcc;
+        final String mnc;
+
+        public MccMnc(String mcc, String mnc) {
+            this.mcc = mcc;
+            this.mnc = mnc;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            MccMnc mccMnc = (MccMnc) o;
+            return Objects.equals(mcc, mccMnc.mcc)
+                    && Objects.equals(mnc, mccMnc.mnc);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mcc, mnc);
+        }
+
+        @Override
+        public String toString() {
+            return "MccMnc{"
+                    + "mcc=" + mcc
+                    + ", mnc=" + mnc
+                    + '}';
+        }
+    }
+
+    private final MccMnc mccMnc;
+    private final String countryIsoCode;
+
+    public static TelephonyNetwork create(String mcc, String mnc, String countryIsoCode) {
+        String normalizedCountryIso = normalizeCountryIso(countryIsoCode);
+        return new TelephonyNetwork(new MccMnc(mcc, mnc), normalizedCountryIso);
+    }
+
+    private TelephonyNetwork(MccMnc mccMnc, String countryIsoCode) {
+        this.mccMnc = mccMnc;
+        this.countryIsoCode = Objects.requireNonNull(countryIsoCode);
+    }
+
+    public MccMnc getMccMnc() {
+        return mccMnc;
+    }
+
+    @libcore.api.CorePlatformApi
+    public String getMcc() {
+        return mccMnc.mcc;
+    }
+
+    @libcore.api.CorePlatformApi
+    public String getMnc() {
+        return mccMnc.mnc;
+    }
+
+    @libcore.api.CorePlatformApi
+    public String getCountryIsoCode() {
+        return countryIsoCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        TelephonyNetwork that = (TelephonyNetwork) o;
+        return mccMnc.equals(that.mccMnc) &&
+                countryIsoCode.equals(that.countryIsoCode);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mccMnc, countryIsoCode);
+    }
+
+    @Override
+    public String toString() {
+        return "TelephonyNetwork{"
+                + "mccMnc=" + mccMnc
+                + ", countryIsoCode='" + countryIsoCode + '\''
+                + '}';
+    }
+}
diff --git a/luni/src/main/java/libcore/timezone/TelephonyNetworkFinder.java b/luni/src/main/java/libcore/timezone/TelephonyNetworkFinder.java
new file mode 100644
index 0000000..f244159
--- /dev/null
+++ b/luni/src/main/java/libcore/timezone/TelephonyNetworkFinder.java
@@ -0,0 +1,82 @@
+/*
+ * 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 libcore.timezone;
+
+import static libcore.timezone.XmlUtils.normalizeCountryIso;
+
+import libcore.timezone.TelephonyNetwork.MccMnc;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class that can find telephony networks loaded via {@link TelephonyLookup}.
+ * @hide
+ */
+@libcore.api.CorePlatformApi
+public final class TelephonyNetworkFinder {
+
+    private final Map<MccMnc, TelephonyNetwork> networksMap;
+    private final List<TelephonyNetwork> networksList;
+
+    public static TelephonyNetworkFinder create(List<TelephonyNetwork> networksList) {
+        Set<String> validCountryIsoCodes = new HashSet<>();
+        for (String validCountryIsoCode : Locale.getISOCountries()) {
+            validCountryIsoCodes.add(normalizeCountryIso(validCountryIsoCode));
+        }
+
+        Map<MccMnc, TelephonyNetwork> networksMap = new HashMap<>();
+        for (TelephonyNetwork network : networksList) {
+            if (!validCountryIsoCodes.contains(network.getCountryIsoCode())) {
+                System.logW("Unrecognized country code: " + network.getCountryIsoCode()
+                        + " for telephony network=" + network);
+            }
+
+            MccMnc mccMnc = network.getMccMnc();
+            TelephonyNetwork existingEntry = networksMap.put(mccMnc, network);
+            if (existingEntry != null) {
+                System.logW("Duplicate MccMnc detected for " + mccMnc
+                        + ". New entry=" + network + " replacing previous entry.");
+            }
+        }
+        return new TelephonyNetworkFinder(
+                Collections.unmodifiableList(new ArrayList<>(networksList)),
+                networksMap);
+    }
+
+    private TelephonyNetworkFinder(List<TelephonyNetwork> networksList,
+            Map<MccMnc, TelephonyNetwork> networksMap) {
+        this.networksList = networksList;
+        this.networksMap = networksMap;
+    }
+
+    @libcore.api.CorePlatformApi
+    public TelephonyNetwork findNetworkByMccMnc(String mcc, String mnc) {
+        return networksMap.get(new MccMnc(mcc, mnc));
+    }
+
+    // @VisibleForTesting
+    public List<TelephonyNetwork> getAll() {
+        return networksList;
+    }
+}
diff --git a/luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java b/luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java
index 592fac1..b4c8976 100644
--- a/luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java
+++ b/luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java
@@ -27,7 +27,7 @@
 @libcore.api.CorePlatformApi
 public final class TimeZoneDataFiles {
     private static final String ANDROID_ROOT_ENV = "ANDROID_ROOT";
-    private static final String ANDROID_RUNTIME_ROOT_ENV = "ANDROID_RUNTIME_ROOT";
+    private static final String ANDROID_I18N_ROOT_ENV = "ANDROID_I18N_ROOT";
     private static final String ANDROID_TZDATA_ROOT_ENV = "ANDROID_TZDATA_ROOT";
     private static final String ANDROID_DATA_ENV = "ANDROID_DATA";
 
@@ -38,19 +38,14 @@
      * should be tried. See {@link #generateIcuDataPath()} for ICU files instead.
      * <ul>
      * <li>[0] - the location of the file in the /data partition (may not exist).</li>
-     * <li>[1] - the location of the file from the time zone module under /apex (may not exist).
-     * </li>
-     * <li>[2] - the location of the file from the runtime module under /apex (should exist).</li>
+     * <li>[1] - the location of the file from the time zone module under /apex (must exist).</li>
      * </ul>
-     * <li>[3] - the location of the file in the /system partition (should exist).</li>
      */
     // VisibleForTesting
     public static String[] getTimeZoneFilePaths(String fileName) {
         return new String[] {
                 getDataTimeZoneFile(fileName),
-                getTimeZoneModuleFile("tz/" + fileName),
-                getRuntimeModuleFile("tz/" + fileName),
-                getSystemTimeZoneFile(fileName)
+                getTimeZoneModuleTzFile(fileName),
         };
     }
 
@@ -60,26 +55,40 @@
         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;
     }
 
-    public static String getTimeZoneModuleFile(String fileName) {
-        return System.getenv(ANDROID_TZDATA_ROOT_ENV) + "/etc/" + fileName;
+    public static String getTimeZoneModuleTzFile(String fileName) {
+        return getTimeZoneModuleFile("tz/" + fileName);
+    }
+
+    public static String getTimeZoneModuleIcuFile(String fileName) {
+        return getTimeZoneModuleFile("icu/" + fileName);
     }
 
     // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797
     @libcore.api.CorePlatformApi
-    public static String getRuntimeModuleTzVersionFile() {
-        return getRuntimeModuleFile("tz/" + TzDataSetVersion.DEFAULT_FILE_NAME);
+    public static String getTimeZoneModuleTzVersionFile() {
+        return getTimeZoneModuleTzFile(TzDataSetVersion.DEFAULT_FILE_NAME);
     }
 
-    public static String getRuntimeModuleFile(String fileName) {
-        return System.getenv(ANDROID_RUNTIME_ROOT_ENV) + "/etc/" + fileName;
+    // VisibleForTesting
+    public static String getTimeZoneModuleFile(String fileName) {
+        return System.getenv(ANDROID_TZDATA_ROOT_ENV) + "/etc/" + fileName;
     }
 
-    public static String getSystemTimeZoneFile(String fileName) {
+    public static String getI18nModuleIcuFile(String fileName) {
+        return getI18nModuleFile("icu/" + fileName);
+    }
+
+    private static String getI18nModuleFile(String fileName) {
+        return System.getenv(ANDROID_I18N_ROOT_ENV) + "/etc/" + fileName;
+    }
+
+    public static String getSystemTzFile(String fileName) {
         return getEnvironmentPath(ANDROID_ROOT_ENV, "/usr/share/zoneinfo/" + fileName);
     }
 
@@ -90,6 +99,9 @@
     public static String generateIcuDataPath() {
         List<String> paths = new ArrayList<>(3);
 
+        // Note: This logic below should match the logic in IcuRegistration.cpp in external/icu/
+        // to ensure consistent behavior between ICU4C and ICU4J.
+
         // ICU should first look in ANDROID_DATA. This is used for (optional) time zone data
         // delivered by APK (https://source.android.com/devices/tech/config/timezone-rules)
         String dataIcuDataPath =
@@ -100,17 +112,14 @@
 
         // ICU should then look for a mounted time zone module file in /apex. This is used for
         // (optional) time zone data that can be updated with an APEX file.
-        String timeZoneModuleIcuDataPath = getTimeZoneModuleFile("icu/");
-        if (timeZoneModuleIcuDataPath != null) {
-            paths.add(timeZoneModuleIcuDataPath);
-        }
+        String timeZoneModuleIcuDataPath = getTimeZoneModuleIcuFile("");
+        paths.add(timeZoneModuleIcuDataPath);
 
-        // ICU should always look in the runtime module path as this is where most of the data
+        // ICU should always look in the i18n module path as this is where most of the data
         // can be found.
-        String runtimeModuleIcuDataPath = getRuntimeModuleFile("icu/");
-        if (runtimeModuleIcuDataPath != null) {
-            paths.add(runtimeModuleIcuDataPath);
-        }
+        String i18nModuleIcuDataPath = getI18nModuleIcuFile("");
+        paths.add(i18nModuleIcuDataPath);
+
         return String.join(":", paths);
     }
 
diff --git a/luni/src/main/java/libcore/timezone/TimeZoneFinder.java b/luni/src/main/java/libcore/timezone/TimeZoneFinder.java
index eebe8cc..3f18e36 100644
--- a/luni/src/main/java/libcore/timezone/TimeZoneFinder.java
+++ b/luni/src/main/java/libcore/timezone/TimeZoneFinder.java
@@ -16,30 +16,31 @@
 
 package libcore.timezone;
 
+import static libcore.timezone.XmlUtils.checkOnEndTag;
+import static libcore.timezone.XmlUtils.consumeText;
+import static libcore.timezone.XmlUtils.consumeUntilEndTag;
+import static libcore.timezone.XmlUtils.findNextStartTagOrEndTagNoRecurse;
+import static libcore.timezone.XmlUtils.findNextStartTagOrThrowNoRecurse;
+import static libcore.timezone.XmlUtils.normalizeCountryIso;
+import static libcore.timezone.XmlUtils.parseBooleanAttribute;
+import static libcore.timezone.XmlUtils.parseLongAttribute;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlPullParserFactory;
 
-import android.icu.util.TimeZone;
-
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.Reader;
-import java.io.StringReader;
-import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Locale;
 import java.util.Set;
 
 import libcore.timezone.CountryTimeZones.TimeZoneMapping;
+import libcore.timezone.XmlUtils.ReaderSupplier;
 
 /**
  * A class that can find matching time zones by loading data from the tzlookup.xml file.
@@ -48,7 +49,8 @@
 @libcore.api.CorePlatformApi
 public final class TimeZoneFinder {
 
-    private static final String TZLOOKUP_FILE_NAME = "tzlookup.xml";
+    // VisibleForTesting
+    public static final String TZLOOKUP_FILE_NAME = "tzlookup.xml";
 
     // Root element. e.g. <timezones ianaversion="2017b">
     private static final String TIMEZONES_ELEMENT = "timezones";
@@ -57,10 +59,12 @@
     // Country zones section. e.g. <countryzones>
     private static final String COUNTRY_ZONES_ELEMENT = "countryzones";
 
-    // Country data. e.g. <country code="gb" default="Europe/London" everutc="y">
+    // Country data. e.g.
+    // <country code="gb" default="Europe/London" defaultBoost="y" everutc="y">
     private static final String COUNTRY_ELEMENT = "country";
     private static final String COUNTRY_CODE_ATTRIBUTE = "code";
     private static final String DEFAULT_TIME_ZONE_ID_ATTRIBUTE = "default";
+    private static final String DEFAULT_TIME_ZONE_BOOST_ATTRIBUTE = "defaultBoost";
     private static final String EVER_USES_UTC_ATTRIBUTE = "everutc";
 
     // Country -> Time zone mapping. e.g. <id>ZoneId</id>, <id picker="n">ZoneId</id>,
@@ -73,9 +77,6 @@
     private static final String ZONE_SHOW_IN_PICKER_ATTRIBUTE = "picker";
     private static final String ZONE_NOT_USED_AFTER_ATTRIBUTE = "notafter";
 
-    private static final String TRUE_ATTRIBUTE_VALUE = "y";
-    private static final String FALSE_ATTRIBUTE_VALUE = "n";
-
     private static TimeZoneFinder instance;
 
     private final ReaderSupplier xmlSource;
@@ -191,72 +192,6 @@
     }
 
     /**
-     * Returns a frozen ICU time zone that has / would have had the specified offset and DST value
-     * at the specified moment in the specified country.
-     *
-     * <p>In order to be considered a configured zone must match the supplied offset information.
-     *
-     * <p>Matches are considered in a well-defined order. If multiple zones match and one of them
-     * also matches the (optional) bias parameter then the bias time zone will be returned.
-     * Otherwise the first match found is returned.
-     */
-    @libcore.api.CorePlatformApi
-    public TimeZone lookupTimeZoneByCountryAndOffset(
-            String countryIso, int offsetMillis, boolean isDst, long whenMillis, TimeZone bias) {
-
-        CountryTimeZones countryTimeZones = lookupCountryTimeZones(countryIso);
-        if (countryTimeZones == null) {
-            return null;
-        }
-        CountryTimeZones.OffsetResult offsetResult =
-                countryTimeZones.lookupByOffsetWithBias(offsetMillis, isDst, whenMillis, bias);
-        return offsetResult != null ? offsetResult.mTimeZone : null;
-    }
-
-    /**
-     * Returns a "default" time zone ID known to be used in the specified country. This is
-     * the time zone ID that can be used if only the country code is known and can be presumed to be
-     * the "best" choice in the absence of other information. For countries with more than one zone
-     * the time zone will not be correct for everybody.
-     *
-     * <p>If the country code is not recognized or there is an error during lookup this can return
-     * null.
-     */
-    @libcore.api.CorePlatformApi
-    public String lookupDefaultTimeZoneIdByCountry(String countryIso) {
-        CountryTimeZones countryTimeZones = lookupCountryTimeZones(countryIso);
-        return countryTimeZones == null ? null : countryTimeZones.getDefaultTimeZoneId();
-    }
-
-    /**
-     * Returns an immutable list of frozen ICU time zones known to be used in the specified country.
-     * If the country code is not recognized or there is an error during lookup this can return
-     * null. The TimeZones returned will never contain {@link TimeZone#UNKNOWN_ZONE}. This method
-     * can return an empty list in a case when the underlying data files reference only unknown
-     * zone IDs.
-     */
-    @libcore.api.CorePlatformApi
-    public List<TimeZone> lookupTimeZonesByCountry(String countryIso) {
-        CountryTimeZones countryTimeZones = lookupCountryTimeZones(countryIso);
-        return countryTimeZones == null ? null : countryTimeZones.getIcuTimeZones();
-    }
-
-    /**
-     * Returns an immutable list of time zone IDs known to be used in the specified country.
-     * If the country code is not recognized or there is an error during lookup this can return
-     * null. The IDs returned will all be valid for use with
-     * {@link java.util.TimeZone#getTimeZone(String)} and
-     * {@link android.icu.util.TimeZone#getTimeZone(String)}. This method can return an empty list
-     * in a case when the underlying data files reference only unknown zone IDs.
-     */
-    @libcore.api.CorePlatformApi
-    public List<String> lookupTimeZoneIdsByCountry(String countryIso) {
-        CountryTimeZones countryTimeZones = lookupCountryTimeZones(countryIso);
-        return countryTimeZones == null
-                ? null : extractTimeZoneIds(countryTimeZones.getTimeZoneMappings());
-    }
-
-    /**
      * Returns a {@link CountryTimeZones} object associated with the specified country code.
      * Caching is handled as needed. If the country code is not recognized or there is an error
      * during lookup this method can return null.
@@ -295,9 +230,9 @@
 
     /**
      * Processes the XML, applying the {@link TimeZonesProcessor} to the &lt;countryzones&gt;
-     * element. Processing can terminate early if the
-     * {@link TimeZonesProcessor#processCountryZones(String, String, boolean, List, String)} returns
-     * {@link TimeZonesProcessor#HALT} or it throws an exception.
+     * element. Processing can terminate early if the {@link TimeZonesProcessor#processCountryZones(
+     * String, String, boolean, boolean, List, String)} returns {@link TimeZonesProcessor#HALT} or
+     * it throws an exception.
      */
     private void processXml(TimeZonesProcessor processor)
             throws XmlPullParserException, IOException {
@@ -319,14 +254,14 @@
              *       ...
              *       <id>America/Los_Angeles</id>
              *     </country>
-             *     <country code="gb" default="Europe/London">
+             *     <country code="gb" default="Europe/London" defaultBoost="y">
              *       <id>Europe/London</id>
              *     </country>
              *   </countryzones>
              * </timezones>
              */
 
-            findRequiredStartTag(parser, TIMEZONES_ELEMENT);
+            findNextStartTagOrThrowNoRecurse(parser, TIMEZONES_ELEMENT);
 
             // We do not require the ianaversion attribute be present. It is metadata that helps
             // with versioning but is not required.
@@ -338,7 +273,7 @@
 
             // There is only one expected sub-element <countryzones> in the format currently, skip
             // over anything before it.
-            findRequiredStartTag(parser, COUNTRY_ZONES_ELEMENT);
+            findNextStartTagOrThrowNoRecurse(parser, COUNTRY_ZONES_ELEMENT);
 
             if (processCountryZones(parser, processor) == TimeZonesProcessor.HALT) {
                 return;
@@ -363,38 +298,39 @@
             TimeZonesProcessor processor) throws IOException, XmlPullParserException {
 
         // Skip over any unexpected elements and process <country> elements.
-        while (findOptionalStartTag(parser, COUNTRY_ELEMENT)) {
-            if (processor == null) {
-                consumeUntilEndTag(parser, COUNTRY_ELEMENT);
-            } else {
-                String code = parser.getAttributeValue(
-                        null /* namespace */, COUNTRY_CODE_ATTRIBUTE);
-                if (code == null || code.isEmpty()) {
-                    throw new XmlPullParserException(
-                            "Unable to find country code: " + parser.getPositionDescription());
-                }
-                String defaultTimeZoneId = parser.getAttributeValue(
-                        null /* namespace */, DEFAULT_TIME_ZONE_ID_ATTRIBUTE);
-                if (defaultTimeZoneId == null || defaultTimeZoneId.isEmpty()) {
-                    throw new XmlPullParserException("Unable to find default time zone ID: "
-                            + parser.getPositionDescription());
-                }
-                Boolean everUsesUtc = parseBooleanAttribute(
-                        parser, EVER_USES_UTC_ATTRIBUTE, null /* defaultValue */);
-                if (everUsesUtc == null) {
-                    // There is no valid default: we require this to be specified.
-                    throw new XmlPullParserException(
-                            "Unable to find UTC hint attribute (" + EVER_USES_UTC_ATTRIBUTE + "): "
-                            + parser.getPositionDescription());
-                }
+        while (findNextStartTagOrEndTagNoRecurse(parser, COUNTRY_ELEMENT)) {
+            String code = parser.getAttributeValue(
+                    null /* namespace */, COUNTRY_CODE_ATTRIBUTE);
+            if (code == null || code.isEmpty()) {
+                throw new XmlPullParserException(
+                        "Unable to find country code: " + parser.getPositionDescription());
+            }
 
-                String debugInfo = parser.getPositionDescription();
-                List<TimeZoneMapping> timeZoneMappings = parseTimeZoneMappings(parser);
-                boolean result = processor.processCountryZones(code, defaultTimeZoneId, everUsesUtc,
-                        timeZoneMappings, debugInfo);
-                if (result == TimeZonesProcessor.HALT) {
-                    return TimeZonesProcessor.HALT;
-                }
+            String defaultTimeZoneId = parser.getAttributeValue(
+                    null /* namespace */, DEFAULT_TIME_ZONE_ID_ATTRIBUTE);
+            if (defaultTimeZoneId == null || defaultTimeZoneId.isEmpty()) {
+                throw new XmlPullParserException("Unable to find default time zone ID: "
+                        + parser.getPositionDescription());
+            }
+
+            boolean defaultTimeZoneBoost = parseBooleanAttribute(parser,
+                    DEFAULT_TIME_ZONE_BOOST_ATTRIBUTE, false);
+
+            Boolean everUsesUtc = parseBooleanAttribute(
+                    parser, EVER_USES_UTC_ATTRIBUTE, null /* defaultValue */);
+            if (everUsesUtc == null) {
+                // There is no valid default: we require this to be specified.
+                throw new XmlPullParserException(
+                        "Unable to find UTC hint attribute (" + EVER_USES_UTC_ATTRIBUTE + "): "
+                        + parser.getPositionDescription());
+            }
+
+            String debugInfo = parser.getPositionDescription();
+            List<TimeZoneMapping> timeZoneMappings = parseTimeZoneMappings(parser);
+            boolean result = processor.processCountryZones(code, defaultTimeZoneId,
+                    defaultTimeZoneBoost, everUsesUtc, timeZoneMappings, debugInfo);
+            if (result == TimeZonesProcessor.HALT) {
+                return TimeZonesProcessor.HALT;
             }
 
             // Make sure we are on the </country> element.
@@ -409,7 +345,7 @@
         List<TimeZoneMapping> timeZoneMappings = new ArrayList<>();
 
         // Skip over any unexpected elements and process <id> elements.
-        while (findOptionalStartTag(parser, ZONE_ID_ELEMENT)) {
+        while (findNextStartTagOrEndTagNoRecurse(parser, ZONE_ID_ELEMENT)) {
             // The picker attribute is optional and defaulted to true.
             boolean showInPicker = parseBooleanAttribute(
                     parser, ZONE_SHOW_IN_PICKER_ATTRIBUTE, true /* defaultValue */);
@@ -436,177 +372,6 @@
     }
 
     /**
-     * Parses an attribute value, which must be either {@code null} or a valid signed long value.
-     * If the attribute value is {@code null} then {@code defaultValue} is returned. If the
-     * attribute is present but not a valid long value then an XmlPullParserException is thrown.
-     */
-    private static Long parseLongAttribute(XmlPullParser parser, String attributeName,
-            Long defaultValue) throws XmlPullParserException {
-        String attributeValueString = parser.getAttributeValue(null /* namespace */, attributeName);
-        if (attributeValueString == null) {
-            return defaultValue;
-        }
-        try {
-            return Long.parseLong(attributeValueString);
-        } catch (NumberFormatException e) {
-            throw new XmlPullParserException("Attribute \"" + attributeName
-                    + "\" is not a long value: " + parser.getPositionDescription());
-        }
-    }
-
-    /**
-     * Parses an attribute value, which must be either {@code null}, {@code "y"} or {@code "n"}.
-     * If the attribute value is {@code null} then {@code defaultValue} is returned. If the
-     * attribute is present but not "y" or "n" then an XmlPullParserException is thrown.
-     */
-    private static Boolean parseBooleanAttribute(XmlPullParser parser,
-            String attributeName, Boolean defaultValue) throws XmlPullParserException {
-        String attributeValueString = parser.getAttributeValue(null /* namespace */, attributeName);
-        if (attributeValueString == null) {
-            return defaultValue;
-        }
-        boolean isTrue = TRUE_ATTRIBUTE_VALUE.equals(attributeValueString);
-        if (!(isTrue || FALSE_ATTRIBUTE_VALUE.equals(attributeValueString))) {
-            throw new XmlPullParserException("Attribute \"" + attributeName
-                    + "\" is not \"y\" or \"n\": " + parser.getPositionDescription());
-        }
-        return isTrue;
-    }
-
-    private static void findRequiredStartTag(XmlPullParser parser, String elementName)
-            throws IOException, XmlPullParserException {
-        findStartTag(parser, elementName, true /* elementRequired */);
-    }
-
-    /** Called when on a START_TAG. When returning false, it leaves the parser on the END_TAG. */
-    private static boolean findOptionalStartTag(XmlPullParser parser, String elementName)
-            throws IOException, XmlPullParserException {
-        return findStartTag(parser, elementName, false /* elementRequired */);
-    }
-
-    /**
-     * Find a START_TAG with the specified name without decreasing the depth, or increasing the
-     * depth by more than one. More deeply nested elements and text are skipped, even START_TAGs
-     * with matching names. Returns when the START_TAG is found or the next (non-nested) END_TAG is
-     * encountered. The return can take the form of an exception or a false if the START_TAG is not
-     * found. True is returned when it is.
-     */
-    private static boolean findStartTag(
-            XmlPullParser parser, String elementName, boolean elementRequired)
-            throws IOException, XmlPullParserException {
-
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
-            switch (type) {
-                case XmlPullParser.START_TAG:
-                    String currentElementName = parser.getName();
-                    if (elementName.equals(currentElementName)) {
-                        return true;
-                    }
-
-                    // It was not the START_TAG we were looking for. Consume until the end.
-                    parser.next();
-                    consumeUntilEndTag(parser, currentElementName);
-                    break;
-                case XmlPullParser.END_TAG:
-                    if (elementRequired) {
-                        throw new XmlPullParserException(
-                                "No child element found with name " + elementName);
-                    }
-                    return false;
-                default:
-                    // Ignore.
-                    break;
-            }
-        }
-        throw new XmlPullParserException("Unexpected end of document while looking for "
-                + elementName);
-    }
-
-    /**
-     * Consume the remaining contents of an element and move to the END_TAG. Used when processing
-     * within an element can stop. The parser must be pointing at either the END_TAG we are looking
-     * for, a TEXT, or a START_TAG nested within the element to be consumed.
-     */
-    private static void consumeUntilEndTag(XmlPullParser parser, String elementName)
-            throws IOException, XmlPullParserException {
-
-        if (parser.getEventType() == XmlPullParser.END_TAG
-                && elementName.equals(parser.getName())) {
-            // Early return - we are already there.
-            return;
-        }
-
-        // Keep track of the required depth in case there are nested elements to be consumed.
-        // Both the name and the depth must match our expectation to complete.
-
-        int requiredDepth = parser.getDepth();
-        // A TEXT tag would be at the same depth as the END_TAG we are looking for.
-        if (parser.getEventType() == XmlPullParser.START_TAG) {
-            // A START_TAG would have incremented the depth, so we're looking for an END_TAG one
-            // higher than the current tag.
-            requiredDepth--;
-        }
-
-        while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
-            int type = parser.next();
-
-            int currentDepth = parser.getDepth();
-            if (currentDepth < requiredDepth) {
-                throw new XmlPullParserException(
-                        "Unexpected depth while looking for end tag: "
-                                + parser.getPositionDescription());
-            } else if (currentDepth == requiredDepth) {
-                if (type == XmlPullParser.END_TAG) {
-                    if (elementName.equals(parser.getName())) {
-                        return;
-                    }
-                    throw new XmlPullParserException(
-                            "Unexpected eng tag: " + parser.getPositionDescription());
-                }
-            }
-            // Everything else is either a type we are not interested in or is too deep and so is
-            // ignored.
-        }
-        throw new XmlPullParserException("Unexpected end of document");
-    }
-
-    /**
-     * Reads the text inside the current element. Should be called when the parser is currently
-     * on the START_TAG before the TEXT. The parser will be positioned on the END_TAG after this
-     * call when it completes successfully.
-     */
-    private static String consumeText(XmlPullParser parser)
-            throws IOException, XmlPullParserException {
-
-        int type = parser.next();
-        String text;
-        if (type == XmlPullParser.TEXT) {
-            text = parser.getText();
-        } else {
-            throw new XmlPullParserException("Text not found. Found type=" + type
-                    + " at " + parser.getPositionDescription());
-        }
-
-        type = parser.next();
-        if (type != XmlPullParser.END_TAG) {
-            throw new XmlPullParserException(
-                    "Unexpected nested tag or end of document when expecting text: type=" + type
-                            + " at " + parser.getPositionDescription());
-        }
-        return text;
-    }
-
-    private static void checkOnEndTag(XmlPullParser parser, String elementName)
-            throws XmlPullParserException {
-        if (!(parser.getEventType() == XmlPullParser.END_TAG
-                && parser.getName().equals(elementName))) {
-            throw new XmlPullParserException(
-                    "Unexpected tag encountered: " + parser.getPositionDescription());
-        }
-    }
-
-    /**
      * Processes &lt;timezones&gt; data.
      */
     private interface TimeZonesProcessor {
@@ -633,7 +398,8 @@
          * <p>The default implementation returns {@link #CONTINUE}.
          */
         default boolean processCountryZones(String countryIso, String defaultTimeZoneId,
-                boolean everUsesUtc, List<TimeZoneMapping> timeZoneMappings, String debugInfo)
+                boolean defaultTimeZoneBoost, boolean everUsesUtc,
+                List<TimeZoneMapping> timeZoneMappings, String debugInfo)
                 throws XmlPullParserException {
             return CONTINUE;
         }
@@ -653,7 +419,8 @@
 
         @Override
         public boolean processCountryZones(String countryIso, String defaultTimeZoneId,
-                boolean everUsesUtc, List<TimeZoneMapping> timeZoneMappings, String debugInfo)
+                boolean defaultTimeZoneBoost, boolean everUsesUtc,
+                List<TimeZoneMapping> timeZoneMappings, String debugInfo)
                 throws XmlPullParserException {
             if (!normalizeCountryIso(countryIso).equals(countryIso)) {
                 throw new XmlPullParserException("Country code: " + countryIso
@@ -706,11 +473,13 @@
 
         @Override
         public boolean processCountryZones(String countryIso, String defaultTimeZoneId,
-                boolean everUsesUtc, List<TimeZoneMapping> timeZoneMappings, String debugInfo)
+                boolean defaultTimeZoneBoost, boolean everUsesUtc,
+                List<TimeZoneMapping> timeZoneMappings, String debugInfo)
                 throws XmlPullParserException {
 
             CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                    countryIso, defaultTimeZoneId, everUsesUtc, timeZoneMappings, debugInfo);
+                    countryIso, defaultTimeZoneId, defaultTimeZoneBoost, everUsesUtc,
+                    timeZoneMappings, debugInfo);
             countryTimeZonesList.add(countryTimeZones);
             return CONTINUE;
         }
@@ -736,13 +505,15 @@
 
         @Override
         public boolean processCountryZones(String countryIso, String defaultTimeZoneId,
-                boolean everUsesUtc, List<TimeZoneMapping> timeZoneMappings, String debugInfo) {
+                boolean defaultTimeZoneBoost, boolean everUsesUtc,
+                List<TimeZoneMapping> timeZoneMappings, String debugInfo) {
             countryIso = normalizeCountryIso(countryIso);
             if (!countryCodeToMatch.equals(countryIso)) {
                 return CONTINUE;
             }
             validatedCountryTimeZones = CountryTimeZones.createValidated(countryIso,
-                    defaultTimeZoneId, everUsesUtc, timeZoneMappings, debugInfo);
+                    defaultTimeZoneId, defaultTimeZoneBoost, everUsesUtc, timeZoneMappings,
+                    debugInfo);
 
             return HALT;
         }
@@ -755,40 +526,4 @@
         }
     }
 
-    /**
-     * A source of Readers that can be used repeatedly.
-     */
-    private interface ReaderSupplier {
-        /** Returns a Reader. Throws an IOException if the Reader cannot be created. */
-        Reader get() throws IOException;
-
-        static ReaderSupplier forFile(String fileName, Charset charSet) throws IOException {
-            Path file = Paths.get(fileName);
-            if (!Files.exists(file)) {
-                throw new FileNotFoundException(fileName + " does not exist");
-            }
-            if (!Files.isRegularFile(file) && Files.isReadable(file)) {
-                throw new IOException(fileName + " must be a regular readable file.");
-            }
-            return () -> Files.newBufferedReader(file, charSet);
-        }
-
-        static ReaderSupplier forString(String xml) {
-            return () -> new StringReader(xml);
-        }
-    }
-
-    private static List<String> extractTimeZoneIds(List<TimeZoneMapping> timeZoneMappings) {
-        List<String> zoneIds = new ArrayList<>(timeZoneMappings.size());
-        for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
-            zoneIds.add(timeZoneMapping.timeZoneId);
-        }
-        return Collections.unmodifiableList(zoneIds);
-    }
-
-    static String normalizeCountryIso(String countryIso) {
-        // Lowercase ASCII is normalized for the purposes of the input files and the code in this
-        // class and related classes.
-        return countryIso.toLowerCase(Locale.US);
-    }
 }
diff --git a/luni/src/main/java/libcore/timezone/TzDataSetVersion.java b/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
index 2ba64a0..8b97069b 100644
--- a/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
+++ b/luni/src/main/java/libcore/timezone/TzDataSetVersion.java
@@ -29,7 +29,7 @@
  * @hide
  */
 @libcore.api.CorePlatformApi
-public class TzDataSetVersion {
+public final class TzDataSetVersion {
 
     // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797
     /**
@@ -45,7 +45,7 @@
      * version to 1 when doing so.
      */
     // @VisibleForTesting : Keep this inline-able: it is used from CTS tests.
-    public static final int CURRENT_FORMAT_MAJOR_VERSION = 3; // Android Q
+    public static final int CURRENT_FORMAT_MAJOR_VERSION = 4; // Android R
 
     /**
      * Returns the major tz data format version supported by this device.
@@ -102,14 +102,10 @@
                     + REVISION_PATTERN.pattern()
                     + ".*" /* ignore trailing */);
 
-    public final int formatMajorVersion;
-    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;
-
-    public final int revision;
+    private final int formatMajorVersion;
+    private final int formatMinorVersion;
+    private final String rulesVersion;
+    private final int revision;
 
     @libcore.api.CorePlatformApi
     public TzDataSetVersion(int formatMajorVersion, int formatMinorVersion, String rulesVersion,
@@ -155,6 +151,38 @@
         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));
+    }
+
+    @libcore.api.CorePlatformApi
+    public int getFormatMajorVersion() {
+        return formatMajorVersion;
+    }
+
+    @libcore.api.CorePlatformApi
+    public int getFormatMinorVersion() {
+        return formatMinorVersion;
+    }
+
+    @libcore.api.CorePlatformApi
+    public String getRulesVersion() {
+        return rulesVersion;
+    }
+
+    // Remove from CorePlatformApi when all users in platform code are removed. http://b/123398797
+    @libcore.api.CorePlatformApi
+    public int getRevision() {
+        return revision;
+    }
+
     // 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/XmlUtils.java b/luni/src/main/java/libcore/timezone/XmlUtils.java
new file mode 100644
index 0000000..a9616f9
--- /dev/null
+++ b/luni/src/main/java/libcore/timezone/XmlUtils.java
@@ -0,0 +1,254 @@
+/*
+ * 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 libcore.timezone;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Locale;
+
+class XmlUtils {
+
+    private static final String TRUE_ATTRIBUTE_VALUE = "y";
+
+    private static final String FALSE_ATTRIBUTE_VALUE = "n";
+
+    private XmlUtils() {}
+
+    /**
+     * Parses an attribute value, which must be either {@code null} or a valid signed long value.
+     * If the attribute value is {@code null} then {@code defaultValue} is returned. If the
+     * attribute is present but not a valid long value then an XmlPullParserException is thrown.
+     */
+    static Long parseLongAttribute(XmlPullParser parser, String attributeName,
+            Long defaultValue) throws XmlPullParserException {
+        String attributeValueString = parser.getAttributeValue(null /* namespace */, attributeName);
+        if (attributeValueString == null) {
+            return defaultValue;
+        }
+        try {
+            return Long.parseLong(attributeValueString);
+        } catch (NumberFormatException e) {
+            throw new XmlPullParserException("Attribute \"" + attributeName
+                    + "\" is not a long value: " + parser.getPositionDescription());
+        }
+    }
+
+    /**
+     * Parses an attribute value, which must be either {@code null}, {@code "y"} or {@code "n"}.
+     * If the attribute value is {@code null} then {@code defaultValue} is returned. If the
+     * attribute is present but not "y" or "n" then an XmlPullParserException is thrown.
+     */
+    static Boolean parseBooleanAttribute(XmlPullParser parser,
+            String attributeName, Boolean defaultValue) throws XmlPullParserException {
+        String attributeValueString = parser.getAttributeValue(null /* namespace */, attributeName);
+        if (attributeValueString == null) {
+            return defaultValue;
+        }
+        boolean isTrue = TRUE_ATTRIBUTE_VALUE.equals(attributeValueString);
+        if (!(isTrue || FALSE_ATTRIBUTE_VALUE.equals(attributeValueString))) {
+            throw new XmlPullParserException("Attribute \"" + attributeName
+                    + "\" is not \"y\" or \"n\": " + parser.getPositionDescription());
+        }
+        return isTrue;
+    }
+
+    /**
+     * Advances the the parser to the START_TAG for the specified element without decreasing the
+     * depth, or increasing the depth by more than one (i.e. no recursion into child nodes).
+     * If the next (non-nested) END_TAG an exception is thrown. Throws an exception if the end of
+     * the document is encountered unexpectedly.
+     */
+    static void findNextStartTagOrThrowNoRecurse(XmlPullParser parser, String elementName)
+            throws IOException, XmlPullParserException {
+        if (!findNextStartTagOrEndTagNoRecurse(parser, elementName)) {
+            throw new XmlPullParserException("No next element found with name " + elementName);
+        }
+    }
+
+    /**
+     * Advances the the parser to the START_TAG for the specified element without decreasing the
+     * depth, or increasing the depth by more than one (i.e. no recursion into child nodes).
+     * Returns {@code true} if the requested START_TAG is found, or {@code false} when the next
+     * (non-nested) END_TAG is encountered instead. Throws an exception if the end of the document
+     * is encountered unexpectedly.
+     */
+    static boolean findNextStartTagOrEndTagNoRecurse(XmlPullParser parser, String elementName)
+            throws IOException, XmlPullParserException {
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            switch (type) {
+                case XmlPullParser.START_TAG:
+                    String currentElementName = parser.getName();
+                    if (elementName.equals(currentElementName)) {
+                        return true;
+                    }
+
+                    // It was not the START_TAG we were looking for. Consume until the end.
+                    parser.next();
+                    consumeUntilEndTag(parser, currentElementName);
+                    break;
+                case XmlPullParser.END_TAG:
+                    return false;
+                default:
+                    // Ignore.
+                    break;
+            }
+        }
+        throw new XmlPullParserException("Unexpected end of document while looking for "
+                + elementName);
+    }
+
+    /**
+     * Consume any remaining contents of an element and move to the END_TAG. Used when processing
+     * within an element can stop.
+     *
+     * <p>When called, the parser must be pointing at one of:
+     * <ul>
+     *     <li>the END_TAG we are looking for</li>
+     *     <li>a TEXT</li>
+     *     <li>a START_TAG nested within the element that can be consumed</li>
+     * </ul>
+     * Note: The parser synthesizes an END_TAG for self-closing tags so this works for them too.
+     */
+    static void consumeUntilEndTag(XmlPullParser parser, String elementName)
+            throws IOException, XmlPullParserException {
+
+        if (isEndTag(parser, elementName)) {
+            // Early return - we are already there.
+            return;
+        }
+
+        // Keep track of the required depth in case there are nested elements to be consumed.
+        // Both the name and the depth must match our expectation to complete.
+
+        int requiredDepth = parser.getDepth();
+        // A TEXT tag would be at the same depth as the END_TAG we are looking for.
+        if (parser.getEventType() == XmlPullParser.START_TAG) {
+            // A START_TAG would have incremented the depth, so we're looking for an END_TAG one
+            // higher than the current tag.
+            requiredDepth--;
+        }
+
+        while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+            int type = parser.next();
+
+            int currentDepth = parser.getDepth();
+            if (currentDepth < requiredDepth) {
+                throw new XmlPullParserException(
+                        "Unexpected depth while looking for end tag: "
+                                + parser.getPositionDescription());
+            } else if (currentDepth == requiredDepth) {
+                if (type == XmlPullParser.END_TAG) {
+                    if (elementName.equals(parser.getName())) {
+                        return;
+                    }
+                    throw new XmlPullParserException(
+                            "Unexpected eng tag: " + parser.getPositionDescription());
+                }
+            }
+            // Everything else is either a type we are not interested in or is too deep and so is
+            // ignored.
+        }
+        throw new XmlPullParserException("Unexpected end of document");
+    }
+
+    /**
+     * Throws an exception if the current element is not an end tag.
+     * Note: The parser synthesizes an END_TAG for self-closing tags so this works for them too.
+     */
+    static void checkOnEndTag(XmlPullParser parser, String elementName)
+            throws XmlPullParserException {
+        if (!isEndTag(parser, elementName)) {
+            throw new XmlPullParserException(
+                    "Unexpected tag encountered: " + parser.getPositionDescription());
+        }
+    }
+
+    /**
+     * Returns true if the current tag is an end tag.
+     * Note: The parser synthesizes an END_TAG for self-closing tags so this works for them too.
+     */
+    private static boolean isEndTag(XmlPullParser parser, String elementName)
+            throws XmlPullParserException {
+        return parser.getEventType() == XmlPullParser.END_TAG
+                && parser.getName().equals(elementName);
+    }
+
+    static String normalizeCountryIso(String countryIso) {
+        // Lowercase ASCII is normalized for the purposes of the input files and the code in this
+        // class and related classes.
+        return countryIso.toLowerCase(Locale.US);
+    }
+
+    /**
+     * Reads the text inside the current element. Should be called when the parser is currently
+     * on the START_TAG before the TEXT. The parser will be positioned on the END_TAG after this
+     * call when it completes successfully.
+     */
+    static String consumeText(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+
+        int type = parser.next();
+        String text;
+        if (type == XmlPullParser.TEXT) {
+            text = parser.getText();
+        } else {
+            throw new XmlPullParserException("Text not found. Found type=" + type
+                    + " at " + parser.getPositionDescription());
+        }
+
+        type = parser.next();
+        if (type != XmlPullParser.END_TAG) {
+            throw new XmlPullParserException(
+                    "Unexpected nested tag or end of document when expecting text: type=" + type
+                            + " at " + parser.getPositionDescription());
+        }
+        return text;
+    }
+
+    /**
+     * A source of Readers that can be used repeatedly.
+     */
+    interface ReaderSupplier {
+        /** Returns a Reader. Throws an IOException if the Reader cannot be created. */
+        Reader get() throws IOException;
+
+        static ReaderSupplier forFile(String fileName, Charset charSet) throws IOException {
+            Path file = Paths.get(fileName);
+            if (!Files.exists(file)) {
+                throw new FileNotFoundException(fileName + " does not exist");
+            }
+            if (!Files.isRegularFile(file) && Files.isReadable(file)) {
+                throw new IOException(fileName + " must be a regular readable file.");
+            }
+            return () -> Files.newBufferedReader(file, charSet);
+        }
+
+        static ReaderSupplier forString(String xml) {
+            return () -> new StringReader(xml);
+        }
+    }
+}
diff --git a/luni/src/main/java/libcore/timezone/ZoneInfoDB.java b/luni/src/main/java/libcore/timezone/ZoneInfoDB.java
deleted file mode 100644
index ca29319..0000000
--- a/luni/src/main/java/libcore/timezone/ZoneInfoDB.java
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright (C) 2007 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.timezone;
-
-import android.system.ErrnoException;
-import dalvik.annotation.optimization.ReachabilitySensitive;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import libcore.io.BufferIterator;
-import libcore.io.MemoryMappedFile;
-import libcore.util.BasicLruCache;
-import libcore.util.ZoneInfo;
-
-/**
- * A class used to initialize the time zone database. This implementation uses the
- * Olson tzdata as the source of time zone information. However, to conserve
- * disk space (inodes) and reduce I/O, all the data is concatenated into a single file,
- * with an index to indicate the starting position of each time zone record.
- *
- * @hide - used to implement TimeZone
- */
-@libcore.api.CorePlatformApi
-public final class ZoneInfoDB {
-
-  // VisibleForTesting
-  public static final String TZDATA_FILE = "tzdata";
-
-  private static final TzData DATA =
-          TzData.loadTzDataWithFallback(TimeZoneDataFiles.getTimeZoneFilePaths(TZDATA_FILE));
-
-  /** @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 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;
-
-    /**
-     * {@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;
-
-    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.
-
-    /**
-     * 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 + " 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();
-      if (tzData.loadData(path)) {
-        return tzData;
-      }
-      return null;
-    }
-
-    private static TzData createFallback() {
-      TzData tzData = new TzData();
-      tzData.populateFallback();
-      return tzData;
-    }
-
-    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 + " 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 ZoneInfoDB() {
-  }
-
-  @libcore.api.CorePlatformApi
-  public static TzData getInstance() {
-    return DATA;
-  }
-}
diff --git a/luni/src/main/java/libcore/timezone/ZoneInfoDb.java b/luni/src/main/java/libcore/timezone/ZoneInfoDb.java
new file mode 100644
index 0000000..a94d293
--- /dev/null
+++ b/luni/src/main/java/libcore/timezone/ZoneInfoDb.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2007 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.timezone;
+
+import android.system.ErrnoException;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import libcore.io.BufferIterator;
+import libcore.io.MemoryMappedFile;
+import libcore.util.BasicLruCache;
+import libcore.util.ZoneInfo;
+
+/**
+ * A class used to initialize the time zone database. This implementation uses the
+ * Olson tzdata as the source of time zone information. However, to conserve
+ * disk space (inodes) and reduce I/O, all the data is concatenated into a single file,
+ * with an index to indicate the starting position of each time zone record.
+ *
+ * @hide - used to implement TimeZone
+ */
+@libcore.api.CorePlatformApi
+public final class ZoneInfoDb implements AutoCloseable {
+
+  // VisibleForTesting
+  public static final String TZDATA_FILE_NAME = "tzdata";
+
+  private static final ZoneInfoDb DATA = ZoneInfoDb.loadTzDataWithFallback(
+          TimeZoneDataFiles.getTimeZoneFilePaths(TZDATA_FILE_NAME));
+
+  // 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;
+
+  // 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;
+
+  /**
+   * 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;
+
+  /**
+   * 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);
+      }
+    }
+  };
+
+  @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;
+      }
+    }
+
+    // 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 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 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/BasicLruCache.java b/luni/src/main/java/libcore/util/BasicLruCache.java
index 20a3bee..e3ddc64 100644
--- a/luni/src/main/java/libcore/util/BasicLruCache.java
+++ b/luni/src/main/java/libcore/util/BasicLruCache.java
@@ -16,7 +16,7 @@
 
 package libcore.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
diff --git a/luni/src/main/java/libcore/util/CoreLibraryDebug.java b/luni/src/main/java/libcore/util/CoreLibraryDebug.java
index c39017f..0d6ee46 100644
--- a/luni/src/main/java/libcore/util/CoreLibraryDebug.java
+++ b/luni/src/main/java/libcore/util/CoreLibraryDebug.java
@@ -16,10 +16,12 @@
 
 package libcore.util;
 
+import com.android.icu.util.Icu4cMetadata;
+
 import libcore.timezone.TimeZoneDataFiles;
 import libcore.timezone.TzDataSetVersion;
 import libcore.timezone.TzDataSetVersion.TzDataSetException;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
 
 import java.io.File;
 import java.io.IOException;
@@ -59,44 +61,36 @@
         // Time zone module tz data set.
         {
             String tzDataModulePrefix = debugKeyPrefix + "tzdata_module_";
-            String versionFileName = TimeZoneDataFiles.getTimeZoneModuleFile(
-                    "tz/" + TzDataSetVersion.DEFAULT_FILE_NAME);
-            addTzDataSetVersionDebugInfo(versionFileName, tzDataModulePrefix, debugInfo);
-        }
-
-        // Runtime module tz data set.
-        {
-            String runtimeModulePrefix = debugKeyPrefix + "runtime_module_";
-            String versionFileName = TimeZoneDataFiles.getRuntimeModuleFile(
-                    "tz/" + TzDataSetVersion.DEFAULT_FILE_NAME);
-            addTzDataSetVersionDebugInfo(versionFileName, runtimeModulePrefix, debugInfo);
+            String versionFile =
+                    TimeZoneDataFiles.getTimeZoneModuleTzFile(TzDataSetVersion.DEFAULT_FILE_NAME);
+            addTzDataSetVersionDebugInfo(versionFile, tzDataModulePrefix, debugInfo);
         }
 
         // /system tz data set.
         {
             String systemDirPrefix = debugKeyPrefix + "system_";
-            String versionFileName =
-                    TimeZoneDataFiles.getSystemTimeZoneFile(TzDataSetVersion.DEFAULT_FILE_NAME);
-            addTzDataSetVersionDebugInfo(versionFileName, systemDirPrefix, debugInfo);
+            String versionFile =
+                    TimeZoneDataFiles.getSystemTzFile(TzDataSetVersion.DEFAULT_FILE_NAME);
+            addTzDataSetVersionDebugInfo(versionFile, systemDirPrefix, debugInfo);
         }
     }
 
-    private static void addTzDataSetVersionDebugInfo(String tzDataSetVersionFileName,
+    private static void addTzDataSetVersionDebugInfo(String tzDataSetVersionFile,
             String debugKeyPrefix, DebugInfo debugInfo) {
-        File file = new File(tzDataSetVersionFileName);
+        File file = new File(tzDataSetVersionFile);
         String statusKey = debugKeyPrefix + "status";
         if (file.exists()) {
             try {
                 TzDataSetVersion tzDataSetVersion =
                         TzDataSetVersion.readFromFile(file);
-                String formatVersionString = tzDataSetVersion.formatMajorVersion + "."
-                        + tzDataSetVersion.formatMinorVersion;
+                String formatVersionString = tzDataSetVersion.getFormatMajorVersion() + "."
+                        + tzDataSetVersion.getFormatMinorVersion();
                 debugInfo.addStringEntry(statusKey, "OK")
                         .addStringEntry(debugKeyPrefix + "formatVersion", formatVersionString)
                         .addStringEntry(debugKeyPrefix + "rulesVersion",
-                                tzDataSetVersion.rulesVersion)
+                                tzDataSetVersion.getRulesVersion())
                         .addStringEntry(debugKeyPrefix + "revision",
-                                tzDataSetVersion.revision);
+                                tzDataSetVersion.getRevision());
             } catch (IOException | TzDataSetException e) {
                 debugInfo.addStringEntry(statusKey, "ERROR");
                 debugInfo.addStringEntry(debugKeyPrefix + "exception_class", e.getClass().getName());
@@ -115,9 +109,9 @@
                 android.icu.util.TimeZone.getTZDataVersion());
         debugInfo.addStringEntry(
                 debugKeyPrefix + "libcore.tzdb_version",
-                ZoneInfoDB.getInstance().getVersion());
+                ZoneInfoDb.getInstance().getVersion());
         debugInfo.addStringEntry(
                 debugKeyPrefix + "icu4c.tzdb_version",
-                libcore.icu.ICU.getTZDataVersion());
+                Icu4cMetadata.getTzdbVersion());
     }
 }
diff --git a/luni/src/main/java/libcore/util/EmptyArray.java b/luni/src/main/java/libcore/util/EmptyArray.java
index 5b60683..0d1e321 100644
--- a/luni/src/main/java/libcore/util/EmptyArray.java
+++ b/luni/src/main/java/libcore/util/EmptyArray.java
@@ -16,7 +16,8 @@
 
 package libcore.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 /** @hide */
 @libcore.api.CorePlatformApi
@@ -25,22 +26,26 @@
 
     @libcore.api.CorePlatformApi
     public static final boolean[] BOOLEAN = new boolean[0];
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk=VersionCodes.Q,
+            publicAlternatives="Use {@code new byte[0]} instead.")
     @libcore.api.CorePlatformApi
     public static final byte[] BYTE = new byte[0];
     public static final char[] CHAR = new char[0];
     public static final double[] DOUBLE = new double[0];
     @libcore.api.CorePlatformApi
     public static final float[] FLOAT = new float[0];
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk=VersionCodes.Q,
+            publicAlternatives="Use {@code new int[0]} instead.")
     @libcore.api.CorePlatformApi
     public static final int[] INT = new int[0];
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk=VersionCodes.Q,
+            publicAlternatives="Use {@code new long[0]} instead.")
     @libcore.api.CorePlatformApi
     public static final long[] LONG = new long[0];
 
     public static final Class<?>[] CLASS = new Class[0];
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk=VersionCodes.Q,
+            publicAlternatives="Use {@code new Object[0]} instead.")
     @libcore.api.CorePlatformApi
     public static final Object[] OBJECT = new Object[0];
     @libcore.api.CorePlatformApi
diff --git a/luni/src/main/java/libcore/util/FP16.java b/luni/src/main/java/libcore/util/FP16.java
new file mode 100644
index 0000000..602e1d4
--- /dev/null
+++ b/luni/src/main/java/libcore/util/FP16.java
@@ -0,0 +1,750 @@
+/*
+ * 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 libcore.util;
+
+/**
+ * <p>The {@code FP16} class is a wrapper and a utility class to manipulate half-precision 16-bit
+ * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a>
+ * floating point data types (also called fp16 or binary16). A half-precision float can be
+ * created from or converted to single-precision floats, and is stored in a short data type.
+ *
+ * <p>The IEEE 754 standard specifies an fp16 as having the following format:</p>
+ * <ul>
+ * <li>Sign bit: 1 bit</li>
+ * <li>Exponent width: 5 bits</li>
+ * <li>Significand: 10 bits</li>
+ * </ul>
+ *
+ * <p>The format is laid out as follows:</p>
+ * <pre>
+ * 1   11111   1111111111
+ * ^   --^--   -----^----
+ * sign  |          |_______ significand
+ *       |
+ *       -- exponent
+ * </pre>
+ *
+ * <p>Half-precision floating points can be useful to save memory and/or
+ * bandwidth at the expense of range and precision when compared to single-precision
+ * floating points (fp32).</p>
+ * <p>To help you decide whether fp16 is the right storage type for you need, please
+ * refer to the table below that shows the available precision throughout the range of
+ * possible values. The <em>precision</em> column indicates the step size between two
+ * consecutive numbers in a specific part of the range.</p>
+ *
+ * <table summary="Precision of fp16 across the range">
+ *     <tr><th>Range start</th><th>Precision</th></tr>
+ *     <tr><td>0</td><td>1 &frasl; 16,777,216</td></tr>
+ *     <tr><td>1 &frasl; 16,384</td><td>1 &frasl; 16,777,216</td></tr>
+ *     <tr><td>1 &frasl; 8,192</td><td>1 &frasl; 8,388,608</td></tr>
+ *     <tr><td>1 &frasl; 4,096</td><td>1 &frasl; 4,194,304</td></tr>
+ *     <tr><td>1 &frasl; 2,048</td><td>1 &frasl; 2,097,152</td></tr>
+ *     <tr><td>1 &frasl; 1,024</td><td>1 &frasl; 1,048,576</td></tr>
+ *     <tr><td>1 &frasl; 512</td><td>1 &frasl; 524,288</td></tr>
+ *     <tr><td>1 &frasl; 256</td><td>1 &frasl; 262,144</td></tr>
+ *     <tr><td>1 &frasl; 128</td><td>1 &frasl; 131,072</td></tr>
+ *     <tr><td>1 &frasl; 64</td><td>1 &frasl; 65,536</td></tr>
+ *     <tr><td>1 &frasl; 32</td><td>1 &frasl; 32,768</td></tr>
+ *     <tr><td>1 &frasl; 16</td><td>1 &frasl; 16,384</td></tr>
+ *     <tr><td>1 &frasl; 8</td><td>1 &frasl; 8,192</td></tr>
+ *     <tr><td>1 &frasl; 4</td><td>1 &frasl; 4,096</td></tr>
+ *     <tr><td>1 &frasl; 2</td><td>1 &frasl; 2,048</td></tr>
+ *     <tr><td>1</td><td>1 &frasl; 1,024</td></tr>
+ *     <tr><td>2</td><td>1 &frasl; 512</td></tr>
+ *     <tr><td>4</td><td>1 &frasl; 256</td></tr>
+ *     <tr><td>8</td><td>1 &frasl; 128</td></tr>
+ *     <tr><td>16</td><td>1 &frasl; 64</td></tr>
+ *     <tr><td>32</td><td>1 &frasl; 32</td></tr>
+ *     <tr><td>64</td><td>1 &frasl; 16</td></tr>
+ *     <tr><td>128</td><td>1 &frasl; 8</td></tr>
+ *     <tr><td>256</td><td>1 &frasl; 4</td></tr>
+ *     <tr><td>512</td><td>1 &frasl; 2</td></tr>
+ *     <tr><td>1,024</td><td>1</td></tr>
+ *     <tr><td>2,048</td><td>2</td></tr>
+ *     <tr><td>4,096</td><td>4</td></tr>
+ *     <tr><td>8,192</td><td>8</td></tr>
+ *     <tr><td>16,384</td><td>16</td></tr>
+ *     <tr><td>32,768</td><td>32</td></tr>
+ * </table>
+ *
+ * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
+ *
+ * @hide
+ */
+
+@libcore.api.CorePlatformApi
+public class FP16 {
+    /**
+     * The number of bits used to represent a half-precision float value.
+     */
+    @libcore.api.CorePlatformApi
+    public static final int SIZE = 16;
+
+    /**
+     * Epsilon is the difference between 1.0 and the next value representable
+     * by a half-precision floating-point.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short EPSILON = (short) 0x1400;
+
+    /**
+     * Maximum exponent a finite half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final int MAX_EXPONENT = 15;
+    /**
+     * Minimum exponent a normalized half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final int MIN_EXPONENT = -14;
+
+    /**
+     * Smallest negative value a half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short LOWEST_VALUE = (short) 0xfbff;
+    /**
+     * Maximum positive finite value a half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short MAX_VALUE = (short) 0x7bff;
+    /**
+     * Smallest positive normal value a half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short MIN_NORMAL = (short) 0x0400;
+    /**
+     * Smallest positive non-zero value a half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short MIN_VALUE = (short) 0x0001;
+    /**
+     * A Not-a-Number representation of a half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short NaN = (short) 0x7e00;
+    /**
+     * Negative infinity of type half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short NEGATIVE_INFINITY = (short) 0xfc00;
+    /**
+     * Negative 0 of type half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short NEGATIVE_ZERO = (short) 0x8000;
+    /**
+     * Positive infinity of type half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short POSITIVE_INFINITY = (short) 0x7c00;
+    /**
+     * Positive 0 of type half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short POSITIVE_ZERO = (short) 0x0000;
+
+    @libcore.api.CorePlatformApi
+    public static final int SIGN_SHIFT                = 15;
+    @libcore.api.CorePlatformApi
+    public static final int EXPONENT_SHIFT            = 10;
+    @libcore.api.CorePlatformApi
+    public static final int SIGN_MASK                 = 0x8000;
+    @libcore.api.CorePlatformApi
+    public static final int SHIFTED_EXPONENT_MASK     = 0x1f;
+    @libcore.api.CorePlatformApi
+    public static final int SIGNIFICAND_MASK          = 0x3ff;
+    @libcore.api.CorePlatformApi
+    public static final int EXPONENT_SIGNIFICAND_MASK = 0x7fff;
+    @libcore.api.CorePlatformApi
+    public static final int EXPONENT_BIAS             = 15;
+
+    private static final int FP32_SIGN_SHIFT            = 31;
+    private static final int FP32_EXPONENT_SHIFT        = 23;
+    private static final int FP32_SHIFTED_EXPONENT_MASK = 0xff;
+    private static final int FP32_SIGNIFICAND_MASK      = 0x7fffff;
+    private static final int FP32_EXPONENT_BIAS         = 127;
+    private static final int FP32_QNAN_MASK             = 0x400000;
+    private static final int FP32_DENORMAL_MAGIC = 126 << 23;
+    private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC);
+
+    /** Hidden constructor to prevent instantiation. */
+    private FP16() {}
+
+    /**
+     * <p>Compares the two specified half-precision float values. The following
+     * conditions apply during the comparison:</p>
+     *
+     * <ul>
+     * <li>{@link #NaN} is considered by this method to be equal to itself and greater
+     * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li>
+     * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than
+     * {@link #NEGATIVE_ZERO}.</li>
+     * </ul>
+     *
+     * @param x The first half-precision float value to compare.
+     * @param y The second half-precision float value to compare
+     *
+     * @return  The value {@code 0} if {@code x} is numerically equal to {@code y}, a
+     *          value less than {@code 0} if {@code x} is numerically less than {@code y},
+     *          and a value greater than {@code 0} if {@code x} is numerically greater
+     *          than {@code y}
+     */
+    @libcore.api.CorePlatformApi
+    public static int compare(short x, short y) {
+        if (less(x, y)) return -1;
+        if (greater(x, y)) return 1;
+
+        // Collapse NaNs, akin to halfToIntBits(), but we want to keep
+        // (signed) short value types to preserve the ordering of -0.0
+        // and +0.0
+        short xBits = isNaN(x) ? NaN : x;
+        short yBits = isNaN(y) ? NaN : y;
+
+        return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1));
+    }
+
+    /**
+     * Returns the closest integral half-precision float value to the specified
+     * half-precision float value. Special values are handled in the
+     * following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The value of the specified half-precision float rounded to the nearest
+     *         half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short rint(short h) {
+        int bits = h & 0xffff;
+        int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+        int result = bits;
+
+        if (abs < 0x3c00) {
+            result &= SIGN_MASK;
+            if (abs > 0x3800){
+                result |= 0x3c00;
+            }
+        } else if (abs < 0x6400) {
+            int exp = 25 - (abs >> 10);
+            int mask = (1 << exp) - 1;
+            result += ((1 << (exp - 1)) - (~(abs >> exp) & 1));
+            result &= ~mask;
+        }
+        if (isNaN((short) result)) {
+            // if result is NaN mask with qNaN
+            // (i.e. mask the most significant mantissa bit with 1)
+            // to comply with hardware implementations (ARM64, Intel, etc).
+            result |= NaN;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the smallest half-precision float value toward negative infinity
+     * greater than or equal to the specified half-precision float value.
+     * Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The smallest half-precision float value toward negative infinity
+     *         greater than or equal to the specified half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short ceil(short h) {
+        int bits = h & 0xffff;
+        int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+        int result = bits;
+
+        if (abs < 0x3c00) {
+            result &= SIGN_MASK;
+            result |= 0x3c00 & -(~(bits >> 15) & (abs != 0 ? 1 : 0));
+        } else if (abs < 0x6400) {
+            abs = 25 - (abs >> 10);
+            int mask = (1 << abs) - 1;
+            result += mask & ((bits >> 15) - 1);
+            result &= ~mask;
+        }
+        if (isNaN((short) result)) {
+            // if result is NaN mask with qNaN
+            // (i.e. mask the most significant mantissa bit with 1)
+            // to comply with hardware implementations (ARM64, Intel, etc).
+            result |= NaN;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the largest half-precision float value toward positive infinity
+     * less than or equal to the specified half-precision float value.
+     * Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The largest half-precision float value toward positive infinity
+     *         less than or equal to the specified half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short floor(short h) {
+        int bits = h & 0xffff;
+        int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+        int result = bits;
+
+        if (abs < 0x3c00) {
+            result &= SIGN_MASK;
+            result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0);
+        } else if (abs < 0x6400) {
+            abs = 25 - (abs >> 10);
+            int mask = (1 << abs) - 1;
+            result += mask & -(bits >> 15);
+            result &= ~mask;
+        }
+        if (isNaN((short) result)) {
+            // if result is NaN mask with qNaN
+            // i.e. (Mask the most significant mantissa bit with 1)
+            result |= NaN;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the truncated half-precision float value of the specified
+     * half-precision float value. Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The truncated half-precision float value of the specified
+     *         half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short trunc(short h) {
+        int bits = h & 0xffff;
+        int abs = bits & EXPONENT_SIGNIFICAND_MASK;
+        int result = bits;
+
+        if (abs < 0x3c00) {
+            result &= SIGN_MASK;
+        } else if (abs < 0x6400) {
+            abs = 25 - (abs >> 10);
+            int mask = (1 << abs) - 1;
+            result &= ~mask;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the smaller of two half-precision float values (the value closest
+     * to negative infinity). Special values are handled in the following ways:
+     * <ul>
+     * <li>If either value is NaN, the result is NaN</li>
+     * <li>{@link #NEGATIVE_ZERO} is smaller than {@link #POSITIVE_ZERO}</li>
+     * </ul>
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     * @return The smaller of the two specified half-precision values
+     */
+    @libcore.api.CorePlatformApi
+    public static short min(short x, short y) {
+        if (isNaN(x)) return NaN;
+        if (isNaN(y)) return NaN;
+
+        if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
+            return (x & SIGN_MASK) != 0 ? x : y;
+        }
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+    }
+
+    /**
+     * Returns the larger of two half-precision float values (the value closest
+     * to positive infinity). Special values are handled in the following ways:
+     * <ul>
+     * <li>If either value is NaN, the result is NaN</li>
+     * <li>{@link #POSITIVE_ZERO} is greater than {@link #NEGATIVE_ZERO}</li>
+     * </ul>
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return The larger of the two specified half-precision values
+     */
+    @libcore.api.CorePlatformApi
+    public static short max(short x, short y) {
+        if (isNaN(x)) return NaN;
+        if (isNaN(y)) return NaN;
+
+        if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
+            return (x & SIGN_MASK) != 0 ? y : x;
+        }
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+    }
+
+    /**
+     * Returns true if the first half-precision float value is less (smaller
+     * toward negative infinity) than the second half-precision float value.
+     * If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is less than y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean less(short x, short y) {
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is less (smaller
+     * toward negative infinity) than or equal to the second half-precision
+     * float value. If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is less than or equal to y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean lessEquals(short x, short y) {
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <=
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is greater (larger
+     * toward positive infinity) than the second half-precision float value.
+     * If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is greater than y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean greater(short x, short y) {
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is greater (larger
+     * toward positive infinity) than or equal to the second half-precision float
+     * value. If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is greater than y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean greaterEquals(short x, short y) {
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >=
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the two half-precision float values are equal.
+     * If either of the values is NaN, the result is false. {@link #POSITIVE_ZERO}
+     * and {@link #NEGATIVE_ZERO} are considered equal.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is equal to y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean equals(short x, short y) {
+        if (isNaN(x)) return false;
+        if (isNaN(y)) return false;
+
+        return x == y || ((x | y) & EXPONENT_SIGNIFICAND_MASK) == 0;
+    }
+
+    /**
+     * Returns true if the specified half-precision float value represents
+     * infinity, false otherwise.
+     *
+     * @param h A half-precision float value
+     * @return True if the value is positive infinity or negative infinity,
+     *         false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean isInfinite(short h) {
+        return (h & EXPONENT_SIGNIFICAND_MASK) == POSITIVE_INFINITY;
+    }
+
+    /**
+     * Returns true if the specified half-precision float value represents
+     * a Not-a-Number, false otherwise.
+     *
+     * @param h A half-precision float value
+     * @return True if the value is a NaN, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean isNaN(short h) {
+        return (h & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY;
+    }
+
+    /**
+     * Returns true if the specified half-precision float value is normalized
+     * (does not have a subnormal representation). If the specified value is
+     * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY},
+     * {@link #POSITIVE_ZERO}, {@link #NEGATIVE_ZERO}, NaN or any subnormal
+     * number, this method returns false.
+     *
+     * @param h A half-precision float value
+     * @return True if the value is normalized, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean isNormalized(short h) {
+        return (h & POSITIVE_INFINITY) != 0 && (h & POSITIVE_INFINITY) != POSITIVE_INFINITY;
+    }
+
+    /**
+     * <p>Converts the specified half-precision float value into a
+     * single-precision float value. The following special cases are handled:</p>
+     * <ul>
+     * <li>If the input is {@link #NaN}, the returned value is {@link Float#NaN}</li>
+     * <li>If the input is {@link #POSITIVE_INFINITY} or
+     * {@link #NEGATIVE_INFINITY}, the returned value is respectively
+     * {@link Float#POSITIVE_INFINITY} or {@link Float#NEGATIVE_INFINITY}</li>
+     * <li>If the input is 0 (positive or negative), the returned value is +/-0.0f</li>
+     * <li>Otherwise, the returned value is a normalized single-precision float value</li>
+     * </ul>
+     *
+     * @param h The half-precision float value to convert to single-precision
+     * @return A normalized single-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static float toFloat(short h) {
+        int bits = h & 0xffff;
+        int s = bits & SIGN_MASK;
+        int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK;
+        int m = (bits                        ) & SIGNIFICAND_MASK;
+
+        int outE = 0;
+        int outM = 0;
+
+        if (e == 0) { // Denormal or 0
+            if (m != 0) {
+                // Convert denorm fp16 into normalized fp32
+                float o = Float.intBitsToFloat(FP32_DENORMAL_MAGIC + m);
+                o -= FP32_DENORMAL_FLOAT;
+                return s == 0 ? o : -o;
+            }
+        } else {
+            outM = m << 13;
+            if (e == 0x1f) { // Infinite or NaN
+                outE = 0xff;
+                if (outM != 0) { // SNaNs are quieted
+                    outM |= FP32_QNAN_MASK;
+                }
+            } else {
+                outE = e - EXPONENT_BIAS + FP32_EXPONENT_BIAS;
+            }
+        }
+
+        int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM;
+        return Float.intBitsToFloat(out);
+    }
+
+    /**
+     * <p>Converts the specified single-precision float value into a
+     * half-precision float value. The following special cases are handled:</p>
+     * <ul>
+     * <li>If the input is NaN (see {@link Float#isNaN(float)}), the returned
+     * value is {@link #NaN}</li>
+     * <li>If the input is {@link Float#POSITIVE_INFINITY} or
+     * {@link Float#NEGATIVE_INFINITY}, the returned value is respectively
+     * {@link #POSITIVE_INFINITY} or {@link #NEGATIVE_INFINITY}</li>
+     * <li>If the input is 0 (positive or negative), the returned value is
+     * {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li>
+     * <li>If the input is a less than {@link #MIN_VALUE}, the returned value
+     * is flushed to {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li>
+     * <li>If the input is a less than {@link #MIN_NORMAL}, the returned value
+     * is a denorm half-precision float</li>
+     * <li>Otherwise, the returned value is rounded to the nearest
+     * representable half-precision float value</li>
+     * </ul>
+     *
+     * @param f The single-precision float value to convert to half-precision
+     * @return A half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short toHalf(float f) {
+        int bits = Float.floatToRawIntBits(f);
+        int s = (bits >>> FP32_SIGN_SHIFT    );
+        int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_SHIFTED_EXPONENT_MASK;
+        int m = (bits                        ) & FP32_SIGNIFICAND_MASK;
+
+        int outE = 0;
+        int outM = 0;
+
+        if (e == 0xff) { // Infinite or NaN
+            outE = 0x1f;
+            outM = m != 0 ? 0x200 : 0;
+        } else {
+            e = e - FP32_EXPONENT_BIAS + EXPONENT_BIAS;
+            if (e >= 0x1f) { // Overflow
+                outE = 0x1f;
+            } else if (e <= 0) { // Underflow
+                if (e < -10) {
+                    // The absolute fp32 value is less than MIN_VALUE, flush to +/-0
+                } else {
+                    // The fp32 value is a normalized float less than MIN_NORMAL,
+                    // we convert to a denorm fp16
+                    m = m | 0x800000;
+                    int shift = 14 - e;
+                    outM = m >> shift;
+
+                    int lowm = m & ((1 << shift) - 1);
+                    int hway = 1 << (shift - 1);
+                    // if above halfway or exactly halfway and outM is odd
+                    if (lowm + (outM & 1) > hway){
+                        // Round to nearest even
+                        // Can overflow into exponent bit, which surprisingly is OK.
+                        // This increment relies on the +outM in the return statement below
+                        outM++;
+                    }
+                }
+            } else {
+                outE = e;
+                outM = m >> 13;
+                // if above halfway or exactly halfway and outM is odd
+                if ((m & 0x1fff) + (outM & 0x1) > 0x1000) {
+                    // Round to nearest even
+                    // Can overflow into exponent bit, which surprisingly is OK.
+                    // This increment relies on the +outM in the return statement below
+                    outM++;
+                }
+            }
+        }
+        // The outM is added here as the +1 increments for outM above can
+        // cause an overflow in the exponent bit which is OK.
+        return (short) ((s << SIGN_SHIFT) | (outE << EXPONENT_SHIFT) + outM);
+    }
+
+    /**
+     * <p>Returns a hexadecimal string representation of the specified half-precision
+     * float value. If the value is a NaN, the result is <code>"NaN"</code>,
+     * otherwise the result follows this format:</p>
+     * <ul>
+     * <li>If the sign is positive, no sign character appears in the result</li>
+     * <li>If the sign is negative, the first character is <code>'-'</code></li>
+     * <li>If the value is inifinity, the string is <code>"Infinity"</code></li>
+     * <li>If the value is 0, the string is <code>"0x0.0p0"</code></li>
+     * <li>If the value has a normalized representation, the exponent and
+     * significand are represented in the string in two fields. The significand
+     * starts with <code>"0x1."</code> followed by its lowercase hexadecimal
+     * representation. Trailing zeroes are removed unless all digits are 0, then
+     * a single zero is used. The significand representation is followed by the
+     * exponent, represented by <code>"p"</code>, itself followed by a decimal
+     * string of the unbiased exponent</li>
+     * <li>If the value has a subnormal representation, the significand starts
+     * with <code>"0x0."</code> followed by its lowercase hexadecimal
+     * representation. Trailing zeroes are removed unless all digits are 0, then
+     * a single zero is used. The significand representation is followed by the
+     * exponent, represented by <code>"p-14"</code></li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return A hexadecimal string representation of the specified value
+     */
+    @libcore.api.CorePlatformApi
+    public static String toHexString(short h) {
+        StringBuilder o = new StringBuilder();
+
+        int bits = h & 0xffff;
+        int s = (bits >>> SIGN_SHIFT    );
+        int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK;
+        int m = (bits                   ) & SIGNIFICAND_MASK;
+
+        if (e == 0x1f) { // Infinite or NaN
+            if (m == 0) {
+                if (s != 0) o.append('-');
+                o.append("Infinity");
+            } else {
+                o.append("NaN");
+            }
+        } else {
+            if (s == 1) o.append('-');
+            if (e == 0) {
+                if (m == 0) {
+                    o.append("0x0.0p0");
+                } else {
+                    o.append("0x0.");
+                    String significand = Integer.toHexString(m);
+                    o.append(significand.replaceFirst("0{2,}$", ""));
+                    o.append("p-14");
+                }
+            } else {
+                o.append("0x1.");
+                String significand = Integer.toHexString(m);
+                o.append(significand.replaceFirst("0{2,}$", ""));
+                o.append('p');
+                o.append(Integer.toString(e - EXPONENT_BIAS));
+            }
+        }
+
+        return o.toString();
+    }
+}
diff --git a/luni/src/main/java/libcore/util/HexEncoding.java b/luni/src/main/java/libcore/util/HexEncoding.java
index eceec6b..6d00074 100644
--- a/luni/src/main/java/libcore/util/HexEncoding.java
+++ b/luni/src/main/java/libcore/util/HexEncoding.java
@@ -23,17 +23,43 @@
 @libcore.api.CorePlatformApi
 public class HexEncoding {
 
+    private static final char[] LOWER_CASE_DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+    };
+
+    private static final char[] UPPER_CASE_DIGITS = {
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+    };
+
     /** Hidden constructor to prevent instantiation. */
     private HexEncoding() {}
 
-    private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
+    /**
+     * Encodes the provided byte as a two-digit hexadecimal String value.
+     */
+    @libcore.api.CorePlatformApi
+    public static String encodeToString(byte b, boolean upperCase) {
+        char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;
+        char[] buf = new char[2]; // We always want two digits.
+        buf[0] = digits[(b >> 4) & 0xf];
+        buf[1] = digits[b & 0xf];
+        return new String(buf, 0, 2);
+    }
 
     /**
      * Encodes the provided data as a sequence of hexadecimal characters.
      */
     @libcore.api.CorePlatformApi
     public static char[] encode(byte[] data) {
-        return encode(data, 0, data.length);
+        return encode(data, 0, data.length, true /* upperCase */);
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    @libcore.api.CorePlatformApi
+    public static char[] encode(byte[] data, boolean upperCase) {
+        return encode(data, 0, data.length, upperCase);
     }
 
     /**
@@ -41,12 +67,20 @@
      */
     @libcore.api.CorePlatformApi
     public static char[] encode(byte[] data, int offset, int len) {
+        return encode(data, offset, len, true /* upperCase */);
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    private static char[] encode(byte[] data, int offset, int len, boolean upperCase) {
+        char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;
         char[] result = new char[len * 2];
         for (int i = 0; i < len; i++) {
             byte b = data[offset + i];
             int resultIndex = 2 * i;
-            result[resultIndex] = (HEX_DIGITS[(b >>> 4) & 0x0f]);
-            result[resultIndex + 1] = (HEX_DIGITS[b & 0x0f]);
+            result[resultIndex] = (digits[(b >> 4) & 0x0f]);
+            result[resultIndex + 1] = (digits[b & 0x0f]);
         }
 
         return result;
@@ -57,7 +91,15 @@
      */
     @libcore.api.CorePlatformApi
     public static String encodeToString(byte[] data) {
-        return new String(encode(data));
+        return encodeToString(data, true /* upperCase */);
+    }
+
+    /**
+     * Encodes the provided data as a sequence of hexadecimal characters.
+     */
+    @libcore.api.CorePlatformApi
+    public static String encodeToString(byte[] data, boolean upperCase) {
+        return new String(encode(data, upperCase));
     }
 
     /**
@@ -78,7 +120,9 @@
      *
      * Throws an {@code IllegalArgumentException} if the input is malformed.
      */
-    public static byte[] decode(String encoded, boolean allowSingleChar) throws IllegalArgumentException {
+    @libcore.api.CorePlatformApi
+    public static byte[] decode(String encoded, boolean allowSingleChar)
+            throws IllegalArgumentException {
         return decode(encoded.toCharArray(), allowSingleChar);
     }
 
@@ -101,25 +145,28 @@
      * Throws an {@code IllegalArgumentException} if the input is malformed.
      */
     @libcore.api.CorePlatformApi
-    public static byte[] decode(char[] encoded, boolean allowSingleChar) throws IllegalArgumentException {
-        int resultLengthBytes = (encoded.length + 1) / 2;
+    public static byte[] decode(char[] encoded, boolean allowSingleChar)
+            throws IllegalArgumentException {
+        int encodedLength = encoded.length;
+        int resultLengthBytes = (encodedLength + 1) / 2;
         byte[] result = new byte[resultLengthBytes];
 
         int resultOffset = 0;
         int i = 0;
         if (allowSingleChar) {
-            if ((encoded.length % 2) != 0) {
-                // Odd number of digits -- the first digit is the lower 4 bits of the first result byte.
+            if ((encodedLength % 2) != 0) {
+                // Odd number of digits -- the first digit is the lower 4 bits of the first result
+                // byte.
                 result[resultOffset++] = (byte) toDigit(encoded, i);
                 i++;
             }
         } else {
-            if ((encoded.length % 2) != 0) {
-                throw new IllegalArgumentException("Invalid input length: " + encoded.length);
+            if ((encodedLength % 2) != 0) {
+                throw new IllegalArgumentException("Invalid input length: " + encodedLength);
             }
         }
 
-        for (int len = encoded.length; i < len; i += 2) {
+        for (; i < encodedLength; i += 2) {
             result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1));
         }
 
@@ -139,7 +186,6 @@
             return 10 + (pseudoCodePoint - 'A');
         }
 
-        throw new IllegalArgumentException("Illegal char: " + str[offset] +
-                " at offset " + offset);
+        throw new IllegalArgumentException("Illegal char: " + str[offset] + " at offset " + offset);
     }
 }
diff --git a/luni/src/main/java/libcore/util/NativeAllocationRegistry.java b/luni/src/main/java/libcore/util/NativeAllocationRegistry.java
index 5dc1e98..e114ebe 100644
--- a/luni/src/main/java/libcore/util/NativeAllocationRegistry.java
+++ b/luni/src/main/java/libcore/util/NativeAllocationRegistry.java
@@ -41,6 +41,7 @@
  * @hide
  */
 @libcore.api.CorePlatformApi
+@libcore.api.IntraCoreApi
 public class NativeAllocationRegistry {
 
     private final ClassLoader classLoader;
@@ -118,6 +119,7 @@
      *                     kind of native allocation
      */
     @libcore.api.CorePlatformApi
+    @libcore.api.IntraCoreApi
     public static NativeAllocationRegistry createMalloced(
             ClassLoader classLoader, long freeFunction) {
         return new NativeAllocationRegistry(classLoader, freeFunction, 0, true);
@@ -227,6 +229,7 @@
      *                           thrown.
      */
     @libcore.api.CorePlatformApi
+    @libcore.api.IntraCoreApi
     public Runnable registerNativeAllocation(Object referent, long nativePtr) {
         if (referent == null) {
             throw new IllegalArgumentException("referent is null");
diff --git a/luni/src/main/java/libcore/util/NonNull.java b/luni/src/main/java/libcore/util/NonNull.java
index 900e581..db3cd8e 100644
--- a/luni/src/main/java/libcore/util/NonNull.java
+++ b/luni/src/main/java/libcore/util/NonNull.java
@@ -15,6 +15,9 @@
  */
 package libcore.util;
 
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.ElementType.TYPE_USE;
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -30,7 +33,7 @@
  */
 @Documented
 @Retention(SOURCE)
-@Target({TYPE_USE})
+@Target({FIELD, METHOD, PARAMETER, TYPE_USE})
 @libcore.api.IntraCoreApi
 public @interface NonNull {
    /**
diff --git a/luni/src/main/java/libcore/util/Nullable.java b/luni/src/main/java/libcore/util/Nullable.java
index c8cbe38..3371978 100644
--- a/luni/src/main/java/libcore/util/Nullable.java
+++ b/luni/src/main/java/libcore/util/Nullable.java
@@ -15,6 +15,9 @@
  */
 package libcore.util;
 
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.ElementType.TYPE_USE;
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -30,7 +33,7 @@
  */
 @Documented
 @Retention(SOURCE)
-@Target({TYPE_USE})
+@Target({FIELD, METHOD, PARAMETER, TYPE_USE})
 @libcore.api.IntraCoreApi
 public @interface Nullable {
    /**
diff --git a/luni/src/main/java/libcore/util/TEST_MAPPING b/luni/src/main/java/libcore/util/TEST_MAPPING
new file mode 100644
index 0000000..670cd00
--- /dev/null
+++ b/luni/src/main/java/libcore/util/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.libcore.util"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/libcore/util/ZoneInfo.java b/luni/src/main/java/libcore/util/ZoneInfo.java
index abd98b1..85bf1bc 100644
--- a/luni/src/main/java/libcore/util/ZoneInfo.java
+++ b/luni/src/main/java/libcore/util/ZoneInfo.java
@@ -22,7 +22,8 @@
  */
 package libcore.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.util.Arrays;
@@ -31,7 +32,7 @@
 import java.util.GregorianCalendar;
 import java.util.TimeZone;
 import libcore.io.BufferIterator;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
 
 /**
  * Our concrete TimeZone implementation, backed by zoneinfo data.
@@ -42,26 +43,15 @@
  * {@code man 8 zic}) and an index by long name, e.g. Europe/London.
  *
  * <p>The compacted form is created by {@code external/icu/tools/ZoneCompactor.java} and is used
- * by both this and Bionic. {@link ZoneInfoDB} is responsible for mapping the binary file, and
+ * by both this and Bionic. {@link ZoneInfoDb} is responsible for mapping the binary file, and
  * reading the index and creating a {@link BufferIterator} that provides access to an entry for a
  * specific file. This class is responsible for reading the data from that {@link BufferIterator}
  * and storing it a representation to support the {@link TimeZone} and {@link GregorianCalendar}
  * implementations. See {@link ZoneInfo#readTimeZone(String, BufferIterator, long)}.
  *
- * <p>The main difference between {@code tzfile} and the compacted form is that the
- * {@code struct ttinfo} only uses a single byte for {@code tt_isdst} and {@code tt_abbrind}.
- *
  * <p>This class does not use all the information from the {@code tzfile}; it uses:
  * {@code tzh_timecnt} and the associated transition times and type information. For each type
- * (described by {@code struct ttinfo}) it uses {@code tt_gmtoff} and {@code tt_isdst}. Note, that
- * the definition of {@code struct ttinfo} uses {@code long}, and {@code int} but they do not have
- * the same meaning as Java. The prose following the definition makes it clear that the {@code long}
- * is 4 bytes and the {@code int} fields are 1 byte.
- *
- * <p>As the data uses 32 bits to store the time in seconds the time range is limited to roughly
- * 69 years either side of the epoch (1st Jan 1970 00:00:00) that means that it cannot handle any
- * dates before 1900 and after 2038. There is an extended version of the table that uses 64 bits
- * to store the data but that information is not used by this.
+ * (described by {@code struct ttinfo}) it uses {@code tt_gmtoff} and {@code tt_isdst}.
  *
  * <p>This class should be in libcore.timezone but this class is Serializable so cannot
  * be moved there without breaking apps that have (for some reason) serialized TimeZone objects.
@@ -197,6 +187,19 @@
 
     public static ZoneInfo readTimeZone(String id, BufferIterator it, long currentTimeMillis)
             throws IOException {
+
+        // Skip over the superseded 32-bit header and data.
+        skipOver32BitData(id, it);
+
+        // Read the v2+ 64-bit header and data.
+        return read64BitData(id, it, currentTimeMillis);
+    }
+
+    /**
+     * Skip over the 32-bit data with some minimal validation to make sure sure we reading a valid
+     * and supported file.
+     */
+    private static void skipOver32BitData(String id, BufferIterator it) throws IOException {
         // Variable names beginning tzh_ correspond to those in "tzfile.h".
 
         // Check tzh_magic.
@@ -205,24 +208,82 @@
             throw new IOException("Timezone id=" + id + " has an invalid header=" + tzh_magic);
         }
 
-        // Skip the uninteresting part of the header.
-        it.skip(28);
+        byte tzh_version = it.readByte();
+        checkTzifVersionAcceptable(id, tzh_version);
+
+        // Skip the unused bytes.
+        it.skip(15);
+
+        // Read the header values necessary to read through all the 32-bit data.
+        int tzh_ttisgmtcnt = it.readInt();
+        int tzh_ttisstdcnt = it.readInt();
+        int tzh_leapcnt = it.readInt();
+        int tzh_timecnt = it.readInt();
+        int tzh_typecnt = it.readInt();
+        int tzh_charcnt = it.readInt();
+
+        // Skip transitions data, 4 bytes for each 32-bit time + 1 byte for isDst.
+        final int transitionInfoSize = 4 + 1;
+        it.skip(tzh_timecnt * transitionInfoSize);
+
+        // Skip ttinfos.
+        // struct ttinfo {
+        //     int32_t       tt_gmtoff;
+        //     unsigned char tt_isdst;
+        //     unsigned char tt_abbrind;
+        // };
+        final int ttinfoSize = 4 + 1 + 1;
+        it.skip(tzh_typecnt * ttinfoSize);
+
+        // Skip tzh_charcnt time zone abbreviations.
+        it.skip(tzh_charcnt);
+
+        // Skip tzh_leapcnt repetitions of a 32-bit time + a 32-bit correction.
+        int leapInfoSize = 4 + 4;
+        it.skip(tzh_leapcnt * leapInfoSize);
+
+        // Skip ttisstds and ttisgmts information. These can be ignored for our usecases as per
+        // https://mm.icann.org/pipermail/tz/2006-February/013359.html
+        it.skip(tzh_ttisstdcnt + tzh_ttisgmtcnt);
+    }
+
+    /**
+     * Read the 64-bit header and data for {@code id} from the current position of {@code it} and
+     * return a ZoneInfo.
+     */
+    private static ZoneInfo read64BitData(String id, BufferIterator it, long currentTimeMillis)
+            throws IOException {
+        // Variable names beginning tzh_ correspond to those in "tzfile.h".
+
+        // Check tzh_magic.
+        int tzh_magic = it.readInt();
+        if (tzh_magic != 0x545a6966) { // "TZif"
+            throw new IOException("Timezone id=" + id + " has an invalid header=" + tzh_magic);
+        }
+
+        byte tzh_version = it.readByte();
+        checkTzifVersionAcceptable(id, tzh_version);
+
+        // Skip the uninteresting parts of the header.
+        it.skip(27);
 
         // Read the sizes of the arrays we're about to read.
         int tzh_timecnt = it.readInt();
+
         // Arbitrary ceiling to prevent allocating memory for corrupt data.
-        // 2 per year with 2^32 seconds would give ~272 transitions.
         final int MAX_TRANSITIONS = 2000;
         if (tzh_timecnt < 0 || tzh_timecnt > MAX_TRANSITIONS) {
             throw new IOException(
-                    "Timezone id=" + id + " has an invalid number of transitions=" + tzh_timecnt);
+                    "Timezone id=" + id + " has an invalid number of transitions="
+                            + tzh_timecnt);
         }
 
         int tzh_typecnt = it.readInt();
         final int MAX_TYPES = 256;
         if (tzh_typecnt < 1) {
             throw new IOException("ZoneInfo requires at least one type "
-                    + "to be provided for each timezone but could not find one for '" + id + "'");
+                    + "to be provided for each timezone but could not find one for '" + id
+                    + "'");
         } else if (tzh_typecnt > MAX_TYPES) {
             throw new IOException(
                     "Timezone with id " + id + " has too many types=" + tzh_typecnt);
@@ -230,18 +291,9 @@
 
         it.skip(4); // Skip tzh_charcnt.
 
-        // Transitions are signed 32 bit integers, but we store them as signed 64 bit
-        // integers since it's easier to compare them against 64 bit inputs (see getOffset
-        // and isDaylightTime) with much less risk of an overflow in our calculations.
-        //
-        // The alternative of checking the input against the first and last transition in
-        // the array is far more awkward and error prone.
-        int[] transitions32 = new int[tzh_timecnt];
-        it.readIntArray(transitions32, 0, transitions32.length);
-
         long[] transitions64 = new long[tzh_timecnt];
+        it.readLongArray(transitions64, 0, transitions64.length);
         for (int i = 0; i < tzh_timecnt; ++i) {
-            transitions64[i] = transitions32[i];
             if (i > 0 && transitions64[i] <= transitions64[i - 1]) {
                 throw new IOException(
                         id + " transition at " + i + " is not sorted correctly, is "
@@ -249,13 +301,14 @@
             }
         }
 
-        byte[] type = new byte[tzh_timecnt];
-        it.readByteArray(type, 0, type.length);
-        for (int i = 0; i < type.length; i++) {
-            int typeIndex = type[i] & 0xff;
+        byte[] types = new byte[tzh_timecnt];
+        it.readByteArray(types, 0, types.length);
+        for (int i = 0; i < types.length; i++) {
+            int typeIndex = types[i] & 0xff;
             if (typeIndex >= tzh_typecnt) {
                 throw new IOException(
-                        id + " type at " + i + " is not < " + tzh_typecnt + ", is " + typeIndex);
+                        id + " type at " + i + " is not < " + tzh_typecnt + ", is "
+                                + typeIndex);
             }
         }
 
@@ -277,8 +330,19 @@
             // for any locale. (The RI doesn't do any better than us here either.)
             it.skip(1);
         }
+        return new ZoneInfo(id, transitions64, types, gmtOffsets, isDsts, currentTimeMillis);
+    }
 
-        return new ZoneInfo(id, transitions64, type, gmtOffsets, isDsts, currentTimeMillis);
+    private static void checkTzifVersionAcceptable(String id, byte tzh_version) throws IOException {
+        char tzh_version_char = (char) tzh_version;
+        // Version >= 2 is required because the 64-bit time section is required. v3 is the latest
+        // version known at the time of writing and is identical to v2 in the parts used by this
+        // class.
+        if (tzh_version_char != '2' && tzh_version_char != '3') {
+            throw new IOException(
+                    "Timezone id=" + id + " has an invalid format version=\'" + tzh_version_char
+                            + "\' (" + tzh_version + ")");
+        }
     }
 
     private ZoneInfo(String name, long[] transitions, byte[] types, int[] gmtOffsets, byte[] isDsts,
diff --git a/luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java b/luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java
index 3368f92..22ee4a2 100644
--- a/luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java
+++ b/luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java
@@ -16,9 +16,10 @@
 
 package org.apache.harmony.xml;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import org.xml.sax.Attributes;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 /**
  * Wraps native attribute array.
  */
diff --git a/luni/src/main/java/org/apache/harmony/xml/ExpatParser.java b/luni/src/main/java/org/apache/harmony/xml/ExpatParser.java
index 71c94f9..8872e1d 100644
--- a/luni/src/main/java/org/apache/harmony/xml/ExpatParser.java
+++ b/luni/src/main/java/org/apache/harmony/xml/ExpatParser.java
@@ -16,15 +16,6 @@
 
 package org.apache.harmony.xml;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.annotation.optimization.ReachabilitySensitive;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLConnection;
-import libcore.io.IoUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.DTDHandler;
@@ -35,6 +26,18 @@
 import org.xml.sax.SAXParseException;
 import org.xml.sax.ext.LexicalHandler;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import libcore.io.IoUtils;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+
 /**
  * Adapts SAX API to the Expat native XML parser. Not intended for reuse
  * across documents.
diff --git a/luni/src/main/java/org/apache/harmony/xml/ExpatReader.java b/luni/src/main/java/org/apache/harmony/xml/ExpatReader.java
index 510a889..a69f364 100644
--- a/luni/src/main/java/org/apache/harmony/xml/ExpatReader.java
+++ b/luni/src/main/java/org/apache/harmony/xml/ExpatReader.java
@@ -16,11 +16,6 @@
 
 package org.apache.harmony.xml;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import libcore.io.IoUtils;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.DTDHandler;
 import org.xml.sax.EntityResolver;
@@ -32,6 +27,13 @@
 import org.xml.sax.XMLReader;
 import org.xml.sax.ext.LexicalHandler;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import libcore.io.IoUtils;
+
 /**
  * SAX wrapper around Expat. Interns strings. Does not support validation.
  * Does not support {@link DTDHandler}.
diff --git a/luni/src/main/java/org/apache/harmony/xml/TEST_MAPPING b/luni/src/main/java/org/apache/harmony/xml/TEST_MAPPING
new file mode 100644
index 0000000..d8c9759
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xml/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.xml"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
index a0da24d..b522265 100644
--- a/luni/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
@@ -16,10 +16,6 @@
 
 package org.apache.harmony.xml.dom;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
 import org.w3c.dom.Attr;
 import org.w3c.dom.DOMException;
 import org.w3c.dom.Element;
@@ -28,6 +24,12 @@
 import org.w3c.dom.NodeList;
 import org.w3c.dom.TypeInfo;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
 /**
  * Provides a straightforward implementation of the corresponding W3C DOM
  * interface. The class is used internally only, thus only notable members that
diff --git a/luni/src/main/java/org/w3c/dom/TEST_MAPPING b/luni/src/main/java/org/w3c/dom/TEST_MAPPING
new file mode 100644
index 0000000..00e68f7
--- /dev/null
+++ b/luni/src/main/java/org/w3c/dom/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.xml"
+        },
+        {
+          "include-filter": "tests.org.w3c.dom"
+        },
+        {
+          "include-filter": "org.w3c.domts"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java b/luni/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java
index 554807c..9f22f2b 100644
--- a/luni/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java
+++ b/luni/src/main/java/org/w3c/dom/ls/LSSerializerFilter.java
@@ -12,9 +12,10 @@
 
 package org.w3c.dom.ls;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import org.w3c.dom.traversal.NodeFilter;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 /**
  *  <code>LSSerializerFilter</code>s provide applications the ability to
  * examine nodes as they are being serialized and decide what nodes should
diff --git a/luni/src/main/java/org/w3c/dom/traversal/NodeFilter.java b/luni/src/main/java/org/w3c/dom/traversal/NodeFilter.java
index 24f7599..8263d5b 100644
--- a/luni/src/main/java/org/w3c/dom/traversal/NodeFilter.java
+++ b/luni/src/main/java/org/w3c/dom/traversal/NodeFilter.java
@@ -12,9 +12,10 @@
 
 package org.w3c.dom.traversal;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import org.w3c.dom.Node;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 /**
  * Filters are objects that know how to "filter out" nodes. If a
  * <code>NodeIterator</code> or <code>TreeWalker</code> is given a
diff --git a/luni/src/main/java/org/w3c/dom/traversal/NodeIterator.java b/luni/src/main/java/org/w3c/dom/traversal/NodeIterator.java
index 686beb7..3d1f3af 100644
--- a/luni/src/main/java/org/w3c/dom/traversal/NodeIterator.java
+++ b/luni/src/main/java/org/w3c/dom/traversal/NodeIterator.java
@@ -12,10 +12,11 @@
 
 package org.w3c.dom.traversal;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import org.w3c.dom.DOMException;
 import org.w3c.dom.Node;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 /**
  * <code>NodeIterators</code> are used to step through a set of nodes, e.g.
  * the set of nodes in a <code>NodeList</code>, the document subtree
diff --git a/luni/src/main/java/org/xml/sax/InputSource.java b/luni/src/main/java/org/xml/sax/InputSource.java
index 3750cfe..26e027b 100644
--- a/luni/src/main/java/org/xml/sax/InputSource.java
+++ b/luni/src/main/java/org/xml/sax/InputSource.java
@@ -5,7 +5,7 @@
 
 package org.xml.sax;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.io.InputStream;
 import java.io.Reader;
 
diff --git a/luni/src/main/java/org/xml/sax/SAXException.java b/luni/src/main/java/org/xml/sax/SAXException.java
index ea69d3f..383b4a0 100644
--- a/luni/src/main/java/org/xml/sax/SAXException.java
+++ b/luni/src/main/java/org/xml/sax/SAXException.java
@@ -5,7 +5,7 @@
 
 package org.xml.sax;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Encapsulate a general SAX error or warning.
diff --git a/luni/src/main/java/org/xml/sax/SAXParseException.java b/luni/src/main/java/org/xml/sax/SAXParseException.java
index 72b16cf..67cb78a 100644
--- a/luni/src/main/java/org/xml/sax/SAXParseException.java
+++ b/luni/src/main/java/org/xml/sax/SAXParseException.java
@@ -5,7 +5,7 @@
 
 package org.xml.sax;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Encapsulate an XML parse error or warning.
diff --git a/luni/src/main/java/org/xml/sax/TEST_MAPPING b/luni/src/main/java/org/xml/sax/TEST_MAPPING
new file mode 100644
index 0000000..afedf2c
--- /dev/null
+++ b/luni/src/main/java/org/xml/sax/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.xml"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.org.xml.sax"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/org/xml/sax/ext/Attributes2Impl.java b/luni/src/main/java/org/xml/sax/ext/Attributes2Impl.java
index b3702a4..6b4ea18 100644
--- a/luni/src/main/java/org/xml/sax/ext/Attributes2Impl.java
+++ b/luni/src/main/java/org/xml/sax/ext/Attributes2Impl.java
@@ -5,11 +5,13 @@
 
 package org.xml.sax.ext;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import libcore.util.EmptyArray;
 import org.xml.sax.Attributes;
 import org.xml.sax.helpers.AttributesImpl;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
+import libcore.util.EmptyArray;
+
 /**
  * SAX2 extension helper for additional Attributes information,
  * implementing the {@link Attributes2} interface.
diff --git a/luni/src/main/java/org/xml/sax/ext/Locator2Impl.java b/luni/src/main/java/org/xml/sax/ext/Locator2Impl.java
index bb9582f..711639b 100644
--- a/luni/src/main/java/org/xml/sax/ext/Locator2Impl.java
+++ b/luni/src/main/java/org/xml/sax/ext/Locator2Impl.java
@@ -5,10 +5,11 @@
 
 package org.xml.sax.ext;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import org.xml.sax.Locator;
 import org.xml.sax.helpers.LocatorImpl;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 
 /**
  * SAX2 extension helper for holding additional Entity information,
diff --git a/luni/src/main/java/org/xml/sax/ext/TEST_MAPPING b/luni/src/main/java/org/xml/sax/ext/TEST_MAPPING
new file mode 100644
index 0000000..50687ab
--- /dev/null
+++ b/luni/src/main/java/org/xml/sax/ext/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.org.xml.sax.ext"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/org/xml/sax/helpers/AttributesImpl.java b/luni/src/main/java/org/xml/sax/helpers/AttributesImpl.java
index 9193075..dcc6ff0 100644
--- a/luni/src/main/java/org/xml/sax/helpers/AttributesImpl.java
+++ b/luni/src/main/java/org/xml/sax/helpers/AttributesImpl.java
@@ -6,9 +6,10 @@
 
 package org.xml.sax.helpers;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import org.xml.sax.Attributes;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 
 /**
  * Default implementation of the Attributes interface.
diff --git a/luni/src/main/java/org/xml/sax/helpers/LocatorImpl.java b/luni/src/main/java/org/xml/sax/helpers/LocatorImpl.java
index 944c41a..9997375 100644
--- a/luni/src/main/java/org/xml/sax/helpers/LocatorImpl.java
+++ b/luni/src/main/java/org/xml/sax/helpers/LocatorImpl.java
@@ -5,9 +5,10 @@
 
 package org.xml.sax.helpers;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
 import org.xml.sax.Locator;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 
 /**
  * Provide an optional convenience implementation of Locator.
diff --git a/luni/src/main/java/org/xml/sax/helpers/NamespaceSupport.java b/luni/src/main/java/org/xml/sax/helpers/NamespaceSupport.java
index 820f8d2..5322467 100644
--- a/luni/src/main/java/org/xml/sax/helpers/NamespaceSupport.java
+++ b/luni/src/main/java/org/xml/sax/helpers/NamespaceSupport.java
@@ -6,7 +6,7 @@
 
 package org.xml.sax.helpers;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EmptyStackException;
diff --git a/luni/src/main/java/org/xml/sax/helpers/ParserAdapter.java b/luni/src/main/java/org/xml/sax/helpers/ParserAdapter.java
index 5acc659..f6a7a51 100644
--- a/luni/src/main/java/org/xml/sax/helpers/ParserAdapter.java
+++ b/luni/src/main/java/org/xml/sax/helpers/ParserAdapter.java
@@ -6,10 +6,6 @@
 
 package org.xml.sax.helpers;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Enumeration;
 import org.xml.sax.AttributeList;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
@@ -26,6 +22,12 @@
 import org.xml.sax.SAXParseException;
 import org.xml.sax.XMLReader;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
 
 /**
  * Adapt a SAX1 Parser as a SAX2 XMLReader.
diff --git a/luni/src/main/java/org/xml/sax/helpers/TEST_MAPPING b/luni/src/main/java/org/xml/sax/helpers/TEST_MAPPING
new file mode 100644
index 0000000..f13e3f9
--- /dev/null
+++ b/luni/src/main/java/org/xml/sax/helpers/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.org.xml.sax.helpers"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/luni/src/main/java/org/xml/sax/helpers/XMLFilterImpl.java b/luni/src/main/java/org/xml/sax/helpers/XMLFilterImpl.java
index 95ae356..9ad32af 100644
--- a/luni/src/main/java/org/xml/sax/helpers/XMLFilterImpl.java
+++ b/luni/src/main/java/org/xml/sax/helpers/XMLFilterImpl.java
@@ -6,8 +6,6 @@
 
 package org.xml.sax.helpers;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import java.io.IOException;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.DTDHandler;
@@ -22,6 +20,10 @@
 import org.xml.sax.XMLFilter;
 import org.xml.sax.XMLReader;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
+import java.io.IOException;
+
 
 /**
  * Base class for deriving an XML filter.
diff --git a/luni/src/main/java/org/xml/sax/helpers/XMLReaderAdapter.java b/luni/src/main/java/org/xml/sax/helpers/XMLReaderAdapter.java
index 0ef4d6f..5f0789f 100644
--- a/luni/src/main/java/org/xml/sax/helpers/XMLReaderAdapter.java
+++ b/luni/src/main/java/org/xml/sax/helpers/XMLReaderAdapter.java
@@ -6,9 +6,6 @@
 
 package org.xml.sax.helpers;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import java.io.IOException;
-import java.util.Locale;
 import org.xml.sax.AttributeList;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
@@ -23,6 +20,11 @@
 import org.xml.sax.SAXNotSupportedException;
 import org.xml.sax.XMLReader;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
+import java.io.IOException;
+import java.util.Locale;
+
 
 /**
  * Adapt a SAX2 XMLReader as a SAX1 Parser.
diff --git a/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java b/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
index b95728f..08d1664 100644
--- a/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
+++ b/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
@@ -7,13 +7,15 @@
 
 package org.xml.sax.helpers;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+import android.compat.annotation.UnsupportedAppUsage;
+
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
 
 
 /**
diff --git a/luni/src/main/native/Android.bp b/luni/src/main/native/Android.bp
index 8621752..423cdd1 100644
--- a/luni/src/main/native/Android.bp
+++ b/luni/src/main/native/Android.bp
@@ -1,5 +1,22 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 filegroup {
     name: "luni_native_srcs",
+    visibility: [
+        "//libcore",
+    ],
     srcs: [
         "ExecStrings.cpp",
         "IcuUtilities.cpp",
@@ -14,10 +31,7 @@
         "java_lang_invoke_MethodHandle.cpp",
         "java_lang_invoke_VarHandle.cpp",
         "java_math_NativeBN.cpp",
-        "java_util_regex_Matcher.cpp",
-        "java_util_regex_Pattern.cpp",
         "libcore_icu_ICU.cpp",
-        "libcore_icu_NativeConverter.cpp",
         "libcore_icu_TimeZoneNames.cpp",
         "libcore_io_AsynchronousCloseMonitor.cpp",
         "libcore_io_Linux.cpp",
@@ -31,6 +45,9 @@
 
 filegroup {
     name: "libandroidio_srcs",
+    visibility: [
+        "//libcore",
+    ],
     srcs: [
         "AsynchronousCloseMonitor.cpp",
     ],
diff --git a/luni/src/main/native/IcuUtilities.cpp b/luni/src/main/native/IcuUtilities.cpp
index ed10d04..0db59f9 100644
--- a/luni/src/main/native/IcuUtilities.cpp
+++ b/luni/src/main/native/IcuUtilities.cpp
@@ -29,28 +29,6 @@
 #include "unicode/ustring.h"
 #include "unicode/uloc.h"
 
-jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, icu::StringEnumeration* se) {
-  if (maybeThrowIcuException(env, provider, status)) {
-    return NULL;
-  }
-
-  int32_t count = se->count(status);
-  if (maybeThrowIcuException(env, "StringEnumeration::count", status)) {
-    return NULL;
-  }
-
-  jobjectArray result = env->NewObjectArray(count, JniConstants::GetStringClass(env), NULL);
-  for (int32_t i = 0; i < count; ++i) {
-    const icu::UnicodeString* string = se->snext(status);
-    if (maybeThrowIcuException(env, "StringEnumeration::snext", status)) {
-      return NULL;
-    }
-    ScopedLocalRef<jstring> javaString(env, jniCreateString(env, string->getBuffer(), string->length()));
-    env->SetObjectArrayElement(result, i, javaString.get());
-  }
-  return result;
-}
-
 bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error) {
   if (U_SUCCESS(error)) {
     return false;
diff --git a/luni/src/main/native/IcuUtilities.h b/luni/src/main/native/IcuUtilities.h
index c64de30..451dc32 100644
--- a/luni/src/main/native/IcuUtilities.h
+++ b/luni/src/main/native/IcuUtilities.h
@@ -18,10 +18,8 @@
 #define ICU_UTILITIES_H_included
 
 #include "jni.h"
-#include "ustrenum.h" // For UStringEnumeration.
 #include "unicode/utypes.h" // For UErrorCode.
 
-extern jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, icu::StringEnumeration*);
 bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error);
 
 #endif  // ICU_UTILITIES_H_included
diff --git a/luni/src/main/native/JniConstants.cpp b/luni/src/main/native/JniConstants.cpp
index 8427353..478d015 100644
--- a/luni/src/main/native/JniConstants.cpp
+++ b/luni/src/main/native/JniConstants.cpp
@@ -45,7 +45,6 @@
 
 // Constants
 jclass booleanClass;
-jclass charsetICUClass;
 jclass doubleClass;
 jclass errnoExceptionClass;
 jclass fileDescriptorClass;
@@ -61,10 +60,8 @@
 jclass longClass;
 jclass netlinkSocketAddressClass;
 jclass packetSocketAddressClass;
-jclass patternSyntaxExceptionClass;
 jclass stringClass;
 jclass structAddrinfoClass;
-jclass structFlockClass;
 jclass structGroupReqClass;
 jclass structIfaddrsClass;
 jclass structLingerClass;
@@ -93,7 +90,6 @@
     }
 
     booleanClass = findClass(env, "java/lang/Boolean");
-    charsetICUClass = findClass(env, "java/nio/charset/CharsetICU");
     doubleClass = findClass(env, "java/lang/Double");
     errnoExceptionClass = findClass(env, "android/system/ErrnoException");
     fileDescriptorClass = findClass(env, "java/io/FileDescriptor");
@@ -109,10 +105,8 @@
     longClass = findClass(env, "java/lang/Long");
     netlinkSocketAddressClass = findClass(env, "android/system/NetlinkSocketAddress");
     packetSocketAddressClass = findClass(env, "android/system/PacketSocketAddress");
-    patternSyntaxExceptionClass = findClass(env, "java/util/regex/PatternSyntaxException");
     stringClass = findClass(env, "java/lang/String");
     structAddrinfoClass = findClass(env, "android/system/StructAddrinfo");
-    structFlockClass = findClass(env, "android/system/StructFlock");
     structGroupReqClass = findClass(env, "android/system/StructGroupReq");
     structIfaddrsClass = findClass(env, "android/system/StructIfaddrs");
     structLingerClass = findClass(env, "android/system/StructLinger");
@@ -136,6 +130,15 @@
 }
 
 void JniConstants::Invalidate() {
+    // This method is called when a new runtime instance is created. There is no
+    // notification of a runtime instance being destroyed in the JNI interface
+    // so we piggyback on creation. Since only one runtime is supported at a
+    // time, we know the constants are invalid when JNI_CreateJavaVM() is
+    // called.
+    //
+    // Clean shutdown would require calling DeleteGlobalRef() for each of the
+    // class references, but JavaVM is unavailable because ART only calls this
+    // once all threads are unregistered.
     std::lock_guard guard(g_constants_mutex);
     g_constants_valid = false;
 }
@@ -145,11 +148,6 @@
     return booleanClass;
 }
 
-jclass JniConstants::GetCharsetICUClass(JNIEnv* env) {
-    EnsureJniConstantsInitialized(env);
-    return charsetICUClass;
-}
-
 jclass JniConstants::GetDoubleClass(JNIEnv* env) {
     EnsureJniConstantsInitialized(env);
     return doubleClass;
@@ -225,11 +223,6 @@
     return packetSocketAddressClass;
 }
 
-jclass JniConstants::GetPatternSyntaxExceptionClass(JNIEnv* env) {
-    EnsureJniConstantsInitialized(env);
-    return patternSyntaxExceptionClass;
-}
-
 jclass JniConstants::GetStringClass(JNIEnv* env) {
     EnsureJniConstantsInitialized(env);
     return stringClass;
@@ -240,11 +233,6 @@
     return structAddrinfoClass;
 }
 
-jclass JniConstants::GetStructFlockClass(JNIEnv* env) {
-    EnsureJniConstantsInitialized(env);
-    return structFlockClass;
-}
-
 jclass JniConstants::GetStructGroupReqClass(JNIEnv* env) {
     EnsureJniConstantsInitialized(env);
     return structGroupReqClass;
diff --git a/luni/src/main/native/JniConstants.h b/luni/src/main/native/JniConstants.h
index 021dc53..868e928 100644
--- a/luni/src/main/native/JniConstants.h
+++ b/luni/src/main/native/JniConstants.h
@@ -30,7 +30,6 @@
     static void Invalidate();
 
     static jclass GetBooleanClass(JNIEnv* env);
-    static jclass GetCharsetICUClass(JNIEnv* env);
     static jclass GetDoubleClass(JNIEnv* env);
     static jclass GetErrnoExceptionClass(JNIEnv* env);
     static jclass GetFileDescriptorClass(JNIEnv* env);
@@ -46,7 +45,6 @@
     static jclass GetLongClass(JNIEnv* env);
     static jclass GetNetlinkSocketAddressClass(JNIEnv* env);
     static jclass GetPacketSocketAddressClass(JNIEnv* env);
-    static jclass GetPatternSyntaxExceptionClass(JNIEnv* env);
     static jclass GetStringClass(JNIEnv* env);
     static jclass GetStructAddrinfoClass(JNIEnv* env);
     static jclass GetStructFlockClass(JNIEnv* env);
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index 0b4a94a..17ca839 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -40,10 +40,7 @@
     REGISTER(register_java_lang_invoke_MethodHandle);
     REGISTER(register_java_lang_invoke_VarHandle);
     REGISTER(register_java_math_NativeBN);
-    REGISTER(register_java_util_regex_Matcher);
-    REGISTER(register_java_util_regex_Pattern);
     REGISTER(register_libcore_icu_ICU);
-    REGISTER(register_libcore_icu_NativeConverter);
     REGISTER(register_libcore_icu_TimeZoneNames);
     REGISTER(register_libcore_io_AsynchronousCloseMonitor);
     REGISTER(register_libcore_io_Linux);
diff --git a/luni/src/main/native/ScopedIcuULoc.h b/luni/src/main/native/ScopedIcuULoc.h
new file mode 100644
index 0000000..5de5e36
--- /dev/null
+++ b/luni/src/main/native/ScopedIcuULoc.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#pragma once
+
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+#include "unicode/uloc.h"
+
+
+static void getLocale(const char* localeName, std::string& locale, UErrorCode* status) {
+    int length;
+    {
+        // Most common locale name should fit the max capacity.
+        char buffer[ULOC_FULLNAME_CAPACITY];
+        UErrorCode err = U_ZERO_ERROR;
+
+        length = uloc_getName(localeName, buffer, ULOC_FULLNAME_CAPACITY, &err);
+        if (U_SUCCESS(err)) {
+            locale = buffer;
+            *status = err;
+            return;
+        } else if (err != U_BUFFER_OVERFLOW_ERROR) {
+            *status = err;
+            return;
+        }
+    }
+
+    // Case U_BUFFER_OVERFLOW_ERROR
+    std::unique_ptr<char[]> buffer(new char[length+1]);
+    UErrorCode err = U_ZERO_ERROR;
+    uloc_getName(localeName, buffer.get(), length+1, &err);
+    if (U_SUCCESS(err)) {
+        locale = buffer.get();
+    }
+    *status = err;
+    return;
+}
+
+class ScopedIcuULoc {
+ public:
+  ScopedIcuULoc(JNIEnv* env, jstring javaLocaleName) {
+    isValid = false;
+
+    if (javaLocaleName == NULL) {
+      jniThrowNullPointerException(env, "javaLocaleName == null");
+      return;
+    }
+
+    const ScopedUtfChars localeName(env, javaLocaleName);
+    if (localeName.c_str() == NULL) {
+      return;
+    }
+
+    UErrorCode status = U_ZERO_ERROR;
+    getLocale(localeName.c_str(), mLocale, &status);
+    isValid = U_SUCCESS(status);
+  }
+
+  ~ScopedIcuULoc() {
+  }
+
+  bool valid() const {
+    return isValid;
+  }
+
+  const char* locale() const {
+    return mLocale.c_str();
+  }
+
+  int32_t locale_length() const {
+    return mLocale.length();
+  }
+
+ private:
+  bool isValid;
+  std::string mLocale;
+
+  // Disallow copy and assignment.
+  ScopedIcuULoc(const ScopedIcuULoc&);
+  void operator=(const ScopedIcuULoc&);
+};
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index bb19f6e..6cf2c8b 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -351,6 +351,7 @@
     initConstant(env, c, "_LINUX_CAPABILITY_VERSION_3", _LINUX_CAPABILITY_VERSION_3);
 #endif
     initConstant(env, c, "MAP_FIXED", MAP_FIXED);
+    initConstant(env, c, "MAP_ANONYMOUS", MAP_ANONYMOUS);
     initConstant(env, c, "MAP_POPULATE", MAP_POPULATE);
     initConstant(env, c, "MAP_PRIVATE", MAP_PRIVATE);
     initConstant(env, c, "MAP_SHARED", MAP_SHARED);
@@ -374,6 +375,9 @@
 #endif
     initConstant(env, c, "MCL_CURRENT", MCL_CURRENT);
     initConstant(env, c, "MCL_FUTURE", MCL_FUTURE);
+#if defined(MFD_CLOEXEC)
+    initConstant(env, c, "MFD_CLOEXEC", MFD_CLOEXEC);
+#endif
     initConstant(env, c, "MSG_CTRUNC", MSG_CTRUNC);
     initConstant(env, c, "MSG_DONTROUTE", MSG_DONTROUTE);
     initConstant(env, c, "MSG_EOR", MSG_EOR);
diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp
deleted file mode 100644
index 12fb764..0000000
--- a/luni/src/main/native/java_util_regex_Matcher.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#define LOG_TAG "Matcher"
-
-#include <memory>
-#include <stdlib.h>
-
-#include <android-base/logging.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedStringChars.h>
-#include <nativehelper/jni_macros.h>
-
-#include "IcuUtilities.h"
-#include "JniException.h"
-#include "ScopedJavaUnicodeString.h"
-#include "unicode/parseerr.h"
-#include "unicode/regex.h"
-
-// ICU documentation: http://icu-project.org/apiref/icu4c/classRegexMatcher.html
-
-/**
- * Encapsulates an instance of ICU4C's RegexMatcher class along with a copy of
- * the input it's currently operating on in the native heap.
- *
- * Rationale: We choose to make a copy here because it turns out to be a lot
- * cheaper when a moving GC and/or string compression is enabled. This is
- * because env->GetStringChars() always copies in this scenario. This becomes
- * especially bad when the String in question is long and/or contains a large
- * number of matches.
- *
- * Drawbacks: The native allocation associated with this class is no longer
- * fixed size, so we're effectively lying to the NativeAllocationRegistry about
- * the size of the object(s) we're allocating on the native heap. The peak
- * memory usage doesn't change though, given that GetStringChars would have
- * made an allocation of precisely the same size.
- */
-class MatcherState {
-public:
-    MatcherState(icu::RegexMatcher* matcher) :
-        mMatcher(matcher),
-        mUChars(nullptr),
-        mUText(nullptr),
-        mStatus(U_ZERO_ERROR) {
-    }
-
-    bool updateInput(JNIEnv* env, jstring input) {
-        // First, close the UText struct, since we're about to allocate a new one.
-        if (mUText != nullptr) {
-            utext_close(mUText);
-            mUText = nullptr;
-        }
-
-        // Then delete the UChar* associated with the UText struct..
-        mUChars.reset(nullptr);
-
-        // TODO: We should investigate whether we can avoid an additional copy
-        // in the native heap when is_copy == JNI_TRUE. The problem with doing
-        // that is that we might call ReleaseStringChars with a different
-        // JNIEnv* on a different downcall. This is currently safe as
-        // implemented in ART, but is unlikely to be portable and the spec stays
-        // silent on the matter.
-        ScopedStringChars inputChars(env, input);
-        if (inputChars.get() == nullptr) {
-            // There will be an exception pending if we get here.
-            return false;
-        }
-
-        // Make a copy of |input| on the native heap. This copy will be live
-        // until the next call to updateInput or close.
-        mUChars.reset(new (std::nothrow) UChar[inputChars.size()]);
-        if (mUChars.get() == nullptr) {
-            env->ThrowNew(env->FindClass("Ljava/lang/OutOfMemoryError;"), "Out of memory");
-            return false;
-        }
-
-        static_assert(sizeof(UChar) == sizeof(jchar), "sizeof(Uchar) != sizeof(jchar)");
-        memcpy(mUChars.get(), inputChars.get(), inputChars.size() * sizeof(jchar));
-
-        // Reset any errors that might have occurred on previous patches.
-        mStatus = U_ZERO_ERROR;
-        mUText = utext_openUChars(nullptr, mUChars.get(), inputChars.size(), &mStatus);
-        if (mUText == nullptr) {
-            CHECK(maybeThrowIcuException(env, "utext_openUChars", mStatus));
-            return false;
-        }
-
-        // It is an error for ICU to have returned a non-null mUText but to
-        // still have indicated an error.
-        CHECK(U_SUCCESS(mStatus));
-
-        mMatcher->reset(mUText);
-        return true;
-    }
-
-    ~MatcherState() {
-        if (mUText != nullptr) {
-            utext_close(mUText);
-        }
-    }
-
-    icu::RegexMatcher* matcher() {
-        return mMatcher.get();
-    }
-
-    UErrorCode& status() {
-        return mStatus;
-    }
-
-    void updateOffsets(JNIEnv* env, jintArray javaOffsets) {
-        ScopedIntArrayRW offsets(env, javaOffsets);
-        if (offsets.get() == NULL) {
-            return;
-        }
-
-        for (size_t i = 0, groupCount = mMatcher->groupCount(); i <= groupCount; ++i) {
-            offsets[2*i + 0] = mMatcher->start(i, mStatus);
-            offsets[2*i + 1] = mMatcher->end(i, mStatus);
-        }
-    }
-
-private:
-    std::unique_ptr<icu::RegexMatcher> mMatcher;
-    std::unique_ptr<UChar[]> mUChars;
-    UText* mUText;
-    UErrorCode mStatus;
-
-    // Disallow copy and assignment.
-    MatcherState(const MatcherState&);
-    void operator=(const MatcherState&);
-};
-
-static inline MatcherState* toMatcherState(jlong address) {
-    return reinterpret_cast<MatcherState*>(static_cast<uintptr_t>(address));
-}
-
-static void Matcher_free(void* address) {
-    MatcherState* state = reinterpret_cast<MatcherState*>(address);
-    delete state;
-}
-
-static jlong Matcher_getNativeFinalizer(JNIEnv*, jclass) {
-    return reinterpret_cast<jlong>(&Matcher_free);
-}
-
-static jboolean Matcher_findImpl(JNIEnv* env, jclass, jlong addr, jint startIndex, jintArray offsets) {
-    MatcherState* state = toMatcherState(addr);
-    UBool result = state->matcher()->find(startIndex, state->status());
-    if (result) {
-        state->updateOffsets(env, offsets);
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
-static jboolean Matcher_findNextImpl(JNIEnv* env, jclass, jlong addr, jintArray offsets) {
-    MatcherState* state = toMatcherState(addr);
-    UBool result = state->matcher()->find();
-    if (result) {
-        state->updateOffsets(env, offsets);
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
-static jint Matcher_groupCountImpl(JNIEnv*, jclass, jlong addr) {
-    MatcherState* state = toMatcherState(addr);
-    return state->matcher()->groupCount();
-}
-
-static jboolean Matcher_hitEndImpl(JNIEnv*, jclass, jlong addr) {
-    MatcherState* state = toMatcherState(addr);
-    if (state->matcher()->hitEnd() != 0) {
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
-static jboolean Matcher_lookingAtImpl(JNIEnv* env, jclass, jlong addr, jintArray offsets) {
-    MatcherState* state = toMatcherState(addr);
-    UBool result = state->matcher()->lookingAt(state->status());
-    if (result) {
-        state->updateOffsets(env, offsets);
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
-static jboolean Matcher_matchesImpl(JNIEnv* env, jclass, jlong addr, jintArray offsets) {
-    MatcherState* state = toMatcherState(addr);
-    UBool result = state->matcher()->matches(state->status());
-    if (result) {
-        state->updateOffsets(env, offsets);
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
-static jlong Matcher_openImpl(JNIEnv* env, jclass, jlong patternAddr) {
-    icu::RegexPattern* pattern = reinterpret_cast<icu::RegexPattern*>(static_cast<uintptr_t>(patternAddr));
-    UErrorCode status = U_ZERO_ERROR;
-    icu::RegexMatcher* result = pattern->matcher(status);
-    if (maybeThrowIcuException(env, "RegexPattern::matcher", status)) {
-        return 0;
-    }
-
-    return reinterpret_cast<uintptr_t>(new MatcherState(result));
-}
-
-static jboolean Matcher_requireEndImpl(JNIEnv*, jclass, jlong addr) {
-    MatcherState* state = toMatcherState(addr);
-    if (state->matcher()->requireEnd() != 0) {
-        return JNI_TRUE;
-    } else {
-        return JNI_FALSE;
-    }
-}
-
-static void Matcher_setInputImpl(JNIEnv* env, jclass, jlong addr, jstring javaText, jint start, jint end) {
-    MatcherState* state = toMatcherState(addr);
-    if (state->updateInput(env, javaText)) {
-        state->matcher()->region(start, end, state->status());
-    }
-}
-
-static void Matcher_useAnchoringBoundsImpl(JNIEnv*, jclass, jlong addr, jboolean value) {
-    MatcherState* state = toMatcherState(addr);
-    state->matcher()->useAnchoringBounds(value);
-}
-
-static void Matcher_useTransparentBoundsImpl(JNIEnv*, jclass, jlong addr, jboolean value) {
-    MatcherState* state = toMatcherState(addr);
-    state->matcher()->useTransparentBounds(value);
-}
-
-static jint Matcher_getMatchedGroupIndex0(JNIEnv* env, jclass, jlong patternAddr, jstring javaGroupName) {
-  icu::RegexPattern* pattern = reinterpret_cast<icu::RegexPattern*>(static_cast<uintptr_t>(patternAddr));
-  ScopedJavaUnicodeString groupName(env, javaGroupName);
-  UErrorCode status = U_ZERO_ERROR;
-
-  jint result = pattern->groupNumberFromName(groupName.unicodeString(), status);
-  if (U_SUCCESS(status)) {
-    return result;
-  }
-  if (status == U_REGEX_INVALID_CAPTURE_GROUP_NAME) {
-    return -1;
-  }
-  maybeThrowIcuException(env, "RegexPattern::groupNumberFromName", status);
-  return -1;
-}
-
-
-static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(Matcher, getMatchedGroupIndex0, "(JLjava/lang/String;)I"),
-    NATIVE_METHOD(Matcher, findImpl, "(JI[I)Z"),
-    NATIVE_METHOD(Matcher, findNextImpl, "(J[I)Z"),
-    NATIVE_METHOD(Matcher, getNativeFinalizer, "()J"),
-    NATIVE_METHOD(Matcher, groupCountImpl, "(J)I"),
-    NATIVE_METHOD(Matcher, hitEndImpl, "(J)Z"),
-    NATIVE_METHOD(Matcher, lookingAtImpl, "(J[I)Z"),
-    NATIVE_METHOD(Matcher, matchesImpl, "(J[I)Z"),
-    NATIVE_METHOD(Matcher, openImpl, "(J)J"),
-    NATIVE_METHOD(Matcher, requireEndImpl, "(J)Z"),
-    NATIVE_METHOD(Matcher, setInputImpl, "(JLjava/lang/String;II)V"),
-    NATIVE_METHOD(Matcher, useAnchoringBoundsImpl, "(JZ)V"),
-    NATIVE_METHOD(Matcher, useTransparentBoundsImpl, "(JZ)V"),
-};
-void register_java_util_regex_Matcher(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "java/util/regex/Matcher", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/java_util_regex_Pattern.cpp b/luni/src/main/native/java_util_regex_Pattern.cpp
deleted file mode 100644
index a893bab..0000000
--- a/luni/src/main/native/java_util_regex_Pattern.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#define LOG_TAG "Pattern"
-
-#include <stdlib.h>
-
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/jni_macros.h>
-
-#include "unicode/parseerr.h"
-#include "unicode/regex.h"
-
-#include "JniConstants.h"
-#include "ScopedJavaUnicodeString.h"
-
-// ICU documentation: http://icu-project.org/apiref/icu4c/classRegexPattern.html
-
-static const char* regexDetailMessage(UErrorCode status) {
-    // These human-readable error messages were culled from "utypes.h", and then slightly tuned
-    // to make more sense in context.
-    // If we don't have a special-case, we'll just return the textual name of
-    // the enum value (such as U_REGEX_RULE_SYNTAX), which is better than nothing.
-    switch (status) {
-    case U_REGEX_INTERNAL_ERROR: return "An internal error was detected";
-    case U_REGEX_RULE_SYNTAX: return "Syntax error in regexp pattern";
-    case U_REGEX_INVALID_STATE: return "Matcher in invalid state for requested operation";
-    case U_REGEX_BAD_ESCAPE_SEQUENCE: return "Unrecognized backslash escape sequence in pattern";
-    case U_REGEX_PROPERTY_SYNTAX: return "Incorrect Unicode property";
-    case U_REGEX_UNIMPLEMENTED: return "Use of unimplemented feature";
-    case U_REGEX_MISMATCHED_PAREN: return "Incorrectly nested parentheses in regexp pattern";
-    case U_REGEX_NUMBER_TOO_BIG: return "Decimal number is too large";
-    case U_REGEX_BAD_INTERVAL: return "Error in {min,max} interval";
-    case U_REGEX_MAX_LT_MIN: return "In {min,max}, max is less than min";
-    case U_REGEX_INVALID_BACK_REF: return "Back-reference to a non-existent capture group";
-    case U_REGEX_INVALID_FLAG: return "Invalid value for match mode flags";
-    case U_REGEX_LOOK_BEHIND_LIMIT: return "Look-behind pattern matches must have a bounded maximum length";
-    case U_REGEX_SET_CONTAINS_STRING: return "Regular expressions cannot have UnicodeSets containing strings";
-    case U_REGEX_OCTAL_TOO_BIG: return "Octal character constants must be <= 0377.";
-    case U_REGEX_MISSING_CLOSE_BRACKET: return "Missing closing bracket in character class";
-    case U_REGEX_INVALID_RANGE: return "In a character range [x-y], x is greater than y";
-    case U_REGEX_STACK_OVERFLOW: return "Regular expression backtrack stack overflow";
-    case U_REGEX_TIME_OUT: return "Maximum allowed match time exceeded";
-    case U_REGEX_STOPPED_BY_CALLER: return "Matching operation aborted by user callback function";
-    default:
-        return u_errorName(status);
-    }
-}
-
-static void throwPatternSyntaxException(JNIEnv* env, UErrorCode status, jstring pattern, UParseError error) {
-    static jmethodID method = env->GetMethodID(JniConstants::GetPatternSyntaxExceptionClass(env),
-            "<init>", "(Ljava/lang/String;Ljava/lang/String;I)V");
-    jstring message = env->NewStringUTF(regexDetailMessage(status));
-    jclass exceptionClass = JniConstants::GetPatternSyntaxExceptionClass(env);
-    jobject exception = env->NewObject(exceptionClass, method, message, pattern, error.offset);
-    env->Throw(reinterpret_cast<jthrowable>(exception));
-}
-
-static void Pattern_free(void* addr) {
-    delete reinterpret_cast<icu::RegexPattern*>(addr);
-}
-
-static jlong Pattern_getNativeFinalizer(JNIEnv*, jclass) {
-    return reinterpret_cast<jlong>(&Pattern_free);
-}
-
-static jlong Pattern_compileImpl(JNIEnv* env, jclass, jstring javaRegex, jint flags) {
-    flags |= UREGEX_ERROR_ON_UNKNOWN_ESCAPES;
-
-    UErrorCode status = U_ZERO_ERROR;
-    UParseError error;
-    error.offset = -1;
-
-    ScopedJavaUnicodeString regex(env, javaRegex);
-    if (!regex.valid()) {
-        return 0;
-    }
-    icu::UnicodeString& regexString(regex.unicodeString());
-    icu::RegexPattern* result = icu::RegexPattern::compile(regexString, flags, error, status);
-    if (!U_SUCCESS(status)) {
-        throwPatternSyntaxException(env, status, javaRegex, error);
-    }
-    return static_cast<jlong>(reinterpret_cast<uintptr_t>(result));
-}
-
-static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(Pattern, compileImpl, "(Ljava/lang/String;I)J"),
-    NATIVE_METHOD(Pattern, getNativeFinalizer, "()J"),
-};
-
-void register_java_util_regex_Pattern(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "java/util/regex/Pattern", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 8a571fd..9879761 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -23,19 +23,18 @@
 #include <string.h>
 #include <string>
 #include <sys/mman.h>
-#include <sys/stat.h>
 #include <sys/time.h>
-#include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 
 #include <memory>
 #include <vector>
 
-#include <android-base/unique_fd.h>
+#include <androidicuinit/IcuRegistration.h>
 #include <log/log.h>
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedStringChars.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/jni_macros.h>
 #include <nativehelper/toStringArray.h>
@@ -44,28 +43,27 @@
 #include "JniConstants.h"
 #include "JniException.h"
 #include "ScopedIcuLocale.h"
+#include "ScopedIcuULoc.h"
 #include "ScopedJavaUnicodeString.h"
 #include "unicode/brkiter.h"
+#include "unicode/char16ptr.h"
 #include "unicode/calendar.h"
 #include "unicode/datefmt.h"
 #include "unicode/dcfmtsym.h"
 #include "unicode/decimfmt.h"
 #include "unicode/dtfmtsym.h"
-#include "unicode/dtptngen.h"
 #include "unicode/gregocal.h"
 #include "unicode/locid.h"
 #include "unicode/numfmt.h"
 #include "unicode/strenum.h"
-#include "unicode/timezone.h"
 #include "unicode/ubrk.h"
 #include "unicode/ucal.h"
 #include "unicode/ucasemap.h"
-#include "unicode/uclean.h"
 #include "unicode/ucol.h"
 #include "unicode/ucurr.h"
 #include "unicode/udat.h"
+#include "unicode/udatpg.h"
 #include "unicode/uloc.h"
-#include "unicode/ulocdata.h"
 #include "unicode/ures.h"
 #include "unicode/ustring.h"
 #include "ureslocs.h"
@@ -97,42 +95,21 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedResourceBundle);
 };
 
-static jstring ICU_addLikelySubtags(JNIEnv* env, jclass, jstring javaLocaleName) {
-    UErrorCode status = U_ZERO_ERROR;
-    ScopedUtfChars localeID(env, javaLocaleName);
-    char maximizedLocaleID[ULOC_FULLNAME_CAPACITY];
-    uloc_addLikelySubtags(localeID.c_str(), maximizedLocaleID, sizeof(maximizedLocaleID), &status);
-    if (U_FAILURE(status)) {
-        return javaLocaleName;
-    }
-    return env->NewStringUTF(maximizedLocaleID);
-}
-
 static jstring ICU_getScript(JNIEnv* env, jclass, jstring javaLocaleName) {
-  ScopedIcuLocale icuLocale(env, javaLocaleName);
+  ScopedIcuULoc icuLocale(env, javaLocaleName);
   if (!icuLocale.valid()) {
     return NULL;
   }
-  return env->NewStringUTF(icuLocale.locale().getScript());
-}
-
-static jint ICU_getCurrencyFractionDigits(JNIEnv* env, jclass, jstring javaCurrencyCode) {
-  ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
-  if (!currencyCode.valid()) {
-    return 0;
-  }
-  icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
+  // Normal script part is 4-char long. Being conservative for allocation size
+  // because if the locale contains script part, it should not be longer than the locale itself.
+  int32_t capacity = std::max(ULOC_SCRIPT_CAPACITY, icuLocale.locale_length() + 1);
+  std::unique_ptr<char[]> buffer(new char(capacity));
   UErrorCode status = U_ZERO_ERROR;
-  return ucurr_getDefaultFractionDigits(icuCurrencyCode.getTerminatedBuffer(), &status);
-}
-
-static jint ICU_getCurrencyNumericCode(JNIEnv* env, jclass, jstring javaCurrencyCode) {
-  ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
-  if (!currencyCode.valid()) {
-    return 0;
+  uloc_getScript(icuLocale.locale(), buffer.get(), capacity, &status);
+  if (U_FAILURE(status)) {
+    return NULL;
   }
-  icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
-  return ucurr_getNumericCode(icuCurrencyCode.getTerminatedBuffer());
+  return env->NewStringUTF(buffer.get());
 }
 
 // TODO: rewrite this with int32_t ucurr_forLocale(const char* locale, UChar* buff, int32_t buffCapacity, UErrorCode* ec)...
@@ -210,122 +187,34 @@
   return (charCount == 0) ? NULL : jniCreateString(env, chars, charCount);
 }
 
-static jstring ICU_getCurrencyDisplayName(JNIEnv* env, jclass, jstring javaLanguageTag, jstring javaCurrencyCode) {
-  return getCurrencyName(env, javaLanguageTag, javaCurrencyCode, UCURR_LONG_NAME);
-}
-
-static jstring ICU_getCurrencySymbol(JNIEnv* env, jclass, jstring javaLanguageTag, jstring javaCurrencyCode) {
-  return getCurrencyName(env, javaLanguageTag, javaCurrencyCode, UCURR_SYMBOL_NAME);
-}
-
-static jstring ICU_getDisplayCountryNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
-  if (!icuLocale.valid()) {
-    return NULL;
-  }
-  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
-  if (!icuTargetLocale.valid()) {
-    return NULL;
-  }
-
-  icu::UnicodeString str;
-  icuTargetLocale.locale().getDisplayCountry(icuLocale.locale(), str);
-  return jniCreateString(env, str.getBuffer(), str.length());
-}
-
-static jstring ICU_getDisplayLanguageNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
-  if (!icuLocale.valid()) {
-    return NULL;
-  }
-  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
-  if (!icuTargetLocale.valid()) {
-    return NULL;
-  }
-
-  icu::UnicodeString str;
-  icuTargetLocale.locale().getDisplayLanguage(icuLocale.locale(), str);
-  return jniCreateString(env, str.getBuffer(), str.length());
-}
-
-static jstring ICU_getDisplayScriptNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
-  if (!icuLocale.valid()) {
-    return NULL;
-  }
-  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
-  if (!icuTargetLocale.valid()) {
-    return NULL;
-  }
-
-  icu::UnicodeString str;
-  icuTargetLocale.locale().getDisplayScript(icuLocale.locale(), str);
-  return jniCreateString(env, str.getBuffer(), str.length());
-}
-
-static jstring ICU_getDisplayVariantNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
-  if (!icuLocale.valid()) {
-    return NULL;
-  }
-  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
-  if (!icuTargetLocale.valid()) {
-    return NULL;
-  }
-
-  icu::UnicodeString str;
-  icuTargetLocale.locale().getDisplayVariant(icuLocale.locale(), str);
-  return jniCreateString(env, str.getBuffer(), str.length());
-}
-
 static jstring ICU_getISO3Country(JNIEnv* env, jclass, jstring javaLanguageTag) {
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  ScopedIcuULoc icuLocale(env, javaLanguageTag);
   if (!icuLocale.valid()) {
     return NULL;
   }
-  return env->NewStringUTF(icuLocale.locale().getISO3Country());
+  return env->NewStringUTF(uloc_getISO3Country(icuLocale.locale()));
 }
 
 static jstring ICU_getISO3Language(JNIEnv* env, jclass, jstring javaLanguageTag) {
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  ScopedIcuULoc icuLocale(env, javaLanguageTag);
   if (!icuLocale.valid()) {
     return NULL;
   }
-  return env->NewStringUTF(icuLocale.locale().getISO3Language());
+  return env->NewStringUTF(uloc_getISO3Language(icuLocale.locale()));
 }
 
 static jobjectArray ICU_getISOCountriesNative(JNIEnv* env, jclass) {
-    return toStringArray(env, icu::Locale::getISOCountries());
+    return toStringArray(env, uloc_getISOCountries());
 }
 
 static jobjectArray ICU_getISOLanguagesNative(JNIEnv* env, jclass) {
-    return toStringArray(env, icu::Locale::getISOLanguages());
+    return toStringArray(env, uloc_getISOLanguages());
 }
 
 static jobjectArray ICU_getAvailableLocalesNative(JNIEnv* env, jclass) {
     return toStringArray(env, uloc_countAvailable, uloc_getAvailable);
 }
 
-static jobjectArray ICU_getAvailableBreakIteratorLocalesNative(JNIEnv* env, jclass) {
-    return toStringArray(env, ubrk_countAvailable, ubrk_getAvailable);
-}
-
-static jobjectArray ICU_getAvailableCalendarLocalesNative(JNIEnv* env, jclass) {
-    return toStringArray(env, ucal_countAvailable, ucal_getAvailable);
-}
-
-static jobjectArray ICU_getAvailableCollatorLocalesNative(JNIEnv* env, jclass) {
-    return toStringArray(env, ucol_countAvailable, ucol_getAvailable);
-}
-
-static jobjectArray ICU_getAvailableDateFormatLocalesNative(JNIEnv* env, jclass) {
-    return toStringArray(env, udat_countAvailable, udat_getAvailable);
-}
-
-static jobjectArray ICU_getAvailableNumberFormatLocalesNative(JNIEnv* env, jclass) {
-    return toStringArray(env, unum_countAvailable, unum_getAvailable);
-}
-
 static bool setIntegerField(JNIEnv* env, jobject obj, const char* fieldName, int value) {
     ScopedLocalRef<jobject> integerValue(env, integerValueOf(env, value));
     if (integerValue.get() == NULL) return false;
@@ -684,7 +573,7 @@
 
     jstring currencySymbol = NULL;
     if (internationalCurrencySymbol != NULL) {
-        currencySymbol = ICU_getCurrencySymbol(env, NULL, javaLanguageTag, internationalCurrencySymbol);
+        currencySymbol = getCurrencyName(env, javaLanguageTag, internationalCurrencySymbol, UCURR_SYMBOL_NAME);
     } else {
         internationalCurrencySymbol = env->NewStringUTF("XXX");
     }
@@ -698,148 +587,82 @@
     return JNI_TRUE;
 }
 
-static jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring javaLanguageTag) {
-  ScopedJavaUnicodeString scopedString(env, javaString);
-  if (!scopedString.valid()) {
-    return NULL;
-  }
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
-  if (!icuLocale.valid()) {
-    return NULL;
-  }
-  icu::UnicodeString& s(scopedString.unicodeString());
-  icu::UnicodeString original(s);
-  s.toLower(icuLocale.locale());
-  return s == original ? javaString : jniCreateString(env, s.getBuffer(), s.length());
-}
-
-static jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring javaLanguageTag) {
-  ScopedJavaUnicodeString scopedString(env, javaString);
-  if (!scopedString.valid()) {
-    return NULL;
-  }
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
-  if (!icuLocale.valid()) {
-    return NULL;
-  }
-  icu::UnicodeString& s(scopedString.unicodeString());
-  icu::UnicodeString original(s);
-  s.toUpper(icuLocale.locale());
-  return s == original ? javaString : jniCreateString(env, s.getBuffer(), s.length());
-}
-
-static jstring versionString(JNIEnv* env, const UVersionInfo& version) {
-    char versionString[U_MAX_VERSION_STRING_LENGTH];
-    u_versionToString(const_cast<UVersionInfo&>(version), &versionString[0]);
-    return env->NewStringUTF(versionString);
-}
-
-static jstring ICU_getCldrVersion(JNIEnv* env, jclass) {
-  UErrorCode status = U_ZERO_ERROR;
-  UVersionInfo cldrVersion;
-  ulocdata_getCLDRVersion(cldrVersion, &status);
-  return versionString(env, cldrVersion);
-}
-
-static jstring ICU_getIcuVersion(JNIEnv* env, jclass) {
-    UVersionInfo icuVersion;
-    u_getVersion(icuVersion);
-    return versionString(env, icuVersion);
-}
-
-static jstring ICU_getUnicodeVersion(JNIEnv* env, jclass) {
-    UVersionInfo unicodeVersion;
-    u_getUnicodeVersion(unicodeVersion);
-    return versionString(env, unicodeVersion);
-}
-
-static jstring ICU_getTZDataVersion(JNIEnv* env, jclass) {
-  UErrorCode status = U_ZERO_ERROR;
-  const char* version = icu::TimeZone::getTZDataVersion(status);
-  if (maybeThrowIcuException(env, "icu::TimeZone::getTZDataVersion", status)) {
-    return NULL;
-  }
-  return env->NewStringUTF(version);
-}
-
-static jobjectArray ICU_getAvailableCurrencyCodes(JNIEnv* env, jclass) {
-  UErrorCode status = U_ZERO_ERROR;
-  icu::UStringEnumeration e(ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &status));
-  return fromStringEnumeration(env, status, "ucurr_openISOCurrencies", &e);
-}
-
 static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLanguageTag) {
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  ScopedIcuULoc icuLocale(env, javaLanguageTag);
   if (!icuLocale.valid()) {
     return NULL;
   }
 
   UErrorCode status = U_ZERO_ERROR;
-  std::unique_ptr<icu::DateTimePatternGenerator> generator(icu::DateTimePatternGenerator::createInstance(icuLocale.locale(), status));
-  if (maybeThrowIcuException(env, "DateTimePatternGenerator::createInstance", status)) {
+  std::unique_ptr<UDateTimePatternGenerator, decltype(&udatpg_close)> generator(
+    udatpg_open(icuLocale.locale(), &status), &udatpg_close);
+  if (maybeThrowIcuException(env, "udatpg_open", status)) {
     return NULL;
   }
 
-  ScopedJavaUnicodeString skeletonHolder(env, javaSkeleton);
-  if (!skeletonHolder.valid()) {
-    return NULL;
+  const ScopedStringChars skeletonHolder(env, javaSkeleton);
+  // Convert jchar* to UChar* with the inline-able utility provided by char16ptr.h
+  // which prevents certain compiler optimization than reinterpret_cast.
+  icu::ConstChar16Ptr skeletonPtr(skeletonHolder.get());
+  const UChar* skeleton = icu::toUCharPtr(skeletonPtr.get());
+
+  int32_t patternLength;
+  // Try with fixed-size buffer. 128 chars should be enough for most patterns.
+  // If the buffer is not sufficient, run the below case of U_BUFFER_OVERFLOW_ERROR.
+  #define PATTERN_BUFFER_SIZE 128
+  {
+    UChar buffer[PATTERN_BUFFER_SIZE];
+    status = U_ZERO_ERROR;
+    patternLength = udatpg_getBestPattern(generator.get(), skeleton,
+      skeletonHolder.size(), buffer, PATTERN_BUFFER_SIZE, &status);
+    if (U_SUCCESS(status)) {
+      return jniCreateString(env, buffer, patternLength);
+    } else if (status != U_BUFFER_OVERFLOW_ERROR) {
+      maybeThrowIcuException(env, "udatpg_getBestPattern", status);
+      return NULL;
+    }
   }
-  icu::UnicodeString result(generator->getBestPattern(skeletonHolder.unicodeString(), status));
-  if (maybeThrowIcuException(env, "DateTimePatternGenerator::getBestPattern", status)) {
+  #undef PATTERN_BUFFER_SIZE
+
+  // Case U_BUFFER_OVERFLOW_ERROR
+  std::unique_ptr<UChar[]> buffer(new UChar[patternLength+1]);
+  status = U_ZERO_ERROR;
+  patternLength = udatpg_getBestPattern(generator.get(), skeleton,
+      skeletonHolder.size(), buffer.get(), patternLength+1, &status);
+  if (maybeThrowIcuException(env, "udatpg_getBestPattern", status)) {
     return NULL;
   }
 
-  return jniCreateString(env, result.getBuffer(), result.length());
+  return jniCreateString(env, buffer.get(), patternLength);
 }
 
 static void ICU_setDefaultLocale(JNIEnv* env, jclass, jstring javaLanguageTag) {
-  ScopedIcuLocale icuLocale(env, javaLanguageTag);
+  ScopedIcuULoc icuLocale(env, javaLanguageTag);
   if (!icuLocale.valid()) {
     return;
   }
 
   UErrorCode status = U_ZERO_ERROR;
-  icu::Locale::setDefault(icuLocale.locale(), status);
-  maybeThrowIcuException(env, "Locale::setDefault", status);
+  uloc_setDefault(icuLocale.locale(), &status);
+  maybeThrowIcuException(env, "uloc_setDefault", status);
 }
 
 static jstring ICU_getDefaultLocale(JNIEnv* env, jclass) {
-  return env->NewStringUTF(icu::Locale::getDefault().getName());
+  return env->NewStringUTF(uloc_getDefault());
 }
 
 static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(ICU, addLikelySubtags, "(Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getAvailableBreakIteratorLocalesNative, "()[Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getAvailableCalendarLocalesNative, "()[Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getAvailableCollatorLocalesNative, "()[Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getAvailableCurrencyCodes, "()[Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getAvailableDateFormatLocalesNative, "()[Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getAvailableLocalesNative, "()[Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getAvailableNumberFormatLocalesNative, "()[Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getBestDateTimePatternNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getCldrVersion, "()Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getCurrencyCode, "(Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getCurrencyDisplayName, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getCurrencyFractionDigits, "(Ljava/lang/String;)I"),
-    NATIVE_METHOD(ICU, getCurrencyNumericCode, "(Ljava/lang/String;)I"),
-    NATIVE_METHOD(ICU, getCurrencySymbol, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getDefaultLocale, "()Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getDisplayCountryNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getDisplayLanguageNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getDisplayScriptNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getDisplayVariantNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getISO3Country, "(Ljava/lang/String;)Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getISO3Language, "(Ljava/lang/String;)Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getISOCountriesNative, "()[Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getISOLanguagesNative, "()[Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getIcuVersion, "()Ljava/lang/String;"),
     NATIVE_METHOD(ICU, getScript, "(Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getTZDataVersion, "()Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, getUnicodeVersion, "()Ljava/lang/String;"),
     NATIVE_METHOD(ICU, initLocaleDataNative, "(Ljava/lang/String;Llibcore/icu/LocaleData;)Z"),
     NATIVE_METHOD(ICU, setDefaultLocale, "(Ljava/lang/String;)V"),
-    NATIVE_METHOD(ICU, toLowerCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
-    NATIVE_METHOD(ICU, toUpperCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
 };
 
 //
@@ -847,241 +670,17 @@
 //   - Contains handlers for JNI_OnLoad and JNI_OnUnload
 //
 
-#define FAIL_WITH_STRERROR(s) \
-    ALOGE("Couldn't " s " '%s': %s", path_.c_str(), strerror(errno)); \
-    return FALSE;
-
-#define MAYBE_FAIL_WITH_ICU_ERROR(s) \
-    if (status != U_ZERO_ERROR) {\
-        ALOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path_.c_str()); \
-        return FALSE; \
-    }
-
-// Contain the memory map for ICU data files.
-// Automatically adds the data file to ICU's list of data files upon constructing.
-//
-// - Automatically unmaps in the destructor.
-struct IcuDataMap {
-  // Map in ICU data at the path, returning null if it failed (prints error to ALOGE).
-  static std::unique_ptr<IcuDataMap> Create(const std::string& path) {
-    std::unique_ptr<IcuDataMap> map(new IcuDataMap(path));
-
-    if (!map->TryMap()) {
-      // madvise or ICU could fail but mmap still succeeds.
-      // Destructor will take care of cleaning up a partial init.
-      return nullptr;
-    }
-
-    return map;
-  }
-
-  // Unmap the ICU data.
-  ~IcuDataMap() {
-    TryUnmap();
-  }
-
- private:
-  IcuDataMap(const std::string& path)
-    : path_(path),
-      data_(MAP_FAILED),
-      data_length_(0)
-  {}
-
-  bool TryMap() {
-    // Open the file and get its length.
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path_.c_str(), O_RDONLY)));
-
-    if (fd.get() == -1) {
-        FAIL_WITH_STRERROR("open");
-    }
-
-    struct stat sb;
-    if (fstat(fd.get(), &sb) == -1) {
-        FAIL_WITH_STRERROR("stat");
-    }
-
-    data_length_ = sb.st_size;
-
-    // Map it.
-    data_ = mmap(NULL, data_length_, PROT_READ, MAP_SHARED, fd.get(), 0  /* offset */);
-    if (data_ == MAP_FAILED) {
-        FAIL_WITH_STRERROR("mmap");
-    }
-
-    // Tell the kernel that accesses are likely to be random rather than sequential.
-    if (madvise(data_, data_length_, MADV_RANDOM) == -1) {
-        FAIL_WITH_STRERROR("madvise(MADV_RANDOM)");
-    }
-
-    UErrorCode status = U_ZERO_ERROR;
-
-    // Tell ICU to use our memory-mapped data.
-    udata_setCommonData(data_, &status);
-    MAYBE_FAIL_WITH_ICU_ERROR("udata_setCommonData");
-
-    return true;
-  }
-
-  bool TryUnmap() {
-    // Don't need to do opposite of udata_setCommonData,
-    // u_cleanup (performed in unregister_libcore_icu_ICU) takes care of it.
-
-    // Don't need to opposite of madvise, munmap will take care of it.
-
-    if (data_ != MAP_FAILED) {
-      if (munmap(data_, data_length_) == -1) {
-        FAIL_WITH_STRERROR("munmap");
-      }
-    }
-
-    // Don't need to close the file, it was closed automatically during TryMap.
-    return true;
-  }
-
-  std::string path_;    // Save for error messages.
-  void* data_;          // Save for munmap.
-  size_t data_length_;  // Save for munmap.
-};
-
-struct ICURegistration {
-  // Init ICU, configuring it and loading the data files.
-  ICURegistration(JNIEnv* env) {
-    UErrorCode status = U_ZERO_ERROR;
-    // Tell ICU it can *only* use our memory-mapped data.
-    udata_setFileAccess(UDATA_NO_FILES, &status);
-    if (status != U_ZERO_ERROR) {
-        ALOGE("Couldn't initialize ICU (s_setFileAccess): %s", u_errorName(status));
-        abort();
-    }
-
-    // Check the timezone /data override file exists from the "Time zone update via APK" feature.
-    // https://source.android.com/devices/tech/config/timezone-rules
-    // If it does, map it first so we use its data in preference to later ones.
-    std::string dataPath = getDataTimeZonePath();
-    if (pathExists(dataPath)) {
-        ALOGD("Time zone override file found: %s", dataPath.c_str());
-        if ((icu_datamap_from_data_ = IcuDataMap::Create(dataPath)) == nullptr) {
-            ALOGW("TZ override /data file %s exists but could not be loaded. Skipping.",
-                    dataPath.c_str());
-        }
-    } else {
-        ALOGV("No timezone override /data file found: %s", dataPath.c_str());
-    }
-
-    // Check the timezone override file exists from a mounted APEX file.
-    // If it does, map it next so we use its data in preference to later ones.
-    std::string tzModulePath = getTimeZoneModulePath();
-    if (pathExists(tzModulePath)) {
-        ALOGD("Time zone APEX file found: %s", tzModulePath.c_str());
-        if ((icu_datamap_from_tz_module_ = IcuDataMap::Create(tzModulePath)) == nullptr) {
-            ALOGW("TZ module override file %s exists but could not be loaded. Skipping.",
-                    tzModulePath.c_str());
-        }
-    } else {
-        ALOGV("No time zone module override file found: %s", tzModulePath.c_str());
-    }
-
-    // Use the ICU data files that shipped with the runtime module for everything else.
-    icu_datamap_from_runtime_module_ = IcuDataMap::Create(getRuntimeModulePath());
-    if (icu_datamap_from_runtime_module_ == nullptr) {
-        abort();
-    }
-
-    // Failures to find the ICU data tend to be somewhat obscure because ICU loads its data on first
-    // use, which can be anywhere. Force initialization up front so we can report a nice clear error
-    // and bail.
-    u_init(&status);
-    if (status != U_ZERO_ERROR) {\
-        ALOGE("Couldn't initialize ICU (u_init): %s", u_errorName(status));
-        abort();
-    }
-
-    jniRegisterNativeMethods(env, "libcore/icu/ICU", gMethods, NELEM(gMethods));
-  }
-
-  // De-init ICU, unloading the data files. Do the opposite of the above function.
-  ~ICURegistration() {
-    // Skip unregistering JNI methods explicitly, class unloading takes care of it.
-
-    // Reset libicu state to before it was loaded.
-    u_cleanup();
-
-    // Unmap ICU data files from the runtime module.
-    icu_datamap_from_runtime_module_.reset();
-
-    // Unmap optional TZ module files from /apex.
-    icu_datamap_from_tz_module_.reset();
-
-    // Unmap optional TZ /data file.
-    icu_datamap_from_data_.reset();
-
-    // We don't need to call udata_setFileAccess because u_cleanup takes care of it.
-  }
-
-  static bool pathExists(const std::string path) {
-    struct stat sb;
-    return stat(path.c_str(), &sb) == 0;
-  }
-
-  // Returns a string containing the expected path of the (optional) /data tz data file
-  static std::string getDataTimeZonePath() {
-    const char* dataPathPrefix = getenv("ANDROID_DATA");
-    if (dataPathPrefix == NULL) {
-      ALOGE("ANDROID_DATA environment variable not set"); \
-      abort();
-    }
-    std::string dataPath;
-    dataPath = dataPathPrefix;
-    dataPath += "/misc/zoneinfo/current/icu/icu_tzdata.dat";
-
-    return dataPath;
-  }
-
-  // Returns a string containing the expected path of the (optional) /apex tz module data file
-  static std::string getTimeZoneModulePath() {
-    const char* tzdataModulePathPrefix = getenv("ANDROID_TZDATA_ROOT");
-    if (tzdataModulePathPrefix == NULL) {
-      ALOGE("ANDROID_TZDATA_ROOT environment variable not set"); \
-      abort();
-    }
-
-    std::string tzdataModulePath;
-    tzdataModulePath = tzdataModulePathPrefix;
-    tzdataModulePath += "/etc/icu/icu_tzdata.dat";
-    return tzdataModulePath;
-  }
-
-  static std::string getRuntimeModulePath() {
-    const char* runtimeModulePathPrefix = getenv("ANDROID_RUNTIME_ROOT");
-    if (runtimeModulePathPrefix == NULL) {
-      ALOGE("ANDROID_RUNTIME_ROOT environment variable not set"); \
-      abort();
-    }
-
-    std::string runtimeModulePath;
-    runtimeModulePath = runtimeModulePathPrefix;
-    runtimeModulePath += "/etc/icu/";
-    runtimeModulePath += U_ICUDATA_NAME;
-    runtimeModulePath += ".dat";
-    return runtimeModulePath;
-  }
-
-  std::unique_ptr<IcuDataMap> icu_datamap_from_data_;
-  std::unique_ptr<IcuDataMap> icu_datamap_from_tz_module_;
-  std::unique_ptr<IcuDataMap> icu_datamap_from_runtime_module_;
-};
-
-// Use RAII-style initialization/teardown so that we can get unregistered
-// when dlclose is called (even if JNI_OnUnload is not).
-static std::unique_ptr<ICURegistration> sIcuRegistration;
-
 // Init ICU, configuring it and loading the data files.
 void register_libcore_icu_ICU(JNIEnv* env) {
-  sIcuRegistration.reset(new ICURegistration(env));
+  androidicuinit::IcuRegistration::Register();
+
+  jniRegisterNativeMethods(env, "libcore/icu/ICU", gMethods, NELEM(gMethods));
 }
 
 // De-init ICU, unloading the data files. Do the opposite of the above function.
 void unregister_libcore_icu_ICU() {
-  // Explicitly calling this is optional. Dlclose will take care of it as well.
-  sIcuRegistration.reset();
+  // Skip unregistering JNI methods explicitly, class unloading takes care of
+  // it.
+
+  androidicuinit::IcuRegistration::Deregister();
 }
diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp
deleted file mode 100644
index 9ccfabd..0000000
--- a/luni/src/main/native/libcore_icu_NativeConverter.cpp
+++ /dev/null
@@ -1,700 +0,0 @@
-/**
-*******************************************************************************
-* Copyright (C) 1996-2006, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
-*******************************************************************************
-*
-*
-*******************************************************************************
-*/
-/*
- * (C) Copyright IBM Corp. 2000 - All Rights Reserved
- *  A JNI wrapper to ICU native converter Interface
- * @author: Ram Viswanadha
- */
-
-#define LOG_TAG "NativeConverter"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <memory>
-#include <vector>
-
-#include <android/log.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedStringChars.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include <nativehelper/jni_macros.h>
-#include <nativehelper/toStringArray.h>
-
-#include "IcuUtilities.h"
-#include "JniConstants.h"
-#include "JniException.h"
-#include "unicode/ucnv.h"
-#include "unicode/ucnv_cb.h"
-#include "unicode/uniset.h"
-#include "unicode/ustring.h"
-#include "unicode/utypes.h"
-
-#define NativeConverter_REPORT 0
-#define NativeConverter_IGNORE 1
-#define NativeConverter_REPLACE 2
-
-#define MAX_REPLACEMENT_LENGTH 32 // equivalent to UCNV_ERROR_BUFFER_LENGTH
-
-struct DecoderCallbackContext {
-    UChar replacementChars[MAX_REPLACEMENT_LENGTH];
-    size_t replacementCharCount;
-    UConverterToUCallback onUnmappableInput;
-    UConverterToUCallback onMalformedInput;
-};
-
-struct EncoderCallbackContext {
-    char replacementBytes[MAX_REPLACEMENT_LENGTH];
-    size_t replacementByteCount;
-    UConverterFromUCallback onUnmappableInput;
-    UConverterFromUCallback onMalformedInput;
-};
-
-static UConverter* toUConverter(jlong address) {
-    return reinterpret_cast<UConverter*>(static_cast<uintptr_t>(address));
-}
-
-static bool collectStandardNames(JNIEnv* env, const char* canonicalName, const char* standard,
-                                 std::vector<std::string>& result) {
-  UErrorCode status = U_ZERO_ERROR;
-  icu::UStringEnumeration e(ucnv_openStandardNames(canonicalName, standard, &status));
-  if (maybeThrowIcuException(env, "ucnv_openStandardNames", status)) {
-    return false;
-  }
-
-  int32_t count = e.count(status);
-  if (maybeThrowIcuException(env, "StringEnumeration::count", status)) {
-    return false;
-  }
-
-  for (int32_t i = 0; i < count; ++i) {
-    const icu::UnicodeString* string = e.snext(status);
-    if (maybeThrowIcuException(env, "StringEnumeration::snext", status)) {
-      return false;
-    }
-    std::string s;
-    string->toUTF8String(s);
-    if (s.find_first_of("+,") == std::string::npos) {
-      result.push_back(s);
-    }
-  }
-
-  return true;
-}
-
-static const char* getICUCanonicalName(const char* name) {
-  UErrorCode error = U_ZERO_ERROR;
-  const char* canonicalName = NULL;
-  if ((canonicalName = ucnv_getCanonicalName(name, "MIME", &error)) != NULL) {
-    return canonicalName;
-  } else if ((canonicalName = ucnv_getCanonicalName(name, "IANA", &error)) != NULL) {
-    return canonicalName;
-  } else if ((canonicalName = ucnv_getCanonicalName(name, "", &error)) != NULL) {
-    return canonicalName;
-  } else if ((canonicalName = ucnv_getAlias(name, 0, &error)) != NULL) {
-    // We have some aliases in the form x-blah .. match those first.
-    return canonicalName;
-  } else if (strstr(name, "x-") == name) {
-    // Check if the converter can be opened with the name given.
-    error = U_ZERO_ERROR;
-    icu::LocalUConverterPointer cnv(ucnv_open(name + 2, &error));
-    if (U_SUCCESS(error)) {
-      return name + 2;
-    }
-  }
-  return NULL;
-}
-
-// If a charset listed in the IANA Charset Registry is supported by an implementation
-// of the Java platform then its canonical name must be the name listed in the registry.
-// Many charsets are given more than one name in the registry, in which case the registry
-// identifies one of the names as MIME-preferred. If a charset has more than one registry
-// name then its canonical name must be the MIME-preferred name and the other names in
-// the registry must be valid aliases. If a supported charset is not listed in the IANA
-// registry then its canonical name must begin with one of the strings "X-" or "x-".
-static jstring getJavaCanonicalName(JNIEnv* env, const char* icuCanonicalName) {
-  UErrorCode status = U_ZERO_ERROR;
-
-  // Check to see if this is a well-known MIME or IANA name.
-  const char* cName = NULL;
-  if ((cName = ucnv_getStandardName(icuCanonicalName, "MIME", &status)) != NULL) {
-    return env->NewStringUTF(cName);
-  } else if ((cName = ucnv_getStandardName(icuCanonicalName, "IANA", &status)) != NULL) {
-    return env->NewStringUTF(cName);
-  }
-
-  // Check to see if an alias already exists with "x-" prefix, if yes then
-  // make that the canonical name.
-  int32_t aliasCount = ucnv_countAliases(icuCanonicalName, &status);
-  for (int i = 0; i < aliasCount; ++i) {
-    const char* name = ucnv_getAlias(icuCanonicalName, i, &status);
-    if (name != NULL && name[0] == 'x' && name[1] == '-') {
-      return env->NewStringUTF(name);
-    }
-  }
-
-  // As a last resort, prepend "x-" to any alias and make that the canonical name.
-  status = U_ZERO_ERROR;
-  const char* name = ucnv_getStandardName(icuCanonicalName, "UTR22", &status);
-  if (name == NULL && strchr(icuCanonicalName, ',') != NULL) {
-    name = ucnv_getAlias(icuCanonicalName, 1, &status);
-  }
-  // If there is no UTR22 canonical name then just return the original name.
-  if (name == NULL) {
-    name = icuCanonicalName;
-  }
-  std::unique_ptr<char[]> result(new char[2 + strlen(name) + 1]);
-  strcpy(&result[0], "x-");
-  strcat(&result[0], name);
-  return env->NewStringUTF(&result[0]);
-}
-
-// Returns a canonical ICU converter name which may have a version number appended to it, based on
-// the normal canonical name. This is used to determine the actual native converter to use (the
-// normal unversioned name is used to determine the aliases and the Java name).
-static char const * getVersionedIcuCanonicalName(char const * icuCanonicalName) {
-  if (strcmp(icuCanonicalName, "UTF-16") == 0) {
-    // The ICU UTF-16 converter encodes strings as platform-endian bytes with a BOM. The
-    // UTF-16,version=2 one encodes as big-endian with a BOM, as what the Charset javadoc requires.
-    return "UTF-16,version=2";
-  } else {
-    return icuCanonicalName;
-  }
-}
-
-static jlong NativeConverter_openConverter(JNIEnv* env, jclass, jstring converterName) {
-    ScopedUtfChars converterNameChars(env, converterName);
-    if (converterNameChars.c_str() == NULL) {
-        // Extra debugging check that we do have an exception if the we could not
-        // create a string. See b/62612946.
-        if (env->ExceptionCheck()) {
-            return 0;
-        }
-        maybeThrowIcuException(env, "openConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return 0;
-    }
-    UErrorCode status = U_ZERO_ERROR;
-    UConverter* cnv = ucnv_open(converterNameChars.c_str(), &status);
-    maybeThrowIcuException(env, "ucnv_open", status);
-    if (env->ExceptionCheck()) {
-        return 0;
-    }
-    if (cnv == NULL) {
-        // Extra debugging exception in case cnv is null but ICU did not report
-        // an error. See b/62612946.
-        maybeThrowIcuException(env, "openConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return 0;
-    }
-    return reinterpret_cast<uintptr_t>(cnv);
-}
-
-static void NativeConverter_closeConverter(JNIEnv*, jclass, jlong address) {
-    ucnv_close(toUConverter(address));
-}
-
-static bool shouldCodecThrow(jboolean flush, UErrorCode error) {
-    if (flush) {
-        return (error != U_BUFFER_OVERFLOW_ERROR && error != U_TRUNCATED_CHAR_FOUND);
-    } else {
-        return (error != U_BUFFER_OVERFLOW_ERROR && error != U_INVALID_CHAR_FOUND && error != U_ILLEGAL_CHAR_FOUND);
-    }
-}
-
-static jint NativeConverter_encode(JNIEnv* env, jclass, jlong address,
-        jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd,
-        jintArray data, jboolean flush) {
-
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedCharArrayRO uSource(env, source);
-    if (uSource.get() == NULL) {
-        maybeThrowIcuException(env, "uSource", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedByteArrayRW uTarget(env, target);
-    if (uTarget.get() == NULL) {
-        maybeThrowIcuException(env, "uTarget", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedIntArrayRW myData(env, data);
-    if (myData.get() == NULL) {
-        maybeThrowIcuException(env, "myData", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    // Do the conversion.
-    jint* sourceOffset = &myData[0];
-    jint* targetOffset = &myData[1];
-    const jchar* mySource = uSource.get() + *sourceOffset;
-    const UChar* mySourceLimit= reinterpret_cast<const UChar*>(uSource.get()) + sourceEnd;
-    char* cTarget = reinterpret_cast<char*>(uTarget.get() + *targetOffset);
-    const char* cTargetLimit = reinterpret_cast<const char*>(uTarget.get() + targetEnd);
-    UErrorCode errorCode = U_ZERO_ERROR;
-    ucnv_fromUnicode(cnv, &cTarget, cTargetLimit, reinterpret_cast<const UChar**>(&mySource), mySourceLimit, NULL, (UBool) flush, &errorCode);
-    *sourceOffset = (mySource - uSource.get()) - *sourceOffset;
-    *targetOffset = (reinterpret_cast<jbyte*>(cTarget) - uTarget.get());
-
-    // If there was an error, count the problematic characters.
-    if (errorCode == U_ILLEGAL_CHAR_FOUND || errorCode == U_INVALID_CHAR_FOUND ||
-        errorCode == U_TRUNCATED_CHAR_FOUND) {
-        int8_t invalidUCharCount = 32;
-        UChar invalidUChars[32];
-        UErrorCode minorErrorCode = U_ZERO_ERROR;
-        ucnv_getInvalidUChars(cnv, invalidUChars, &invalidUCharCount, &minorErrorCode);
-        if (U_SUCCESS(minorErrorCode)) {
-            myData[2] = invalidUCharCount;
-        }
-    }
-
-    // Managed code handles some cases; throw all other errors.
-    if (shouldCodecThrow(flush, errorCode)) {
-        maybeThrowIcuException(env, "ucnv_fromUnicode", errorCode);
-    }
-    return errorCode;
-}
-
-static jint NativeConverter_decode(JNIEnv* env, jclass, jlong address,
-        jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd,
-        jintArray data, jboolean flush) {
-
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedByteArrayRO uSource(env, source);
-    if (uSource.get() == NULL) {
-        maybeThrowIcuException(env, "uSource", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedCharArrayRW uTarget(env, target);
-    if (uTarget.get() == NULL) {
-        maybeThrowIcuException(env, "uTarget", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-    ScopedIntArrayRW myData(env, data);
-    if (myData.get() == NULL) {
-        maybeThrowIcuException(env, "myData", U_ILLEGAL_ARGUMENT_ERROR);
-        return U_ILLEGAL_ARGUMENT_ERROR;
-    }
-
-    // Do the conversion.
-    jint* sourceOffset = &myData[0];
-    jint* targetOffset = &myData[1];
-    const char* mySource = reinterpret_cast<const char*>(uSource.get() + *sourceOffset);
-    const char* mySourceLimit = reinterpret_cast<const char*>(uSource.get() + sourceEnd);
-    UChar* cTarget = reinterpret_cast<UChar*>(uTarget.get()) + *targetOffset;
-    const UChar* cTargetLimit = reinterpret_cast<UChar*>(uTarget.get()) + targetEnd;
-    UErrorCode errorCode = U_ZERO_ERROR;
-    ucnv_toUnicode(cnv, &cTarget, cTargetLimit, &mySource, mySourceLimit, NULL, flush, &errorCode);
-    *sourceOffset = mySource - reinterpret_cast<const char*>(uSource.get()) - *sourceOffset;
-    *targetOffset = cTarget - reinterpret_cast<UChar*>(uTarget.get()) - *targetOffset;
-
-    // If there was an error, count the problematic bytes.
-    if (errorCode == U_ILLEGAL_CHAR_FOUND || errorCode == U_INVALID_CHAR_FOUND ||
-        errorCode == U_TRUNCATED_CHAR_FOUND) {
-        int8_t invalidByteCount = 32;
-        char invalidBytes[32] = {'\0'};
-        UErrorCode minorErrorCode = U_ZERO_ERROR;
-        ucnv_getInvalidChars(cnv, invalidBytes, &invalidByteCount, &minorErrorCode);
-        if (U_SUCCESS(minorErrorCode)) {
-            myData[2] = invalidByteCount;
-        }
-    }
-
-    // Managed code handles some cases; throw all other errors.
-    if (shouldCodecThrow(flush, errorCode)) {
-        maybeThrowIcuException(env, "ucnv_toUnicode", errorCode);
-    }
-    return errorCode;
-}
-
-static void NativeConverter_resetByteToChar(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv) {
-        ucnv_resetToUnicode(cnv);
-    }
-}
-
-static void NativeConverter_resetCharToByte(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv) {
-        ucnv_resetFromUnicode(cnv);
-    }
-}
-
-static jint NativeConverter_getMaxBytesPerChar(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    return (cnv != NULL) ? ucnv_getMaxCharSize(cnv) : -1;
-}
-
-static jint NativeConverter_getMinBytesPerChar(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    return (cnv != NULL) ? ucnv_getMinCharSize(cnv) : -1;
-}
-
-static jfloat NativeConverter_getAveBytesPerChar(JNIEnv*, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    return (cnv != NULL) ? ((ucnv_getMaxCharSize(cnv) + ucnv_getMinCharSize(cnv)) / 2.0) : -1;
-}
-
-static jobjectArray NativeConverter_getAvailableCharsetNames(JNIEnv* env, jclass) {
-    int32_t num = ucnv_countAvailable();
-    jobjectArray result = env->NewObjectArray(num, JniConstants::GetStringClass(env), NULL);
-    if (result == NULL) {
-        return NULL;
-    }
-    for (int i = 0; i < num; ++i) {
-        const char* name = ucnv_getAvailableName(i);
-        ScopedLocalRef<jstring> javaCanonicalName(env, getJavaCanonicalName(env, name));
-        if (javaCanonicalName.get() == NULL) {
-            return NULL;
-        }
-        env->SetObjectArrayElement(result, i, javaCanonicalName.get());
-        if (env->ExceptionCheck()) {
-            return NULL;
-        }
-    }
-    return result;
-}
-
-static void CHARSET_ENCODER_CALLBACK(const void* rawContext, UConverterFromUnicodeArgs* args,
-        const UChar* codeUnits, int32_t length, UChar32 codePoint, UConverterCallbackReason reason,
-        UErrorCode* status) {
-    if (!rawContext) {
-        return;
-    }
-    const EncoderCallbackContext* ctx = reinterpret_cast<const EncoderCallbackContext*>(rawContext);
-    switch(reason) {
-    case UCNV_UNASSIGNED:
-        ctx->onUnmappableInput(ctx, args, codeUnits, length, codePoint, reason, status);
-        return;
-    case UCNV_ILLEGAL:
-    case UCNV_IRREGULAR:
-        ctx->onMalformedInput(ctx, args, codeUnits, length, codePoint, reason, status);
-        return;
-    case UCNV_CLOSE:
-        delete ctx;
-        return;
-    default:
-        *status = U_ILLEGAL_ARGUMENT_ERROR;
-        return;
-    }
-}
-
-static void encoderReplaceCallback(const void* rawContext,
-        UConverterFromUnicodeArgs* fromArgs, const UChar*, int32_t, UChar32,
-        UConverterCallbackReason, UErrorCode * err) {
-    if (rawContext == NULL) {
-        return;
-    }
-    const EncoderCallbackContext* context = reinterpret_cast<const EncoderCallbackContext*>(rawContext);
-    *err = U_ZERO_ERROR;
-    ucnv_cbFromUWriteBytes(fromArgs, context->replacementBytes, context->replacementByteCount, 0, err);
-}
-
-static UConverterFromUCallback getFromUCallback(int32_t mode) {
-    switch(mode) {
-    case NativeConverter_IGNORE: return UCNV_FROM_U_CALLBACK_SKIP;
-    case NativeConverter_REPLACE: return encoderReplaceCallback;
-    case NativeConverter_REPORT: return UCNV_FROM_U_CALLBACK_STOP;
-    }
-    abort();
-}
-
-static void NativeConverter_setCallbackEncode(JNIEnv* env, jclass, jlong address,
-        jint onMalformedInput, jint onUnmappableInput, jbyteArray javaReplacement) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        maybeThrowIcuException(env, "toUConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return;
-    }
-
-    UConverterFromUCallback oldCallback = NULL;
-    const void* oldCallbackContext = NULL;
-    ucnv_getFromUCallBack(cnv, &oldCallback, const_cast<const void**>(&oldCallbackContext));
-
-    EncoderCallbackContext* callbackContext = const_cast<EncoderCallbackContext*>(
-            reinterpret_cast<const EncoderCallbackContext*>(oldCallbackContext));
-    // Hold the reference to any new callbackContext we create in a unique_ptr
-    // so that the default behavior is to collect it automatically if we exit
-    // early.
-    std::unique_ptr<EncoderCallbackContext> callbackContextDeleter;
-    if (callbackContext == NULL) {
-        callbackContext = new EncoderCallbackContext;
-        callbackContextDeleter.reset(callbackContext);
-    }
-
-    callbackContext->onMalformedInput = getFromUCallback(onMalformedInput);
-    callbackContext->onUnmappableInput = getFromUCallback(onUnmappableInput);
-
-    ScopedByteArrayRO replacementBytes(env, javaReplacement);
-    if (replacementBytes.get() == NULL
-            || replacementBytes.size() > sizeof(callbackContext->replacementBytes)) {
-        maybeThrowIcuException(env, "replacementBytes", U_ILLEGAL_ARGUMENT_ERROR);
-        return;
-    }
-    memcpy(callbackContext->replacementBytes, replacementBytes.get(), replacementBytes.size());
-    callbackContext->replacementByteCount = replacementBytes.size();
-
-    UErrorCode errorCode = U_ZERO_ERROR;
-    ucnv_setFromUCallBack(cnv, CHARSET_ENCODER_CALLBACK, callbackContext, NULL, NULL, &errorCode);
-    // Iff callbackContextDeleter holds a reference to a callbackContext we can
-    // prevent it being automatically deleted here as responsibility for deletion
-    // has passed to the code that closes the NativeConverter.
-    callbackContextDeleter.release();
-    maybeThrowIcuException(env, "ucnv_setFromUCallBack", errorCode);
-}
-
-static void decoderIgnoreCallback(const void*, UConverterToUnicodeArgs*, const char*, int32_t, UConverterCallbackReason, UErrorCode* err) {
-    // The icu4c UCNV_FROM_U_CALLBACK_SKIP callback requires that the context is NULL, which is
-    // never true for us.
-    *err = U_ZERO_ERROR;
-}
-
-static void decoderReplaceCallback(const void* rawContext,
-        UConverterToUnicodeArgs* toArgs, const char*, int32_t, UConverterCallbackReason,
-        UErrorCode* err) {
-    if (!rawContext) {
-        return;
-    }
-    const DecoderCallbackContext* context = reinterpret_cast<const DecoderCallbackContext*>(rawContext);
-    *err = U_ZERO_ERROR;
-    ucnv_cbToUWriteUChars(toArgs,context->replacementChars, context->replacementCharCount, 0, err);
-}
-
-static UConverterToUCallback getToUCallback(int32_t mode) {
-    switch (mode) {
-    case NativeConverter_IGNORE: return decoderIgnoreCallback;
-    case NativeConverter_REPLACE: return decoderReplaceCallback;
-    case NativeConverter_REPORT: return UCNV_TO_U_CALLBACK_STOP;
-    }
-    abort();
-}
-
-static void CHARSET_DECODER_CALLBACK(const void* rawContext, UConverterToUnicodeArgs* args,
-        const char* codeUnits, int32_t length,
-        UConverterCallbackReason reason, UErrorCode* status) {
-    if (!rawContext) {
-        return;
-    }
-    const DecoderCallbackContext* ctx = reinterpret_cast<const DecoderCallbackContext*>(rawContext);
-    switch(reason) {
-    case UCNV_UNASSIGNED:
-        ctx->onUnmappableInput(ctx, args, codeUnits, length, reason, status);
-        return;
-    case UCNV_ILLEGAL:
-    case UCNV_IRREGULAR:
-        ctx->onMalformedInput(ctx, args, codeUnits, length, reason, status);
-        return;
-    case UCNV_CLOSE:
-        delete ctx;
-        return;
-    default:
-        *status = U_ILLEGAL_ARGUMENT_ERROR;
-        return;
-    }
-}
-
-static void NativeConverter_setCallbackDecode(JNIEnv* env, jclass, jlong address,
-        jint onMalformedInput, jint onUnmappableInput, jstring javaReplacement) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        maybeThrowIcuException(env, "toConverter", U_ILLEGAL_ARGUMENT_ERROR);
-        return;
-    }
-
-    UConverterToUCallback oldCallback;
-    const void* oldCallbackContext;
-    ucnv_getToUCallBack(cnv, &oldCallback, &oldCallbackContext);
-
-    DecoderCallbackContext* callbackContext = const_cast<DecoderCallbackContext*>(
-            reinterpret_cast<const DecoderCallbackContext*>(oldCallbackContext));
-    // Hold the reference to any new callbackContext we create in a unique_ptr
-    // so that the default behavior is to collect it automatically if we exit
-    // early.
-    std::unique_ptr<DecoderCallbackContext> callbackContextDeleter;
-    if (callbackContext == NULL) {
-        callbackContext = new DecoderCallbackContext;
-        callbackContextDeleter.reset(callbackContext);
-    }
-
-    callbackContext->onMalformedInput = getToUCallback(onMalformedInput);
-    callbackContext->onUnmappableInput = getToUCallback(onUnmappableInput);
-
-    ScopedStringChars replacement(env, javaReplacement);
-    if (replacement.get() == NULL
-                || replacement.size() > sizeof(callbackContext->replacementChars) / sizeof(UChar)) {
-        maybeThrowIcuException(env, "replacement", U_ILLEGAL_ARGUMENT_ERROR);
-        return;
-    }
-    u_strncpy(callbackContext->replacementChars, reinterpret_cast<const UChar*>(replacement.get()), replacement.size());
-    callbackContext->replacementCharCount = replacement.size();
-
-    UErrorCode errorCode = U_ZERO_ERROR;
-    ucnv_setToUCallBack(cnv, CHARSET_DECODER_CALLBACK, callbackContext, NULL, NULL, &errorCode);
-    // Iff callbackContextDeleter holds a reference to a callbackContext we can
-    // prevent it being automatically deleted here as responsibility for deletion
-    // has passed to the code that closes the NativeConverter.
-    callbackContextDeleter.release();
-    maybeThrowIcuException(env, "ucnv_setToUCallBack", errorCode);
-}
-
-static jfloat NativeConverter_getAveCharsPerByte(JNIEnv* env, jclass, jlong handle) {
-    return (1 / (jfloat) NativeConverter_getMaxBytesPerChar(env, NULL, handle));
-}
-
-static jbyteArray NativeConverter_getSubstitutionBytes(JNIEnv* env, jclass, jlong address) {
-    UConverter* cnv = toUConverter(address);
-    if (cnv == NULL) {
-        return NULL;
-    }
-    UErrorCode status = U_ZERO_ERROR;
-    char replacementBytes[MAX_REPLACEMENT_LENGTH];
-    int8_t len = sizeof(replacementBytes);
-    ucnv_getSubstChars(cnv, replacementBytes, &len, &status);
-    if (!U_SUCCESS(status)) {
-        return env->NewByteArray(0);
-    }
-    jbyteArray result = env->NewByteArray(len);
-    if (result == NULL) {
-        return NULL;
-    }
-    env->SetByteArrayRegion(result, 0, len, reinterpret_cast<jbyte*>(replacementBytes));
-    return result;
-}
-
-static jboolean NativeConverter_contains(JNIEnv* env, jclass, jstring name1, jstring name2) {
-    ScopedUtfChars name1Chars(env, name1);
-    if (name1Chars.c_str() == NULL) {
-        return JNI_FALSE;
-    }
-    ScopedUtfChars name2Chars(env, name2);
-    if (name2Chars.c_str() == NULL) {
-        return JNI_FALSE;
-    }
-
-    UErrorCode errorCode = U_ZERO_ERROR;
-    icu::LocalUConverterPointer converter1(ucnv_open(name1Chars.c_str(), &errorCode));
-    icu::UnicodeSet set1;
-    ucnv_getUnicodeSet(&*converter1, set1.toUSet(), UCNV_ROUNDTRIP_SET, &errorCode);
-
-    icu::LocalUConverterPointer converter2(ucnv_open(name2Chars.c_str(), &errorCode));
-    icu::UnicodeSet set2;
-    ucnv_getUnicodeSet(&*converter2, set2.toUSet(), UCNV_ROUNDTRIP_SET, &errorCode);
-
-    return U_SUCCESS(errorCode) && set1.containsAll(set2);
-}
-
-static jobject NativeConverter_charsetForName(JNIEnv* env, jclass, jstring charsetName) {
-    ScopedUtfChars charsetNameChars(env, charsetName);
-    if (charsetNameChars.c_str() == NULL) {
-        return NULL;
-    }
-
-    // Get ICU's canonical name for this charset.
-    const char* icuCanonicalName = getICUCanonicalName(charsetNameChars.c_str());
-    if (icuCanonicalName == NULL) {
-        return NULL;
-    }
-
-    // Get Java's canonical name for this charset.
-    jstring javaCanonicalName = getJavaCanonicalName(env, icuCanonicalName);
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-    // Check that this charset is supported.
-    {
-        // ICU doesn't offer any "isSupported", so we just open and immediately close.
-        UErrorCode error = U_ZERO_ERROR;
-        icu::LocalUConverterPointer cnv(ucnv_open(icuCanonicalName, &error));
-        if (!U_SUCCESS(error)) {
-            return NULL;
-        }
-    }
-
-    // Get the aliases for this charset.
-    std::vector<std::string> aliases;
-    if (!collectStandardNames(env, icuCanonicalName, "IANA", aliases)) {
-        return NULL;
-    }
-    if (!collectStandardNames(env, icuCanonicalName, "MIME", aliases)) {
-        return NULL;
-    }
-    if (!collectStandardNames(env, icuCanonicalName, "JAVA", aliases)) {
-        return NULL;
-    }
-    if (!collectStandardNames(env, icuCanonicalName, "WINDOWS", aliases)) {
-        return NULL;
-    }
-    jobjectArray javaAliases = toStringArray(env, aliases);
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-    // Construct the CharsetICU object.
-    static jmethodID charsetConstructor = env->GetMethodID(JniConstants::GetCharsetICUClass(env), "<init>",
-            "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V");
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-    char const * versionedIcuCanonicalName = getVersionedIcuCanonicalName(icuCanonicalName);
-    jstring versionedIcuCanonicalNameStr = env->NewStringUTF(versionedIcuCanonicalName);
-    if (env->ExceptionCheck()) {
-        return NULL;
-    }
-
-    return env->NewObject(JniConstants::GetCharsetICUClass(env), charsetConstructor,
-            javaCanonicalName, versionedIcuCanonicalNameStr, javaAliases);
-}
-
-static void FreeNativeConverter(void *converter) {
-    ucnv_close(reinterpret_cast<UConverter*>(converter));
-}
-
-static jlong NativeConverter_getNativeFinalizer(JNIEnv*, jclass) {
-    return reinterpret_cast<jlong>(&FreeNativeConverter);
-}
-
-static jlong NativeConverter_getNativeSize(JNIEnv*, jclass) {
-    // TODO: Improve estimate.
-    return 200;
-}
-
-static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(NativeConverter, charsetForName, "(Ljava/lang/String;)Ljava/nio/charset/Charset;"),
-    NATIVE_METHOD(NativeConverter, closeConverter, "(J)V"),
-    NATIVE_METHOD(NativeConverter, contains, "(Ljava/lang/String;Ljava/lang/String;)Z"),
-    NATIVE_METHOD(NativeConverter, decode, "(J[BI[CI[IZ)I"),
-    NATIVE_METHOD(NativeConverter, encode, "(J[CI[BI[IZ)I"),
-    NATIVE_METHOD(NativeConverter, getAvailableCharsetNames, "()[Ljava/lang/String;"),
-    NATIVE_METHOD(NativeConverter, getAveBytesPerChar, "(J)F"),
-    NATIVE_METHOD(NativeConverter, getAveCharsPerByte, "(J)F"),
-    NATIVE_METHOD(NativeConverter, getMaxBytesPerChar, "(J)I"),
-    NATIVE_METHOD(NativeConverter, getMinBytesPerChar, "(J)I"),
-    NATIVE_METHOD(NativeConverter, getSubstitutionBytes, "(J)[B"),
-    NATIVE_METHOD(NativeConverter, openConverter, "(Ljava/lang/String;)J"),
-    NATIVE_METHOD(NativeConverter, resetByteToChar, "(J)V"),
-    NATIVE_METHOD(NativeConverter, resetCharToByte, "(J)V"),
-    NATIVE_METHOD(NativeConverter, setCallbackDecode, "(JIILjava/lang/String;)V"),
-    NATIVE_METHOD(NativeConverter, setCallbackEncode, "(JII[B)V"),
-    NATIVE_METHOD(NativeConverter, getNativeFinalizer, "()J"),
-    NATIVE_METHOD(NativeConverter, getNativeSize, "()J")
-};
-void register_libcore_icu_NativeConverter(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "libcore/icu/NativeConverter", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/libcore_io_Linux.cpp b/luni/src/main/native/libcore_io_Linux.cpp
index 6b8ee08..9e44e63 100644
--- a/luni/src/main/native/libcore_io_Linux.cpp
+++ b/luni/src/main/native/libcore_io_Linux.cpp
@@ -418,7 +418,7 @@
     } else if (ss.ss_family == AF_PACKET) {
         const struct sockaddr_ll* sll = reinterpret_cast<const struct sockaddr_ll*>(&ss);
         static jmethodID ctor = env->GetMethodID(JniConstants::GetPacketSocketAddressClass(env),
-                "<init>", "(SISB[B)V");
+                "<init>", "(IIII[B)V");
         if (ctor == NULL) {
             return NULL;
         }
@@ -429,10 +429,10 @@
         env->SetByteArrayRegion(byteArray.get(), 0, sll->sll_halen,
                 reinterpret_cast<const jbyte*>(sll->sll_addr));
         jobject packetSocketAddress = env->NewObject(JniConstants::GetPacketSocketAddressClass(env), ctor,
-                static_cast<jshort>(ntohs(sll->sll_protocol)),
+                static_cast<jint>(ntohs(sll->sll_protocol)),
                 static_cast<jint>(sll->sll_ifindex),
-                static_cast<jshort>(sll->sll_hatype),
-                static_cast<jbyte>(sll->sll_pkttype),
+                static_cast<jint>(sll->sll_hatype),
+                static_cast<jint>(sll->sll_pkttype),
                 byteArray.get());
         return packetSocketAddress;
     }
@@ -686,22 +686,22 @@
 static bool javaPacketSocketAddressToSockaddr(
         JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
     static jfieldID protocolFid = env->GetFieldID(
-            JniConstants::GetPacketSocketAddressClass(env), "sll_protocol", "S");
+            JniConstants::GetPacketSocketAddressClass(env), "sll_protocol", "I");
     static jfieldID ifindexFid = env->GetFieldID(
             JniConstants::GetPacketSocketAddressClass(env), "sll_ifindex", "I");
     static jfieldID hatypeFid = env->GetFieldID(
-            JniConstants::GetPacketSocketAddressClass(env), "sll_hatype", "S");
+            JniConstants::GetPacketSocketAddressClass(env), "sll_hatype", "I");
     static jfieldID pkttypeFid = env->GetFieldID(
-            JniConstants::GetPacketSocketAddressClass(env), "sll_pkttype", "B");
+            JniConstants::GetPacketSocketAddressClass(env), "sll_pkttype", "I");
     static jfieldID addrFid = env->GetFieldID(
             JniConstants::GetPacketSocketAddressClass(env), "sll_addr", "[B");
 
     sockaddr_ll *sll = reinterpret_cast<sockaddr_ll *>(&ss);
     sll->sll_family = AF_PACKET;
-    sll->sll_protocol = htons(env->GetShortField(javaSocketAddress, protocolFid));
+    sll->sll_protocol = htons(env->GetIntField(javaSocketAddress, protocolFid));
     sll->sll_ifindex = env->GetIntField(javaSocketAddress, ifindexFid);
-    sll->sll_hatype = env->GetShortField(javaSocketAddress, hatypeFid);
-    sll->sll_pkttype = env->GetByteField(javaSocketAddress, pkttypeFid);
+    sll->sll_hatype = env->GetIntField(javaSocketAddress, hatypeFid);
+    sll->sll_pkttype = env->GetIntField(javaSocketAddress, pkttypeFid);
 
     jbyteArray sllAddr = (jbyteArray) env->GetObjectField(javaSocketAddress, addrFid);
     if (sllAddr == NULL) {
@@ -1242,32 +1242,6 @@
     throwIfMinusOne(env, "fchown", TEMP_FAILURE_RETRY(fchown(fd, uid, gid)));
 }
 
-static jint Linux_fcntlFlock(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaFlock) {
-    static jfieldID typeFid = env->GetFieldID(JniConstants::GetStructFlockClass(env), "l_type", "S");
-    static jfieldID whenceFid = env->GetFieldID(JniConstants::GetStructFlockClass(env), "l_whence", "S");
-    static jfieldID startFid = env->GetFieldID(JniConstants::GetStructFlockClass(env), "l_start", "J");
-    static jfieldID lenFid = env->GetFieldID(JniConstants::GetStructFlockClass(env), "l_len", "J");
-    static jfieldID pidFid = env->GetFieldID(JniConstants::GetStructFlockClass(env), "l_pid", "I");
-
-    struct flock64 lock;
-    memset(&lock, 0, sizeof(lock));
-    lock.l_type = env->GetShortField(javaFlock, typeFid);
-    lock.l_whence = env->GetShortField(javaFlock, whenceFid);
-    lock.l_start = env->GetLongField(javaFlock, startFid);
-    lock.l_len = env->GetLongField(javaFlock, lenFid);
-    lock.l_pid = env->GetIntField(javaFlock, pidFid);
-
-    int rc = IO_FAILURE_RETRY(env, int, fcntl, javaFd, cmd, &lock);
-    if (rc != -1) {
-        env->SetShortField(javaFlock, typeFid, lock.l_type);
-        env->SetShortField(javaFlock, whenceFid, lock.l_whence);
-        env->SetLongField(javaFlock, startFid, lock.l_start);
-        env->SetLongField(javaFlock, lenFid, lock.l_len);
-        env->SetIntField(javaFlock, pidFid, lock.l_pid);
-    }
-    return rc;
-}
-
 static jint Linux_fcntlInt(JNIEnv* env, jobject, jobject javaFd, jint cmd, jint arg) {
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
     return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd, arg)));
@@ -1863,6 +1837,21 @@
     return doStat(env, javaPath, true);
 }
 
+static jobject Linux_memfd_create(JNIEnv* env, jobject, jstring javaName, jint flags) {
+#if defined(__BIONIC__)
+    ScopedUtfChars name(env, javaName);
+    if (name.c_str() == NULL) {
+        return NULL;
+    }
+
+    int fd = throwIfMinusOne(env, "memfd_create", memfd_create(name.c_str(), flags));
+    return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
+#else
+    UNUSED(env, javaName, flags);
+    return NULL;
+#endif
+}
+
 static void Linux_mincore(JNIEnv* env, jobject, jlong address, jlong byteCount, jbyteArray javaVector) {
     ScopedByteArrayRW vector(env, javaVector);
     if (vector.get() == NULL) {
@@ -2603,7 +2592,6 @@
     NATIVE_METHOD(Linux, execve, "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V"),
     NATIVE_METHOD(Linux, fchmod, "(Ljava/io/FileDescriptor;I)V"),
     NATIVE_METHOD(Linux, fchown, "(Ljava/io/FileDescriptor;II)V"),
-    NATIVE_METHOD(Linux, fcntlFlock, "(Ljava/io/FileDescriptor;ILandroid/system/StructFlock;)I"),
     NATIVE_METHOD(Linux, fcntlInt, "(Ljava/io/FileDescriptor;II)I"),
     NATIVE_METHOD(Linux, fcntlVoid, "(Ljava/io/FileDescriptor;I)I"),
     NATIVE_METHOD(Linux, fdatasync, "(Ljava/io/FileDescriptor;)V"),
@@ -2650,6 +2638,7 @@
     NATIVE_METHOD(Linux, listxattr, "(Ljava/lang/String;)[Ljava/lang/String;"),
     NATIVE_METHOD(Linux, lseek, "(Ljava/io/FileDescriptor;JI)J"),
     NATIVE_METHOD(Linux, lstat, "(Ljava/lang/String;)Landroid/system/StructStat;"),
+    NATIVE_METHOD(Linux, memfd_create, "(Ljava/lang/String;I)Ljava/io/FileDescriptor;"),
     NATIVE_METHOD(Linux, mincore, "(JJ[B)V"),
     NATIVE_METHOD(Linux, mkdir, "(Ljava/lang/String;I)V"),
     NATIVE_METHOD(Linux, mkfifo, "(Ljava/lang/String;I)V"),
diff --git a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
index 9d23837..6df5bdd 100644
--- a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
+++ b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
@@ -33,7 +33,8 @@
 
 #include "JniConstants.h"
 #include "JniException.h"
-#include "unicode/unistr.h"
+#include "unicode/char16ptr.h"
+#include "unicode/ustring.h"
 
 #define BUCKET_COUNT 128
 
@@ -428,11 +429,11 @@
  *
  * @returns number of UTF-16 characters which were copied
  */
-static size_t fillBuffer(ParsingContext* parsingContext, const char* utf8, int byteCount) {
+static size_t fillBuffer(ParsingContext* parsingContext, const char* utf8, int byteLength) {
     JNIEnv* env = parsingContext->env;
 
     // Grow buffer if necessary (the length in bytes is always >= the length in chars).
-    jcharArray javaChars = parsingContext->ensureCapacity(byteCount);
+    jcharArray javaChars = parsingContext->ensureCapacity(byteLength);
     if (javaChars == NULL) {
         return -1;
     }
@@ -443,8 +444,19 @@
         return -1;
     }
     UErrorCode status = U_ZERO_ERROR;
-    icu::UnicodeString utf16(icu::UnicodeString::fromUTF8(icu::StringPiece(utf8, byteCount)));
-    return utf16.extract(chars.get(), byteCount, status);
+    int32_t length16;
+    // Use inline C++ class provided by ICU
+    icu::Char16Ptr dest(chars.get()); // Convert jchar (aka uint16_t*) to char16_t*
+    // Avoid icu::UnicodeString due to unstable C++ ABI.
+    u_strFromUTF8WithSub(dest.get(), // dest
+      byteLength, // destCapacity
+      &length16, // pDestLength
+      utf8, // src
+      byteLength, // srcLength
+      0xfffd,  // 0xfffd is the standard substitution character for malformed input sequence.
+      NULL,    // Don't care about number of substitutions.
+      &status);
+    return length16;
 }
 
 /**
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/annotations/Android.bp b/luni/src/test/annotations/Android.bp
new file mode 100644
index 0000000..437d7c4
--- /dev/null
+++ b/luni/src/test/annotations/Android.bp
@@ -0,0 +1,29 @@
+// 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.
+
+// Build this separately with the --intermediate flag to preserve class
+// retention annotations which are otherwise removed by the dexer.
+//
+// Included as a resource by //libcore:core-tests and loaded into its own
+// class loader by libcore.java.lang.reflect.annotations.RetentionPolicyTest.
+java_library {
+    name: "annotations-test",
+    visibility: [
+        "//libcore",
+    ],
+    compile_dex: true,
+    srcs: ["src/**/*.java"],
+    sdk_version: "core_platform",
+    dxflags: ["--intermediate"],
+}
diff --git a/luni/src/test/annotations/src/libcore/tests/annotations/ClassRetentionAnnotation.java b/luni/src/test/annotations/src/libcore/tests/annotations/ClassRetentionAnnotation.java
new file mode 100644
index 0000000..061590f
--- /dev/null
+++ b/luni/src/test/annotations/src/libcore/tests/annotations/ClassRetentionAnnotation.java
@@ -0,0 +1,23 @@
+/*
+ * 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 libcore.tests.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.CLASS)
+public @interface ClassRetentionAnnotation {
+}
diff --git a/luni/src/test/annotations/src/libcore/tests/annotations/RetentionAnnotations.java b/luni/src/test/annotations/src/libcore/tests/annotations/RetentionAnnotations.java
new file mode 100644
index 0000000..dd2d858
--- /dev/null
+++ b/luni/src/test/annotations/src/libcore/tests/annotations/RetentionAnnotations.java
@@ -0,0 +1,26 @@
+/*
+ * 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 libcore.tests.annotations;
+
+/**
+ * A class that exists so it can be annotated with annotations of different retention
+ * types.
+ */
+@ClassRetentionAnnotation
+@RuntimeRetentionAnnotation
+@SourceRetentionAnnotation
+public class RetentionAnnotations {
+}
diff --git a/luni/src/test/annotations/src/libcore/tests/annotations/RuntimeRetentionAnnotation.java b/luni/src/test/annotations/src/libcore/tests/annotations/RuntimeRetentionAnnotation.java
new file mode 100644
index 0000000..8030c10
--- /dev/null
+++ b/luni/src/test/annotations/src/libcore/tests/annotations/RuntimeRetentionAnnotation.java
@@ -0,0 +1,23 @@
+/*
+ * 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 libcore.tests.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RuntimeRetentionAnnotation {
+}
diff --git a/luni/src/test/annotations/src/libcore/tests/annotations/SourceRetentionAnnotation.java b/luni/src/test/annotations/src/libcore/tests/annotations/SourceRetentionAnnotation.java
new file mode 100644
index 0000000..901ad5a
--- /dev/null
+++ b/luni/src/test/annotations/src/libcore/tests/annotations/SourceRetentionAnnotation.java
@@ -0,0 +1,23 @@
+/*
+ * 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 libcore.tests.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.SOURCE)
+public @interface SourceRetentionAnnotation {
+}
diff --git a/luni/src/test/filesystems/Android.bp b/luni/src/test/filesystems/Android.bp
new file mode 100644
index 0000000..83cb936
--- /dev/null
+++ b/luni/src/test/filesystems/Android.bp
@@ -0,0 +1,31 @@
+// 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.
+
+// Contains classes for testing loading FileSystemProvider from a custom ClassLoader.
+//
+// Included as a resource by //libcore:core-tests and loaded into its own
+// class loader by libcore.java.nio.file.FileSystemsTest.
+java_library {
+    name: "filesystemstest",
+    visibility: [
+        "//libcore",
+    ],
+    compile_dex: true,
+    srcs: ["src/**/*.java"],
+    java_resource_dirs: ["resources"],
+    sdk_version: "core_platform",
+    errorprone: {
+        javacflags: ["-Xep:MissingOverride:OFF"],
+    },
+}
diff --git a/luni/src/test/java/libcore/android/system/OsTest.java b/luni/src/test/java/libcore/android/system/OsTest.java
index 7536885..35019db 100644
--- a/luni/src/test/java/libcore/android/system/OsTest.java
+++ b/luni/src/test/java/libcore/android/system/OsTest.java
@@ -56,6 +56,7 @@
 import junit.framework.TestCase;
 
 import libcore.io.IoUtils;
+import libcore.testing.io.TestIoUtils;
 
 import static android.system.OsConstants.*;
 
@@ -81,11 +82,50 @@
             int flags = Os.fcntlVoid(fis.getFD(), F_GETFD);
             assertTrue((flags & FD_CLOEXEC) != 0);
         } finally {
-            IoUtils.closeQuietly(fis);
+            TestIoUtils.closeQuietly(fis);
             f.delete();
         }
     }
 
+    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();
@@ -537,10 +577,14 @@
 
     public void test_NetlinkSocket() throws Exception {
         FileDescriptor nlSocket = Os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
-        Os.bind(nlSocket, new NetlinkSocketAddress());
-        NetlinkSocketAddress address = (NetlinkSocketAddress) Os.getsockname(nlSocket);
-        assertTrue(address.getPortId() > 0);
-        assertEquals(0, address.getGroupsMask());
+        try {
+            Os.bind(nlSocket, new NetlinkSocketAddress());
+            // Non-system processes should not be allowed to bind() to NETLINK_ROUTE sockets.
+            // http://b/141455849
+            fail("bind() on NETLINK_ROUTE socket succeeded");
+        } catch (ErrnoException expectedException) {
+            assertEquals(expectedException.errno, EACCES);
+        }
 
         NetlinkSocketAddress nlKernel = new NetlinkSocketAddress();
         Os.connect(nlSocket, nlKernel);
@@ -550,14 +594,18 @@
         Os.close(nlSocket);
     }
 
+    // This test is excluded from CTS via the knownfailures.txt because it requires extra
+    // permissions not available in CTS. To run it you have to use an -eng build and use a tool like
+    // vogar that runs the Android runtime as a privileged user.
     public void test_PacketSocketAddress() throws Exception {
         NetworkInterface lo = NetworkInterface.getByName("lo");
         FileDescriptor fd = Os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6);
-        PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, lo.getIndex());
+        PacketSocketAddress addr =
+                new PacketSocketAddress(ETH_P_IPV6, lo.getIndex(), null /* sll_addr */);
         Os.bind(fd, addr);
 
         PacketSocketAddress bound = (PacketSocketAddress) Os.getsockname(fd);
-        assertEquals((short) ETH_P_IPV6, bound.sll_protocol);  // ETH_P_IPV6 is an int.
+        assertEquals(ETH_P_IPV6, bound.sll_protocol);
         assertEquals(lo.getIndex(), bound.sll_ifindex);
         assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype);
         assertEquals(0, bound.sll_pkttype);
@@ -568,6 +616,57 @@
         for (int i = 0; i < 6; i++) {
             assertEquals(0, bound.sll_addr[i]);
         }
+
+        // The following checks that the packet socket address was constructed correctly in a form
+        // that the kernel understands. If the address is correct, the bind should result in a
+        // socket that is listening only for IPv6 packets, and only on loopback.
+
+        // Send an IPv4 packet on loopback.
+        // We send ourselves an IPv4 packet first. If we don't receive it, that (with high
+        // probability) ensures that the packet socket does not see IPv4 packets.
+        try (DatagramSocket s = new DatagramSocket()) {
+            byte[] packet = new byte[64];
+            s.send(new DatagramPacket(packet, 0, packet.length, Inet4Address.LOOPBACK,
+                    53 /* arbitrary port */));
+        }
+
+        // Send an IPv6 packet on loopback.
+        // Sending ourselves an IPv6 packet should cause the socket to receive a packet.
+        // The idea is that if the code gets sll_protocol wrong, then the packet socket will receive
+        // no packets and the test will fail.
+        try (DatagramSocket s = new DatagramSocket()) {
+            byte[] packet = new byte[64];
+            s.send(new DatagramPacket(packet, 0, packet.length, Inet6Address.LOOPBACK,
+                    53 /* arbitrary port */));
+        }
+
+        // Check that the socket associated with fd has received an IPv6 packet, not necessarily the
+        // UDP one we sent above. IPv6 packets always begin with the nibble 6. If we get anything
+        // else it means we're catching non-IPv6 or non-loopback packets unexpectedly. Since the
+        // socket is not discriminating it may catch packets unrelated to this test from things
+        // happening on the device at the same time, so we can't assert too much about the received
+        // packet, i.e. no length / content check.
+        {
+            byte[] receivedPacket = new byte[4096];
+            Os.read(fd, receivedPacket, 0, receivedPacket.length);
+            assertEquals(6, (receivedPacket[0] & 0xf0) >> 4);
+
+            byte[] sourceAddress = getIPv6AddressBytesAtOffset(receivedPacket, 8);
+            assertArrayEquals(Inet6Address.LOOPBACK.getAddress(), sourceAddress);
+
+            byte[] destAddress = getIPv6AddressBytesAtOffset(receivedPacket, 24);
+            assertArrayEquals(Inet6Address.LOOPBACK.getAddress(), destAddress);
+        }
+
+        Os.close(fd);
+    }
+
+    private static byte[] getIPv6AddressBytesAtOffset(byte[] packet, int offsetIndex) {
+        byte[] address = new byte[16];
+        for (int i = 0; i < 16; i++) {
+            address[i] = packet[i + offsetIndex];
+        }
+        return address;
     }
 
     public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception {
@@ -885,7 +984,7 @@
 
         // ENOTSUP, Extended attributes are not supported by the filesystem, or are disabled.
         // Since kernel version 4.9 (or some other version after 4.4), *xattr() methods
-        // may set errno to EACCESS instead. This behavior change is likely related to
+        // may set errno to EACCES instead. This behavior change is likely related to
         // https://patchwork.kernel.org/patch/9294421/ which reimplemented getxattr, setxattr,
         // and removexattr on top of generic handlers.
         final String path = "/proc/self/stat";
@@ -1133,7 +1232,7 @@
     }
 
     public void test_readlink() throws Exception {
-        File path = new File(IoUtils.createTemporaryDirectory("test_readlink"), "symlink");
+        File path = new File(TestIoUtils.createTemporaryDirectory("test_readlink"), "symlink");
 
         // ext2 and ext4 have PAGE_SIZE limits on symlink targets.
         // If file encryption is enabled, there's extra overhead to store the
@@ -1251,7 +1350,7 @@
                 android.system.Os.sendfile(outFd, inFd, offset, maxBytes);
                 assertEquals(expectedEndOffset, offset == null ? null : offset.value);
             }
-            return IoUtils.readFileAsString(out.getPath());
+            return TestIoUtils.readFileAsString(out.getPath());
         } finally {
             out.delete();
         }
@@ -1307,7 +1406,7 @@
             assertEquals(5, offOut.value);
         }
 
-        assertEquals("oobar", IoUtils.readFileAsString(out.getPath()));
+        assertEquals("oobar", TestIoUtils.readFileAsString(out.getPath()));
 
         Os.close(pipe[0]);
         Os.close(pipe[1]);
@@ -1414,4 +1513,83 @@
         InetAddress inetAddress = Os.inet_pton(AF_INET, srcAddress);
         assertNull(inetAddress);
     }
+
+    /**
+     * Verifies the {@link OsConstants#MAP_ANONYMOUS}.
+     */
+    public void testMapAnonymous() throws Exception {
+        final long size = 4096;
+        final long address = Os.mmap(0, size, PROT_READ,
+                MAP_PRIVATE | MAP_ANONYMOUS, new FileDescriptor(), 0);
+        assertTrue(address > 0);
+        Os.munmap(address, size);
+    }
+
+    public void testMemfdCreate() throws Exception {
+        FileDescriptor fd = null;
+        try {
+            fd = Os.memfd_create("test_memfd", 0);
+            assertNotNull(fd);
+            assertTrue(fd.valid());
+
+            StructStat stat = Os.fstat(fd);
+            assertEquals(0, stat.st_size);
+
+            final byte[] expected = new byte[] {1, 2, 3, 4};
+            Os.write(fd, expected, 0, expected.length);
+            stat = Os.fstat(fd);
+            assertEquals(expected.length, stat.st_size);
+
+            byte[] actual = new byte[expected.length];
+            // should be seekable
+            Os.lseek(fd, 0, SEEK_SET);
+            Os.read(fd, actual, 0, actual.length);
+            assertArrayEquals(expected, actual);
+        } finally {
+            if (fd != null) {
+                Os.close(fd);
+                fd = null;
+            }
+        }
+    }
+
+    public void testMemfdCreateFlags() throws Exception {
+        FileDescriptor fd = null;
+
+        // test that MFD_CLOEXEC is obeyed
+        try {
+            fd = Os.memfd_create("test_memfd", 0);
+            assertNotNull(fd);
+            assertTrue(fd.valid());
+            int flags = Os.fcntlVoid(fd, F_GETFD);
+            assertTrue("Expected flags to not include " + FD_CLOEXEC + ", actual value: " + flags,
+                    0 == (flags & FD_CLOEXEC));
+        } finally {
+            if (fd != null) {
+                Os.close(fd);
+                fd = null;
+            }
+        }
+        try {
+            fd = Os.memfd_create("test_memfd", MFD_CLOEXEC);
+            assertNotNull(fd);
+            assertTrue(fd.valid());
+            int flags = Os.fcntlVoid(fd, F_GETFD);
+            assertTrue("Expected flags to include " + FD_CLOEXEC + ", actual value: " + flags,
+                    0 != (flags & FD_CLOEXEC));
+        } finally {
+            if (fd != null) {
+                Os.close(fd);
+                fd = null;
+            }
+        }
+    }
+
+    public void testMemfdCreateErrno() throws Exception {
+        expectException(() -> Os.memfd_create(null, 0), NullPointerException.class, null,
+                "memfd_create(null, 0)");
+
+        expectException(() -> Os.memfd_create("test_memfd", 0xffff), ErrnoException.class, EINVAL,
+                "memfd_create(\"test_memfd\", 0xffff)");
+    }
 }
diff --git a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
index 84f7f71..7d3b6f2 100644
--- a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
@@ -20,10 +20,12 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import dalvik.system.BaseDexClassLoader;
 import dalvik.system.DelegateLastClassLoader;
 import dalvik.system.PathClassLoader;
+import java.lang.reflect.Method;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
@@ -32,6 +34,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -46,23 +49,21 @@
 @RunWith(JUnit4.class)
 public final class BaseDexClassLoaderTest {
     private static class Reporter implements BaseDexClassLoader.Reporter {
-        public final List<ClassLoader> classLoaders = new ArrayList<>();
-        public final List<String> loadedDexPaths = new ArrayList<>();
+        public final Map<String, String> loadedDexMapping = new HashMap<String, String>();
 
         @Override
-        public void report(List<ClassLoader> loaders, List<String> dexPaths) {
-            classLoaders.addAll(loaders);
-            loadedDexPaths.addAll(dexPaths);
+        public void report(Map<String, String> contextMap) {
+            loadedDexMapping.putAll(contextMap);
         }
 
         void reset() {
-            classLoaders.clear();
-            loadedDexPaths.clear();
+            loadedDexMapping.clear();
         }
     }
 
     private ClassLoader pcl;
     private File jar;
+    private File jar2;
     private Reporter reporter;
 
     // For resources that we will load in this test. We're re-using parent.jar and child.jar
@@ -81,7 +82,7 @@
     }
 
     @Before
-    public void extractTestJar() throws Exception {
+    public void extractTestJars() throws Exception {
         // Extract loading-test.jar from the resource.
         pcl = BaseDexClassLoaderTest.class.getClassLoader();
         jar = File.createTempFile("loading-test", ".jar");
@@ -89,6 +90,11 @@
              FileOutputStream out = new FileOutputStream(jar)) {
           Streams.copy(in, out);
         }
+        jar2 = File.createTempFile("loading-test2", ".jar");
+        try (InputStream in = pcl.getResourceAsStream("dalvik/system/loading-test2.jar");
+             FileOutputStream out = new FileOutputStream(jar2)) {
+          Streams.copy(in, out);
+        }
     }
 
     @Before
@@ -103,8 +109,9 @@
     }
 
     @After
-    public void deleteTestJar() throws Exception {
+    public void deleteTestJars() throws Exception {
         assertTrue(jar.delete());
+        assertTrue(jar2.delete());
     }
 
     @Test
@@ -113,17 +120,15 @@
         BaseDexClassLoader cl1 = new PathClassLoader(jar.getPath(),
             ClassLoader.getSystemClassLoader());
 
-        // Verify the reported data.
-        assertEquals(2, reporter.loadedDexPaths.size());
-        assertEquals(2, reporter.classLoaders.size());
+        assertEquals(1, reporter.loadedDexMapping.size());
 
-        // First class loader should be the one loading the files
-        assertEquals(jar.getPath(), reporter.loadedDexPaths.get(0));
-        assertEquals(cl1, reporter.classLoaders.get(0));
-
-        // Second class loader should be the system class loader.
-        // Don't check the actual classpath as that might vary based on system properties.
-        assertEquals(ClassLoader.getSystemClassLoader(), reporter.classLoaders.get(1));
+        String[] contexts = reporter.loadedDexMapping.get(jar.getPath()).split(";");
+        assertEquals(2, contexts.length);
+        // Verify the context for the loaded dex files.
+        assertEquals("PCL[]", contexts[0]);
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
     }
 
     @Test
@@ -132,16 +137,10 @@
         ClassLoader unknownLoader = new ClassLoader(ClassLoader.getSystemClassLoader()) {};
         BaseDexClassLoader cl1 = new PathClassLoader(jar.getPath(), unknownLoader);
 
-        assertEquals(3, reporter.loadedDexPaths.size());
-        assertEquals(3, reporter.classLoaders.size());
-
-        assertEquals(jar.getPath(), reporter.loadedDexPaths.get(0));
-        assertEquals(cl1, reporter.classLoaders.get(0));
-
-        assertNull(reporter.loadedDexPaths.get(1));
-        assertEquals(unknownLoader, reporter.classLoaders.get(1));
-
-        assertEquals(ClassLoader.getSystemClassLoader(), reporter.classLoaders.get(2));
+        // Verify the dex path gets reported, but with no class loader context due to the foreign
+        // class loader.
+        assertEquals(Map.of(jar.getPath(), "=UnsupportedClassLoaderContext="),
+                reporter.loadedDexMapping);
     }
 
     @Test
@@ -149,8 +148,15 @@
         BaseDexClassLoader cl1 = new PathClassLoader(jar.getPath(),
             ClassLoader.getSystemClassLoader());
 
-        assertEquals(2, reporter.loadedDexPaths.size());
-        assertEquals(2, reporter.classLoaders.size());
+        assertEquals(1, reporter.loadedDexMapping.size());
+
+        String[] contexts = reporter.loadedDexMapping.get(jar.getPath()).split(";");
+        assertEquals(2, contexts.length);
+        // Verify the context for the loaded dex files.
+        assertEquals("PCL[]", contexts[0]);
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
 
         // Check we don't report after the reporter is unregistered.
         unregisterReporter();
@@ -160,8 +166,120 @@
         BaseDexClassLoader cl2 = new PathClassLoader(jar.getPath(), pcl);
 
         // Verify nothing reported
-        assertEquals(0, reporter.loadedDexPaths.size());
-        assertEquals(0, reporter.classLoaders.size());
+        assertEquals(Map.<String, String>of(), reporter.loadedDexMapping);
+    }
+
+    @Test
+    public void testReporting_multipleJars() throws Exception {
+        // Load the jar file using a PathClassLoader.
+        BaseDexClassLoader cl1 = new PathClassLoader(
+            String.join(File.pathSeparator, jar.getPath(), jar2.getPath()),
+            ClassLoader.getSystemClassLoader());
+
+        assertEquals(2, reporter.loadedDexMapping.size());
+        // Verify the first jar.
+        String[] contexts = reporter.loadedDexMapping.get(jar.getPath()).split(";");
+        assertEquals(2, contexts.length);
+        // Verify the context for the loaded dex files.
+        assertEquals("PCL[]", contexts[0]);
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
+
+        // Verify the second jar.
+        String[] contexts2 = reporter.loadedDexMapping.get(jar2.getPath()).split(";");
+        assertEquals(2, contexts2.length);
+        // Verify the context for the loaded dex files.
+        assertEquals("PCL[" + jar.getPath() + "]", contexts2[0]);
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts2[1].startsWith("PCL["));
+    }
+
+
+    /**
+      * Separates the system class loader context from the rest of the context.
+      * Returns an array of 2 elements, where index 0 is the application class loader context
+      * without the system class loader and index 0 is the system class loader context.
+      */
+    private String[] separateSystemClassLoaderContext(String context) {
+        int clcSeparatorIndex = context.lastIndexOf(";");
+        String jarContext = context.substring(0, clcSeparatorIndex);
+        String systemClassLoaderContext = context.substring(clcSeparatorIndex + 1);
+        return new String[] {jarContext, systemClassLoaderContext};
+    }
+
+    @Test
+    public void testReporting_withSharedLibraries() throws Exception {
+        final ClassLoader parent = ClassLoader.getSystemClassLoader();
+        final ClassLoader sharedLoaders[] = new ClassLoader[] {
+            new PathClassLoader(jar2.getPath(), /* librarySearchPath */ null, parent),
+        };
+        // Reset so we don't get load reports from creating the shared library CL
+        reporter.reset();
+
+        BaseDexClassLoader bdcl = new PathClassLoader(jar.getPath(), null, parent, sharedLoaders);
+
+        assertEquals(1, reporter.loadedDexMapping.size());
+
+        String[] contexts = separateSystemClassLoaderContext(
+            reporter.loadedDexMapping.get(jar.getPath()));
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
+        // Verify the context for the loaded dex files. The system class loader should be part
+        // of the shared library class loader.
+        assertEquals("PCL[]{PCL[" + jar2.getPath() + "];" + contexts[1] + "}",
+                     contexts[0]);
+    }
+
+    @Test
+    public void testReporting_multipleJars_withSharedLibraries() throws Exception {
+        final ClassLoader parent = ClassLoader.getSystemClassLoader();
+        final String sharedJarPath = resourcesMap.get("parent.jar").getAbsolutePath();
+        final ClassLoader sharedLoaders[] = new ClassLoader[] {
+            new PathClassLoader(sharedJarPath, /* librarySearchPath */ null, parent),
+        };
+        // Reset so we don't get load reports from creating the shared library CL
+        reporter.reset();
+
+        BaseDexClassLoader bdcl = new PathClassLoader(
+                String.join(File.pathSeparator, jar.getPath(), jar2.getPath()),
+                null, parent, sharedLoaders);
+
+        assertEquals(2, reporter.loadedDexMapping.size());
+
+
+        // Verify the first jar.
+        String[] contexts = separateSystemClassLoaderContext(
+            reporter.loadedDexMapping.get(jar.getPath()));
+        String contextSuffix = "{PCL[" + sharedJarPath + "];" + contexts[1] + "}";
+
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
+        // Verify the context for the loaded dex files.
+        assertEquals("PCL[]" + contextSuffix, contexts[0]);
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts[1].startsWith("PCL["));
+
+        // Verify the second jar.
+        String[] contexts2 = separateSystemClassLoaderContext(
+            reporter.loadedDexMapping.get(jar2.getPath()));
+        String contextSuffix2 = "{PCL[" + sharedJarPath + "];" + contexts2[1] + "}";
+
+        // Verify the context for the loaded dex files.
+        assertEquals("PCL[" + jar.getPath() + "]" + contextSuffix2, contexts2[0]);
+        // We cannot fully verify the context of the system class loader because its classpath
+        // may vary based on system properties and whether or not we are in a test environment.
+        assertTrue(contexts2[1].startsWith("PCL[")) ;
+    }
+
+    @Test
+    public void testReporting_emptyPath() throws Exception {
+        BaseDexClassLoader cl1 = new PathClassLoader("", ClassLoader.getSystemClassLoader());
+        assertEquals(Map.<String, String>of(), reporter.loadedDexMapping);
     }
 
     /* package */ static List<String> readResources(ClassLoader cl, String resourceName)
@@ -337,4 +455,30 @@
         assertEquals("child", readResource(delegateLast, "resource.txt"));
 
     }
+
+    @Test
+    public void testAddDexPath() throws Exception {
+        BaseDexClassLoader bdcl = new PathClassLoader(jar.getPath(),
+            ClassLoader.getSystemClassLoader());
+
+        Class test1Class = bdcl.loadClass("test.Test1");
+        Method testMethod = test1Class.getMethod("test", (Class[]) null);
+        String testResult = (String) testMethod.invoke(null, (Object[]) null);
+        assertEquals("blort", testResult);
+
+        // Just for completeness sake, prove that we were able to load
+        // the class only after addDexPath was called.
+        try {
+          bdcl.loadClass("test2.Target2");
+          fail();
+        } catch (ClassNotFoundException expected) {
+        }
+
+        bdcl.addDexPath(jar2.getPath());
+
+        Class target2Class = bdcl.loadClass("test2.Target2");
+        Method frotzMethod = target2Class.getMethod("frotz", (Class[]) null);
+        String frotzResult = (String) frotzMethod.invoke(null, (Object[]) null);
+        assertEquals("frotz", frotzResult);
+    }
 }
diff --git a/luni/src/test/java/libcore/dalvik/system/DexClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/DexClassLoaderTest.java
index efc9c29..0294f26 100644
--- a/luni/src/test/java/libcore/dalvik/system/DexClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/DexClassLoaderTest.java
@@ -348,6 +348,16 @@
      * Tests native modification behaviors
      */
 
+    private boolean isLibraryFound(DexClassLoader loader, String libName) {
+        String ret = loader.findLibrary(libName);
+        if (ret != null && ret.startsWith("/")) {
+            return true;
+        }
+        // This case includes findLibrary returning null or a mapped libname
+        // e.g. "libfake.so" when libName was "fake".
+        return false;
+    }
+
     /**
      * Checks that a adding a native library to an existing class loader makes it visible for
      * subsequent calls.
@@ -357,12 +367,12 @@
         String path = nativeLib1.getParentFile().getAbsolutePath();
         DexClassLoader classLoader = (DexClassLoader) createLoader(dex1);
 
-        assertNull("findLibrary should not find un-added path",
-                classLoader.findLibrary("fake"));
+        assertFalse("findLibrary should not find un-added path",
+                isLibraryFound(classLoader, "fake"));
 
         classLoader.addNativePath(Collections.singletonList(path));
 
-        assertNotNull("findLibrary should find newly added path",
-                classLoader.findLibrary("fake"));
+        assertTrue("findLibrary should find newly added path",
+                isLibraryFound(classLoader, "fake"));
     }
 }
diff --git a/luni/src/test/java/libcore/dalvik/system/EmulatedStackFrameTest.java b/luni/src/test/java/libcore/dalvik/system/EmulatedStackFrameTest.java
index 6d61300..c17fad7 100644
--- a/luni/src/test/java/libcore/dalvik/system/EmulatedStackFrameTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/EmulatedStackFrameTest.java
@@ -113,6 +113,23 @@
         assertEquals("foo", reader.nextReference(String.class));
     }
 
+    public void testReaderWriter_assignableTypes() {
+        EmulatedStackFrame stackFrame = EmulatedStackFrame.create(
+            MethodType.methodType(Object.class, Object.class));
+
+        EmulatedStackFrame.StackFrameWriter writer = new EmulatedStackFrame.StackFrameWriter();
+        writer.attach(stackFrame);
+        writer.putNextReference(Boolean.TRUE, Object.class);
+        writer.makeReturnValueAccessor();
+        writer.putNextReference(Boolean.FALSE, Object.class);
+
+        EmulatedStackFrame.StackFrameReader reader = new EmulatedStackFrame.StackFrameReader();
+        reader.attach(stackFrame);
+        assertEquals(Boolean.TRUE, reader.nextReference(Object.class));
+        reader.makeReturnValueAccessor();
+        assertEquals(Boolean.FALSE, reader.nextReference(Object.class));
+    }
+
     public void testReaderWriter_wrongTypes() {
         EmulatedStackFrame stackFrame = EmulatedStackFrame.create(
                 MethodType.methodType(boolean.class, String.class));
diff --git a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
index 3e82690..390cfd6 100644
--- a/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
+++ b/luni/src/test/java/libcore/java/io/FileDescriptorTest.java
@@ -16,7 +16,10 @@
 
 package libcore.java.io;
 
+import android.system.Os;
+
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -24,6 +27,8 @@
 import java.net.ServerSocket;
 import junit.framework.TestCase;
 
+import static org.junit.Assert.assertNotEquals;
+
 public class FileDescriptorTest extends TestCase {
   public void testReadOnlyFileDescriptorSync() throws Exception {
     File f= File.createTempFile("FileDescriptorTest", "tmp");
@@ -40,4 +45,31 @@
     assertTrue(s.getImpl().getFD$().isSocket$());
     s.close();
   }
+
+  public void testStaticFileDescriptors() {
+    assertTrue(FileDescriptor.in.valid());
+    assertTrue(FileDescriptor.out.valid());
+    assertTrue(FileDescriptor.err.valid());
+  }
+
+  public void testFileDescriptorCloneForFork() throws Exception {
+    FileDescriptor [] sources = { FileDescriptor.in, FileDescriptor.out, FileDescriptor.err };
+    for (FileDescriptor source : sources) {
+      // Create a new file descriptor and set it's native descriptor to each of the well
+      // known descriptors in FileDescriptor.
+      FileDescriptor target = new FileDescriptor();
+      target.setInt$(source.getInt$());
+      assertEquals(target.getInt$(), source.getInt$());
+
+      // Clone file descriptor, this creates a native file descriptor.
+      target.cloneForFork();
+      assertTrue(source.valid());
+      assertTrue(target.valid());
+      assertNotEquals(target.getInt$(), source.getInt$());
+
+      // Clean-up native resource we allocated in cloneForFork. Os.close() may throw
+      // an ErrnoException.
+      Os.close(target);
+    }
+  }
 }
diff --git a/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java b/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
index 3811cbc..eab558a 100644
--- a/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
+++ b/luni/src/test/java/libcore/java/io/RandomAccessFileTest.java
@@ -41,16 +41,6 @@
         file.delete();
     }
 
-    public void testSeekTooLarge() throws Exception {
-        try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
-            try {
-                raf.seek(Long.MAX_VALUE);
-                fail();
-            } catch (IOException expected) {
-            }
-        }
-    }
-
     public void testSetLengthTooLarge() throws Exception {
         try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
             try {
diff --git a/luni/src/test/java/libcore/java/lang/StringTest.java b/luni/src/test/java/libcore/java/lang/StringTest.java
index c440ebe..395209a 100644
--- a/luni/src/test/java/libcore/java/lang/StringTest.java
+++ b/luni/src/test/java/libcore/java/lang/StringTest.java
@@ -29,7 +29,6 @@
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
 import java.nio.charset.CodingErrorAction;
-import java.nio.charset.ModifiedUtf8;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.ArrayList;
diff --git a/luni/src/test/java/libcore/java/lang/ThreadTest.java b/luni/src/test/java/libcore/java/lang/ThreadTest.java
index f1d0db6..4e60891 100644
--- a/luni/src/test/java/libcore/java/lang/ThreadTest.java
+++ b/luni/src/test/java/libcore/java/lang/ThreadTest.java
@@ -16,7 +16,13 @@
 
 package libcore.java.lang;
 
+import dalvik.system.InMemoryDexClassLoader;
+
+import java.io.InputStream;
+import java.lang.reflect.Method;
 import java.lang.Thread.UncaughtExceptionHandler;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.LockSupport;
@@ -28,6 +34,7 @@
 import org.mockito.InOrder;
 import org.mockito.Mockito;
 
+import libcore.io.Streams;
 import libcore.java.lang.ref.FinalizationTester;
 
 public final class ThreadTest extends TestCase {
@@ -137,6 +144,85 @@
         assertSame(Thread.currentThread().getContextClassLoader(), other.getContextClassLoader());
     }
 
+    public void testSetPriority_unstarted() throws Exception {
+        Thread thread = new Thread();
+        checkSetPriority_inBounds_succeeds(thread);
+        checkSetPriority_outOfBounds_fails(thread);
+    }
+
+    public void testSetPriority_starting() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        Thread thread = new Thread("starting thread") {
+            @Override public void run() { try { latch.await(); } catch (Exception e) { } }
+        };
+        // priority set while thread was not started should carry over to started thread
+        int priority = thread.getPriority() + 1;
+        if (priority > Thread.MAX_PRIORITY) {
+            priority = Thread.MIN_PRIORITY;
+        }
+        thread.setPriority(priority);
+        thread.start();
+        assertEquals(priority, thread.getPriority());
+        latch.countDown();
+        thread.join();
+    }
+
+    public void testSetPriority_started() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        Thread startedThread = new Thread("started thread") {
+            @Override public void run() { try { latch.await(); } catch (Exception e) { } }
+        };
+        startedThread.start();
+        checkSetPriority_inBounds_succeeds(startedThread);
+        checkSetPriority_outOfBounds_fails(startedThread);
+        latch.countDown();
+        startedThread.join();
+    }
+
+    public void testSetPriority_joined() throws Exception {
+        Thread joinedThread = new Thread();
+        joinedThread.start();
+        joinedThread.join();
+
+        int originalPriority = joinedThread.getPriority();
+        for (int p = Thread.MIN_PRIORITY; p <= Thread.MAX_PRIORITY; p++) {
+            joinedThread.setPriority(p);
+            // setting the priority of a not-alive Thread should not succeed
+            assertEquals(originalPriority, joinedThread.getPriority());
+        }
+        checkSetPriority_outOfBounds_fails(joinedThread);
+    }
+
+    private static void checkSetPriority_inBounds_succeeds(Thread thread) {
+        int oldPriority = thread.getPriority();
+        try {
+            for (int priority = Thread.MIN_PRIORITY; priority <= Thread.MAX_PRIORITY; priority++) {
+                thread.setPriority(priority);
+                assertEquals(priority, thread.getPriority());
+            }
+        } finally {
+            thread.setPriority(oldPriority);
+        }
+        assertEquals(oldPriority, thread.getPriority());
+    }
+
+    private static void checkSetPriority_outOfBounds_fails(Thread thread) {
+        checkSetPriority_outOfBounds_fails(thread, Thread.MIN_PRIORITY - 1);
+        checkSetPriority_outOfBounds_fails(thread, Thread.MAX_PRIORITY + 1);
+        checkSetPriority_outOfBounds_fails(thread, Integer.MIN_VALUE);
+        checkSetPriority_outOfBounds_fails(thread, Integer.MAX_VALUE);
+    }
+
+    private static void checkSetPriority_outOfBounds_fails(Thread thread, int invalidPriority) {
+        int oldPriority = thread.getPriority();
+        try {
+            thread.setPriority(invalidPriority);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+        assertEquals(oldPriority, thread.getPriority()); // priority shouldn't have changed
+    }
+
     public void testUncaughtExceptionPreHandler_calledBeforeDefaultHandler() {
         UncaughtExceptionHandler initialHandler = Mockito.mock(UncaughtExceptionHandler.class);
         UncaughtExceptionHandler defaultHandler = Mockito.mock(UncaughtExceptionHandler.class);
@@ -203,6 +289,84 @@
         t1.join();
     }
 
+    /**
+     * Checks that a stacktrace reports the expected debug metadata
+     * (source-filename, line number) hard-coded in a class loaded from
+     * pre-built test resources.
+     */
+    public void testGetStackTrace_debugInfo() throws Exception {
+        StackTraceElement ste = getStackTraceElement("debugInfo");
+
+        // Verify that this StackTraceElement appears as we expect it to
+        // e.g. when an exception is printed.
+        assertEquals("java.lang.ThreadTestHelper.debugInfo(ThreadTestHelper.java:9)",
+                ste.toString());
+
+        // Since we emit debug information for ThreadTestHelper.debugInfo,
+        // the Runtime will symbolicate this frame with the correct file name.
+        assertEquals("ThreadTestHelper.java", ste.getFileName());
+
+        // We explicitly specify this in the test resource.
+        assertEquals(9, ste.getLineNumber());
+    }
+
+    /**
+     * Checks that a stacktrace reports the expected dex PC in place of
+     * a line number when debug info is missing for a method; the method is
+     * declared on a class loaded from pre-built test resources.
+     */
+    public void testGetStackTrace_noDebugInfo() throws Exception {
+        StackTraceElement ste = getStackTraceElement("noDebugInfo");
+
+        // Verify that this StackTraceElement appears as we expect it to
+        // e.g. when an exception is printed.
+        assertEquals("java.lang.ThreadTestHelper.noDebugInfo(Unknown Source:3)", ste.toString());
+
+        // Since we don't have any debug info for this method, the Runtime
+        // doesn't symbolicate this with a file name (even though the
+        // enclosing class may have the file name specified).
+        assertEquals(null, ste.getFileName());
+
+        // In the test resource we emit 3 nops before generating a stack
+        // trace; each nop advances the dex PC by 1 because a nop is a
+        // single code unit wide.
+        assertEquals(3, ste.getLineNumber());
+    }
+
+    /**
+     * Calls the given static method declared on ThreadTestHelper, which
+     * is loaded from precompiled test resources.
+     *
+     * @param methodName either {@quote "debugInfo"} or {@quote "noDebugInfo"}
+     * @return the StackTraceElement corresponding to said method's frame
+     */
+    private static StackTraceElement getStackTraceElement(String methodName) throws Exception {
+        final String className = "java.lang.ThreadTestHelper";
+        byte[] data;
+        try (InputStream is =
+                ThreadTest.class.getClassLoader().getResourceAsStream("core-tests-smali.dex")) {
+            data = Streams.readFullyNoClose(is);
+        }
+        ClassLoader imcl = new InMemoryDexClassLoader(ByteBuffer.wrap(data),
+                ThreadTest.class.getClassLoader());
+        Class<?> helper = imcl.loadClass(className);
+        Method m = helper.getDeclaredMethod(methodName);
+        StackTraceElement[] stes = (StackTraceElement[]) m.invoke(null);
+
+        // The top of the stack trace looks like:
+        // - VMStack.getThreadStackTrace()
+        // - Thread.getStackTrace()
+        // - ThreadTestHelper.createStackTrace()
+        // - ThreadTestHelper.{debugInfo,noDebugInfo}
+        StackTraceElement result = stes[3];
+
+        // Sanity check before we return
+        assertEquals(result.getClassName(), className);
+        assertEquals(result.getMethodName(), methodName);
+        assertFalse(result.isNativeMethod());
+        return result;
+    }
+
     public void testGetAllStackTracesIncludesAllGroups() throws Exception {
         final AtomicInteger visibleTraces = new AtomicInteger();
         ThreadGroup group = new ThreadGroup("1");
diff --git a/luni/src/test/java/libcore/java/lang/ThreadTestHelper.smali b/luni/src/test/java/libcore/java/lang/ThreadTestHelper.smali
new file mode 100644
index 0000000..d55120e
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/ThreadTestHelper.smali
@@ -0,0 +1,96 @@
+#
+# 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.
+#
+
+# Generated by running the following java through dx/baksmali:
+# package java.lang;
+#
+# public class ThreadTestHelper {
+#     static StackTraceElement[] createStackTrace() {
+#         return Thread.currentThread().getStackTrace();
+#     }
+#
+#     static public StackTraceElement[] debugInfo() {
+#         return createStackTrace();
+#     }
+#
+#     static public StackTraceElement[] noDebugInfo() {
+#         return createStackTrace();
+#     }
+# }
+# Additionally .line / .prologue declarations were removed from noDebugInfo
+# so that no debug info is generated for that method and three nops were
+# introduced so that the stack trace is a little bit more interesting.
+.class public Ljava/lang/ThreadTestHelper;
+.super Ljava/lang/Object;
+.source "ThreadTestHelper.java"
+
+
+# direct methods
+.method public constructor <init>()V
+    .registers 1
+
+    .prologue
+    .line 3
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+    return-void
+.end method
+
+.method static createStackTrace()[Ljava/lang/StackTraceElement;
+    .registers 1
+
+    .prologue
+    .line 5
+    invoke-static {}, Ljava/lang/Thread;->currentThread()Ljava/lang/Thread;
+
+    move-result-object v0
+
+    invoke-virtual {v0}, Ljava/lang/Thread;->getStackTrace()[Ljava/lang/StackTraceElement;
+
+    move-result-object v0
+
+    return-object v0
+.end method
+
+.method public static debugInfo()[Ljava/lang/StackTraceElement;
+    .registers 1
+
+    .prologue
+    .line 9
+    invoke-static {}, Ljava/lang/ThreadTestHelper;->createStackTrace()[Ljava/lang/StackTraceElement;
+
+    move-result-object v0
+
+    return-object v0
+.end method
+
+.method public static noDebugInfo()[Ljava/lang/StackTraceElement;
+    .registers 1
+
+    # Removed so this method doesn't have debug info
+    #.prologue
+    #.line 13
+
+    # Added so the stack trace looks more interesting
+    nop
+    nop
+    nop
+    invoke-static {}, Ljava/lang/ThreadTestHelper;->createStackTrace()[Ljava/lang/StackTraceElement;
+
+    move-result-object v0
+
+    return-object v0
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/invoke/ExplicitCastArgumentsTest.java b/luni/src/test/java/libcore/java/lang/invoke/ExplicitCastArgumentsTest.java
new file mode 100644
index 0000000..abc5825
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/invoke/ExplicitCastArgumentsTest.java
@@ -0,0 +1,5724 @@
+/*
+ * 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 libcore.java.lang.invoke;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.WrongMethodTypeException;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class ExplicitCastArgumentsTest {
+    //
+    // Constants for value casts.
+    //
+    private static final Boolean[] BOOLEAN_VALUES = new Boolean[]{ Boolean.TRUE, Boolean.FALSE };
+
+    private static final Byte[] BYTE_VALUES = new Byte[]{
+        Byte.valueOf((byte) 0), Byte.valueOf((byte) 1), Byte.valueOf((byte) 2),
+        Byte.valueOf((byte) -1), Byte.valueOf((byte) -2), Byte.MIN_VALUE, Byte.MAX_VALUE
+    };
+
+    private static final Character[] CHARACTER_VALUES = new Character[]{
+        Character.MIN_VALUE, Character.MAX_VALUE, Character.valueOf('A'), Character.valueOf('B'),
+    };
+
+    private static final Short[] SHORT_VALUES = new Short[]{
+        Short.valueOf((short) 0), Short.valueOf((short) 1), Short.valueOf((short) 130),
+        Short.valueOf((short) -1), Short.valueOf((short) -130), Short.MIN_VALUE, Short.MAX_VALUE
+    };
+
+    private static final Integer[] INTEGER_VALUES = new Integer[]{
+        Integer.valueOf(0), Integer.valueOf(1), Integer.valueOf(130), Integer.valueOf(32768),
+        Integer.valueOf(-1), Integer.valueOf(-130), Integer.valueOf(-32769),
+        Integer.MIN_VALUE, Integer.MAX_VALUE
+    };
+
+    private static final Long[] LONG_VALUES = new Long[]{
+        Long.valueOf(0L), Long.valueOf(1L), Long.valueOf(130L), Long.valueOf(32768L),
+        Long.valueOf(0x800000000L), Long.valueOf(0x800000001L),
+        Long.valueOf(-1l), Long.valueOf(-130l), Long.valueOf(-32769l), Long.valueOf(-0x800000000L),
+        Long.valueOf(-0x800000001L), Long.MIN_VALUE, Long.MAX_VALUE
+    };
+
+    private static final Float[] FLOAT_VALUES = new Float[]{
+        Float.valueOf(0.0f), Float.valueOf(0.5f), Float.valueOf(1.0f), Float.valueOf(2.0f),
+        Float.valueOf(3.141f), Float.valueOf(-0.5f), Float.valueOf(-1.0f), Float.valueOf(-2.0f),
+        Float.valueOf(-3.141f), Float.MIN_VALUE, Float.MAX_VALUE
+    };
+
+    private static final Double[] DOUBLE_VALUES = new Double[]{
+        Double.valueOf(0.0), Double.valueOf(0.5), Double.valueOf(1.0), Double.valueOf(2.0),
+        Double.valueOf(3.141), Double.valueOf(-0.5), Double.valueOf(-1.0), Double.valueOf(-2.0),
+        Double.valueOf(-3.141), Double.MIN_VALUE, Double.MAX_VALUE,
+    };
+
+    // Conversions to boolean for explicitCastArgument().
+    private static boolean toBooleanValue(byte v) { return (v & 1) != 0; }
+    private static boolean toBooleanValue(char v) { return toBooleanValue((byte) v); }
+    private static boolean toBooleanValue(short v) { return toBooleanValue((byte) v); }
+    private static boolean toBooleanValue(int v) { return toBooleanValue((byte) v); }
+    private static boolean toBooleanValue(long v) { return toBooleanValue((byte) v); }
+    private static boolean toBooleanValue(float v) { return toBooleanValue((long) v); }
+    private static boolean toBooleanValue(double v) { return toBooleanValue((long) v); }
+
+    // Conversions from boolean for explicitCastArgument().
+    private static byte byteFromBooleanValue(boolean v) { return v ? (byte) 1 : (byte) 0; }
+    private static char charFromBooleanValue(boolean v) { return v ? (char) 1 : (char) 0; }
+    private static short shortFromBooleanValue(boolean v) { return v ? (short) 1 : (short) 0; }
+    private static int intFromBooleanValue(boolean v) { return v ? 1 : 0; }
+    private static long longFromBooleanValue(boolean v) { return v ? 1L : 0L; }
+    private static float floatFromBooleanValue(boolean v) { return v ? 1.0f : 0.0f; }
+    private static double doubleFromBooleanValue(boolean v) { return v ? 1.0 : 0.0; }
+
+    // Helper constructing a MethodHandle of type (identityClass, argClass) for testing
+    // explicit casts applied to the argument of the MethodHandle invocation.
+    private static MethodHandle explicitCastArgumentToIdentity(Class identityClass,
+                                                               Class argClass) {
+        MethodHandle identity = MethodHandles.identity(identityClass);
+        MethodType mt = MethodType.methodType(identityClass, argClass);
+        return MethodHandles.explicitCastArguments(identity, mt);
+    }
+
+    // Helper constructing a MethodHandle of type (argClass, identity) for testing
+    // explicit casts applied to the return value from the MethodHandle invocation.
+    private static MethodHandle explicitCastReturnValueFromIdentity(Class identityClass,
+                                                                    Class retClass) {
+        MethodHandle identity = MethodHandles.identity(identityClass);
+        MethodType mt = MethodType.methodType(retClass, identityClass);
+        return MethodHandles.explicitCastArguments(identity, mt);
+    }
+
+    // Helper for constructing a typed null constant with aan explicit cast to a primitive
+    // type.
+    private static MethodHandle nullConstantExplicitCastToPrimitive(Class constantType,
+                                                                    Class primitiveType) {
+        return MethodHandles.explicitCastArguments(MethodHandles.constant(constantType, null),
+                                                   MethodType.methodType(primitiveType));
+    }
+
+    // Helper returning void.
+    public static void voidFunction() {
+    }
+
+    // Helper for constructing an explicit cast from void to type return value.
+    private static MethodHandle explicitCastVoidReturnValue(Class toType) throws Throwable {
+        MethodHandle m =
+            MethodHandles.publicLookup().findStatic(ExplicitCastArgumentsTest.class,
+                                                    "voidFunction",
+                                                    MethodType.methodType(void.class));
+        return MethodHandles.explicitCastArguments(m, MethodType.methodType(toType));
+    }
+
+    // Helper classes and interfaces for reference checks.
+    interface ParentInterface {
+        public static String name = "ParentInterface";
+    }
+
+    interface ChildInterface {
+        public static String name = "ChildInterface";
+    }
+
+    class Parent implements ParentInterface {}
+
+    class Child extends Parent implements ChildInterface {}
+
+    // Explicit casting of arguments and return values for reference types.
+    @Test
+    public void explicitCastArgumentParentToChild() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Child.class, Parent.class);
+        try {
+            Child c = (Child) mh.invokeExact(new Parent());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentNullParentToChild() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Child.class, Parent.class);
+        Child c = (Child) mh.invokeExact((Parent) null);
+        assertNull(c);
+    }
+
+    @Test
+    public void explicitCastArgumentChildToParent() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Parent.class, Child.class);
+        Parent p = (Parent) mh.invokeExact(new Child());
+        assertTrue(p instanceof Child);
+    }
+
+    @Test
+    public void explicitCastArgumentNullChildToParent() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Parent.class, Child.class);
+        Parent p = (Parent) mh.invokeExact((Child) null);
+        assertNull(p);
+    }
+
+    @Test
+    public void explicitCastReturnValueNullParentToChild() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Parent.class, Child.class);
+        Child c = (Child) mh.invokeExact((Parent) null);
+        assertNull(c);
+    }
+
+    @Test
+    public void explicitCastReturnValueParentToChild() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Parent.class, Child.class);
+        try {
+            Child c = (Child) mh.invokeExact(new Parent());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueNullChildToParent() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Child.class, Parent.class);
+        Parent p = (Parent) mh.invokeExact((Child) null);
+        assertNull(p);
+    }
+
+    @Test
+    public void explicitCastReturnValueChildToParent() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Child.class, Parent.class);
+        Parent x = (Parent) mh.invokeExact(new Child());
+        assertTrue(x instanceof Child);
+    }
+
+    @Test
+    public void explicitCastArgumentOfInterfaceType_doesNotThrow() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(ParentInterface.class, Parent.class);
+        ParentInterface pi = (ParentInterface) mh.invokeExact(new Parent());
+        assertTrue(pi instanceof ParentInterface);
+        pi = (ParentInterface) mh.invokeExact((Parent) null);
+        assertNull(pi);
+
+        MethodHandle mh1 = explicitCastArgumentToIdentity(ParentInterface.class, Child.class);
+        pi = (ParentInterface) mh1.invokeExact(new Child());
+        assertTrue(pi instanceof ParentInterface);
+        pi = (ParentInterface) mh1.invokeExact((Child) null);
+        assertNull(pi);
+
+        MethodHandle mh2 = explicitCastArgumentToIdentity(ParentInterface.class, Integer.class);
+        pi = (ParentInterface) mh2.invokeExact(Integer.valueOf(3));
+        assertFalse(pi instanceof ParentInterface);
+        pi = (ParentInterface) mh2.invokeExact((Integer) null);
+        assertNull(pi);
+    }
+
+    @Test
+    public void explicitCastReturnValueOfInterfaceType_doesNotThrow() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Parent.class,
+                                                              ParentInterface.class);
+        ParentInterface pi = (ParentInterface) mh.invokeExact(new Parent());
+        assertTrue(pi instanceof ParentInterface);
+        pi = (ParentInterface) mh.invokeExact((Parent) null);
+        assertNull(pi);
+
+        MethodHandle mh1 = explicitCastReturnValueFromIdentity(Child.class,
+                                                               ParentInterface.class);
+        pi = (ParentInterface) mh1.invokeExact(new Child());
+        assertTrue(pi instanceof ParentInterface);
+        pi = (ParentInterface) mh1.invokeExact((Child) null);
+        assertNull(pi);
+
+        MethodHandle mh2 = explicitCastReturnValueFromIdentity(Integer.class,
+                                                               ParentInterface.class);
+        pi = (ParentInterface) mh2.invokeExact(Integer.valueOf(42));
+        assertFalse(pi instanceof ParentInterface);
+        pi = (ParentInterface) mh2.invokeExact((Integer) null);
+        assertNull(pi);
+    }
+
+    @Test
+    public void originalTypeAndNewTypeEqual() throws Throwable {
+        MethodHandle mh = MethodHandles.identity(Integer.class);
+        assertEquals(mh, MethodHandles.explicitCastArguments(mh, mh.type()));
+        assertEquals(mh,
+                     MethodHandles.explicitCastArguments(mh,
+                                                         MethodType.methodType(Integer.class,
+                                                                               Integer.class)));
+    }
+
+    //
+    // Explicit casting of arguments between the primitive types and their
+    // reference type counterparts.
+    //
+    @Test
+    public void explicitCastArgumentZToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(v, (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(byteFromBooleanValue(v), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(charFromBooleanValue(v), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(shortFromBooleanValue(v), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(intFromBooleanValue(v), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(longFromBooleanValue(v), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(floatFromBooleanValue(v), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(doubleFromBooleanValue(v), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(Boolean.valueOf(v), (Boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentZToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, boolean.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentZToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, boolean.class);
+        try {
+            Character o = (Character) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentZToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, boolean.class);
+        try {
+            Short o = (Short) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentZToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, boolean.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentZToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, boolean.class);
+        try {
+            Long o = (Long) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentZToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, boolean.class);
+        try {
+            Float o = (Float) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentZToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, boolean.class);
+        try {
+            Double o = (Double) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals(v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, byte.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals(Byte.valueOf(v), (Byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, byte.class);
+        try {
+            Character o = (Character) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, byte.class);
+        try {
+            Short o = (Short) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, byte.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, byte.class);
+        try {
+            Long o = (Long) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, byte.class);
+        try {
+            Float o = (Float) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, byte.class);
+        try {
+            Double o = (Double) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals(v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, char.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, char.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals(Character.valueOf(v), (Character) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, char.class);
+        try {
+            Short o = (Short) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, char.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, char.class);
+        try {
+            Long o = (Long) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, char.class);
+        try {
+            Float o = (Float) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, char.class);
+        try {
+            Double o = (Double) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentSToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals(v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, short.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentSToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, short.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentSToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, short.class);
+        try {
+            Character o = (Character) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentSToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals(Short.valueOf(v), (Short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentSToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, short.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentSToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, short.class);
+        try {
+            Long o = (Long) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentSToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, short.class);
+        try {
+            Float o = (Float) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentSToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, short.class);
+        try {
+            Double o = (Double) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals(v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, int.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, int.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, int.class);
+        try {
+            Character o = (Character) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, int.class);
+        try {
+            Short o = (Short) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals(Integer.valueOf(v), (Integer) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, int.class);
+        try {
+            Long o = (Long) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, int.class);
+        try {
+            Float o = (Float) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, int.class);
+        try {
+            Double o = (Double) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentJToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals(v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, long.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentJToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, long.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentJToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, long.class);
+        try {
+            Character o = (Character) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentJToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, long.class);
+        try {
+            Short o = (Short) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentJToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, long.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentJToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals(Long.valueOf(v), (Long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentJToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, long.class);
+        try {
+            Float o = (Float) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentJToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, long.class);
+        try {
+            Double o = (Double) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals(v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, float.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, float.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, float.class);
+        try {
+            Character o = (Character) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, float.class);
+        try {
+            Short o = (Short) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, float.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, float.class);
+        try {
+            Long o = (Long) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals(Float.valueOf(v), (Float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, float.class);
+        try {
+            Double o = (Double) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals(v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, double.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, double.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, double.class);
+        try {
+            Character o = (Character) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, double.class);
+        try {
+            Short o = (Short) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, double.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, double.class);
+        try {
+            Long o = (Long) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, double.class);
+        try {
+            Float o = (Float) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals(Double.valueOf(v), (Double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(v.booleanValue(), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(byteFromBooleanValue(v.booleanValue()), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(charFromBooleanValue(v.booleanValue()), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(shortFromBooleanValue(v.booleanValue()), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(intFromBooleanValue(v.booleanValue()), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(longFromBooleanValue(v.booleanValue()), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(floatFromBooleanValue(v.booleanValue()), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(doubleFromBooleanValue(v.booleanValue()), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(v, (Boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, Boolean.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, Boolean.class);
+        try {
+            Character o = (Character) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, Boolean.class);
+        try {
+            Short o = (Short) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, Boolean.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, Boolean.class);
+        try {
+            Long o = (Long) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, Boolean.class);
+        try {
+            Float o = (Float) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentBooleanToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, Boolean.class);
+        try {
+            Double o = (Double) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentByteToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals(toBooleanValue(v.byteValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals(v.byteValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((char) v.byteValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((short) v.byteValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((int) v.byteValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((long) v.byteValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((float) v.byteValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((double) v.byteValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, Byte.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentByteToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals(v, (Byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentByteToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, Byte.class);
+        try {
+            Character o = (Character) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentByteToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, Byte.class);
+        try {
+            Short o = (Short) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentByteToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, Byte.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentByteToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, Byte.class);
+        try {
+            Long o = (Long) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentByteToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, Byte.class);
+        try {
+            Float o = (Float) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentByteToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, Byte.class);
+        try {
+            Double o = (Double) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals(toBooleanValue(v.charValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((byte) v.charValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals(v.charValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((short) v.charValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((int) v.charValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((long) v.charValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((float) v.charValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((double) v.charValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, Character.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, Character.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals(v, (Character) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, Character.class);
+        try {
+            Short o = (Short) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, Character.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, Character.class);
+        try {
+            Long o = (Long) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, Character.class);
+        try {
+            Float o = (Float) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentCharacterToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, Character.class);
+        try {
+            Double o = (Double) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentShortToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals(toBooleanValue(v.shortValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((byte) v.shortValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((char) v.shortValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals(v.shortValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((int) v.shortValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((long) v.shortValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((float) v.shortValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((double) v.shortValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, Short.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentShortToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, Short.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentShortToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, Short.class);
+        try {
+            Character o = (Character) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentShortToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals(v, (Short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentShortToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, Short.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentShortToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, Short.class);
+        try {
+            Long o = (Long) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentShortToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, Short.class);
+        try {
+            Float o = (Float) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentShortToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, Short.class);
+        try {
+            Double o = (Double) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals(toBooleanValue(v.intValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((byte) v.intValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((char) v.intValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((short) v.intValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals(v.intValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((long) v.intValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((float) v.intValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((double) v.intValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, Integer.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, Integer.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, Integer.class);
+        try {
+            Character o = (Character) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, Integer.class);
+        try {
+            Short o = (Short) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals(v, (Integer) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, Integer.class);
+        try {
+            Long o = (Long) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, Integer.class);
+        try {
+            Float o = (Float) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentIntegerToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, Integer.class);
+        try {
+            Double o = (Double) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentLongToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals(toBooleanValue(v.longValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((byte) v.longValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((char) v.longValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((short) v.longValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((int) v.longValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals(v.longValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((float) v.longValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((double) v.longValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, Long.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentLongToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, Long.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentLongToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, Long.class);
+        try {
+            Character o = (Character) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentLongToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, Long.class);
+        try {
+            Short o = (Short) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentLongToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, Long.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentLongToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals(v, (Long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentLongToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, Long.class);
+        try {
+            Float o = (Float) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentLongToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, Long.class);
+        try {
+            Double o = (Double) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals(toBooleanValue(v.floatValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((byte) v.floatValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((char) v.floatValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((short) v.floatValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((int) v.floatValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((long) v.floatValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals(v.floatValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((double) v.floatValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, Float.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, Float.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, Float.class);
+        try {
+            Character o = (Character) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, Float.class);
+        try {
+            Short o = (Short) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, Float.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, Float.class);
+        try {
+            Long o = (Long) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals(v, (Float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentFloatToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, Float.class);
+        try {
+            Double o = (Double) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToZ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(boolean.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals(toBooleanValue(v.doubleValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToB() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(byte.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((byte) v.doubleValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToC() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(char.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((char) v.doubleValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToS() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(short.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((short) v.doubleValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToI() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(int.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((int) v.doubleValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToJ() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(long.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((long) v.doubleValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToF() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(float.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((float) v.doubleValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToD() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(double.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals(v.doubleValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Boolean.class, Double.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToByte() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Byte.class, Double.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Character.class, Double.class);
+        try {
+            Character o = (Character) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToShort() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Short.class, Double.class);
+        try {
+            Short o = (Short) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToInteger() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Integer.class, Double.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToLong() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Long.class, Double.class);
+        try {
+            Long o = (Long) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToFloat() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Float.class, Double.class);
+        try {
+            Float o = (Float) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastArgumentDoubleToDouble() throws Throwable {
+        MethodHandle mh = explicitCastArgumentToIdentity(Double.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals(v, (Double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    //
+    // Explicit casting of return values between the primitive types and their
+    // reference type counterparts.
+    //
+    @Test
+    public void explicitCastReturnValueZToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(v, (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, boolean.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, boolean.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, boolean.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, boolean.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, boolean.class);
+        for (long v : LONG_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, boolean.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, boolean.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals(toBooleanValue(v), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(v.booleanValue(), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, boolean.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals(toBooleanValue(v.byteValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, boolean.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals(toBooleanValue(v.charValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, boolean.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals(toBooleanValue(v.shortValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, boolean.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals(toBooleanValue(v.intValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, boolean.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals(toBooleanValue(v.longValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, boolean.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals(toBooleanValue(v.floatValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToZ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, boolean.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals(toBooleanValue(v.doubleValue()), (boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueZToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, byte.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(byteFromBooleanValue(v), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals(v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, byte.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, byte.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, byte.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, byte.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, byte.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, byte.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((byte) v, (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, byte.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(byteFromBooleanValue(v.booleanValue()), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals(v.byteValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, byte.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((byte) v.charValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, byte.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((byte) v.shortValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, byte.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((byte) v.intValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, byte.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((byte) v.longValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, byte.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((byte) v.floatValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToB() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, byte.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((byte) v.doubleValue(), (byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueZToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, char.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(charFromBooleanValue(v), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, char.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, char.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals(v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, char.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, char.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, char.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, char.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, char.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((char) v, (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, char.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(charFromBooleanValue(v.booleanValue()), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, char.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((char) v.byteValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, char.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals(v.charValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, char.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((char) v.shortValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, char.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((char) v.intValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, char.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((char) v.longValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, char.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((char) v.floatValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToC() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, char.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((char) v.doubleValue(), (char) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueZToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, short.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(shortFromBooleanValue(v), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, short.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, short.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals(v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, short.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, short.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, short.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, short.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((short) v, (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, short.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(shortFromBooleanValue(v.booleanValue()), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, short.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((short) v.byteValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, short.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((short) v.charValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals(v.shortValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, short.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((short) v.intValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, short.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((short) v.longValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, short.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((short) v.floatValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToS() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, short.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((short) v.doubleValue(), (short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueZToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, int.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(intFromBooleanValue(v), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, int.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, int.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, int.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, int.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals(v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, int.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, int.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, int.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((int) v, (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, int.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(intFromBooleanValue(v.booleanValue()), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, int.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((int) v.byteValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, int.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((int) v.charValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, int.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((int) v.shortValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, int.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals(v.intValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, int.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((int) v.longValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, int.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((int) v.floatValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToI() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, int.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((int) v.doubleValue(), (int) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueZToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, long.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(longFromBooleanValue(v), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, long.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, long.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, long.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, long.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals(v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, long.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, long.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((long) v, (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, long.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(longFromBooleanValue(v.booleanValue()), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, long.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((long) v.byteValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, long.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((long) v.charValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, long.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((long) v.shortValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, long.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((long) v.intValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals(v.longValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, long.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((long) v.floatValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToJ() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, long.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((long) v.doubleValue(), (long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueZToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, float.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(floatFromBooleanValue(v), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, float.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, float.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, float.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, float.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, float.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals(v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, float.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals((float) v, (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, float.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(floatFromBooleanValue(v.booleanValue()), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, float.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((float) v.byteValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, float.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((float) v.charValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, float.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((float) v.shortValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, float.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((float) v.intValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, float.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((float) v.longValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals(v.floatValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToF() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, float.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals((float) v.doubleValue(), (float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueZToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, double.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(doubleFromBooleanValue(v), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, double.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, double.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, double.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, double.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, double.class);
+        for (long v : LONG_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, double.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals((double) v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals(v, (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, double.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(doubleFromBooleanValue(v.booleanValue()), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, double.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals((double) v.byteValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, double.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals((double) v.charValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, double.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals((double) v.shortValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, double.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals((double) v.intValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, double.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals((double) v.longValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, double.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals((double) v.floatValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToD() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals(v.doubleValue(), (double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueZToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, Boolean.class);
+        for (boolean v : BOOLEAN_VALUES) {
+            assertEquals(Boolean.valueOf(v), (Boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueSToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueJToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, Boolean.class);
+        for (Boolean v : BOOLEAN_VALUES) {
+            assertEquals(v, (Boolean) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToBoolean() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, Boolean.class);
+        try {
+            Boolean o = (Boolean) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueZToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, Byte.class);
+        for (byte v : BYTE_VALUES) {
+            assertEquals(Byte.valueOf(v), (Byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueSToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueJToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, Byte.class);
+        for (Byte v : BYTE_VALUES) {
+            assertEquals(v, (Byte) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToByte() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, Byte.class);
+        try {
+            Byte o = (Byte) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueZToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, Character.class);
+        for (char v : CHARACTER_VALUES) {
+            assertEquals(Character.valueOf(v), (Character) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueSToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueJToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, Character.class);
+        for (Character v : CHARACTER_VALUES) {
+            assertEquals(v, (Character) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToCharacter() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, Character.class);
+        try {
+            Character o = (Character) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueZToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueSToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, Short.class);
+        for (short v : SHORT_VALUES) {
+            assertEquals(Short.valueOf(v), (Short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueJToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, Short.class);
+        for (Short v : SHORT_VALUES) {
+            assertEquals(v, (Short) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToShort() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, Short.class);
+        try {
+            Short o = (Short) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueZToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueSToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, Integer.class);
+        for (int v : INTEGER_VALUES) {
+            assertEquals(Integer.valueOf(v), (Integer) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueJToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, Integer.class);
+        for (Integer v : INTEGER_VALUES) {
+            assertEquals(v, (Integer) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToInteger() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, Integer.class);
+        try {
+            Integer o = (Integer) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueZToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueSToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueJToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, Long.class);
+        for (long v : LONG_VALUES) {
+            assertEquals(Long.valueOf(v), (Long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, Long.class);
+        for (Long v : LONG_VALUES) {
+            assertEquals(v, (Long) mh.invokeExact(v));
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToLong() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, Long.class);
+        try {
+            Long o = (Long) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueZToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueSToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueJToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, Float.class);
+        for (float v : FLOAT_VALUES) {
+            assertEquals(Float.valueOf(v), (Float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(DOUBLE_VALUES[0].doubleValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, Float.class);
+        for (Float v : FLOAT_VALUES) {
+            assertEquals(v, (Float) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToFloat() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, Float.class);
+        try {
+            Float o = (Float) mh.invokeExact(DOUBLE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueZToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(boolean.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(BOOLEAN_VALUES[0].booleanValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueBToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(byte.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(BYTE_VALUES[0].byteValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(char.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(CHARACTER_VALUES[0].charValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueSToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(short.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(SHORT_VALUES[0].shortValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(int.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(INTEGER_VALUES[0].intValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueJToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(long.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(LONG_VALUES[0].longValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(float.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(FLOAT_VALUES[0].floatValue());
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(double.class, Double.class);
+        for (double v : DOUBLE_VALUES) {
+            assertEquals(Double.valueOf(v), (Double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    @Test
+    public void explicitCastReturnValueBooleanToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Boolean.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(BOOLEAN_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueByteToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Byte.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(BYTE_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueCharacterToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Character.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(CHARACTER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueShortToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Short.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(SHORT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueIntegerToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Integer.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(INTEGER_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueLongToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Long.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(LONG_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueFloatToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Float.class, Double.class);
+        try {
+            Double o = (Double) mh.invokeExact(FLOAT_VALUES[0]);
+            fail("Expected CCE");
+        } catch (ClassCastException expected) {}
+    }
+
+    @Test
+    public void explicitCastReturnValueDoubleToDouble() throws Throwable {
+        MethodHandle mh = explicitCastReturnValueFromIdentity(Double.class, Double.class);
+        for (Double v : DOUBLE_VALUES) {
+            assertEquals(v, (Double) mh.invokeExact(v), 0.0);
+        }
+    }
+
+    //
+    // Explicit casting of null valued arguments to primitive type values
+    // (zero/false).
+    //
+    @Test
+    public void nullBooleanArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Boolean.class);
+        assertEquals(false, (boolean) m.invokeExact((Boolean) null));
+    }
+
+    @Test
+    public void nullBooleanArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Boolean.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Boolean) null));
+    }
+
+    @Test
+    public void nullBooleanArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Boolean.class);
+        assertEquals((char) 0, (char) m.invokeExact((Boolean) null));
+    }
+
+    @Test
+    public void nullBooleanArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Boolean.class);
+        assertEquals((short) 0, (short) m.invokeExact((Boolean) null));
+    }
+
+    @Test
+    public void nullBooleanArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Boolean.class);
+        assertEquals((int) 0, (int) m.invokeExact((Boolean) null));
+    }
+
+    @Test
+    public void nullBooleanArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Boolean.class);
+        assertEquals((long) 0, (long) m.invokeExact((Boolean) null));
+    }
+
+    @Test
+    public void nullBooleanArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Boolean.class);
+        assertEquals((float) 0, (float) m.invokeExact((Boolean) null), 0.0);
+    }
+
+    @Test
+    public void nullBooleanArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Boolean.class);
+        assertEquals((double) 0, (double) m.invokeExact((Boolean) null), 0.0);
+    }
+
+    @Test
+    public void nullByteArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Byte.class);
+        assertEquals(false, (boolean) m.invokeExact((Byte) null));
+    }
+
+    @Test
+    public void nullByteArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Byte) null));
+    }
+
+    @Test
+    public void nullByteArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Byte.class);
+        assertEquals((char) 0, (char) m.invokeExact((Byte) null));
+    }
+
+    @Test
+    public void nullByteArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Byte.class);
+        assertEquals((short) 0, (short) m.invokeExact((Byte) null));
+    }
+
+    @Test
+    public void nullByteArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Byte.class);
+        assertEquals((int) 0, (int) m.invokeExact((Byte) null));
+    }
+
+    @Test
+    public void nullByteArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Byte.class);
+        assertEquals((long) 0, (long) m.invokeExact((Byte) null));
+    }
+
+    @Test
+    public void nullByteArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Byte.class);
+        assertEquals((float) 0, (float) m.invokeExact((Byte) null), 0.0);
+    }
+
+    @Test
+    public void nullByteArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Byte.class);
+        assertEquals((double) 0, (double) m.invokeExact((Byte) null), 0.0);
+    }
+
+    @Test
+    public void nullCharacterArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Character.class);
+        assertEquals(false, (boolean) m.invokeExact((Character) null));
+    }
+
+    @Test
+    public void nullCharacterArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Character.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Character) null));
+    }
+
+    @Test
+    public void nullCharacterArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Character.class);
+        assertEquals((char) 0, (char) m.invokeExact((Character) null));
+    }
+
+    @Test
+    public void nullCharacterArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Character.class);
+        assertEquals((short) 0, (short) m.invokeExact((Character) null));
+    }
+
+    @Test
+    public void nullCharacterArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Character.class);
+        assertEquals((int) 0, (int) m.invokeExact((Character) null));
+    }
+
+    @Test
+    public void nullCharacterArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Character.class);
+        assertEquals((long) 0, (long) m.invokeExact((Character) null));
+    }
+
+    @Test
+    public void nullCharacterArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Character.class);
+        assertEquals((float) 0, (float) m.invokeExact((Character) null), 0.0);
+    }
+
+    @Test
+    public void nullCharacterArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Character.class);
+        assertEquals((double) 0, (double) m.invokeExact((Character) null), 0.0);
+    }
+
+    @Test
+    public void nullShortArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Short.class);
+        assertEquals(false, (boolean) m.invokeExact((Short) null));
+    }
+
+    @Test
+    public void nullShortArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Short.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Short) null));
+    }
+
+    @Test
+    public void nullShortArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Short.class);
+        assertEquals((char) 0, (char) m.invokeExact((Short) null));
+    }
+
+    @Test
+    public void nullShortArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Short.class);
+        assertEquals((short) 0, (short) m.invokeExact((Short) null));
+    }
+
+    @Test
+    public void nullShortArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Short.class);
+        assertEquals((int) 0, (int) m.invokeExact((Short) null));
+    }
+
+    @Test
+    public void nullShortArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Short.class);
+        assertEquals((long) 0, (long) m.invokeExact((Short) null));
+    }
+
+    @Test
+    public void nullShortArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Short.class);
+        assertEquals((float) 0, (float) m.invokeExact((Short) null), 0.0);
+    }
+
+    @Test
+    public void nullShortArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Short.class);
+        assertEquals((double) 0, (double) m.invokeExact((Short) null), 0.0);
+    }
+
+    @Test
+    public void nullIntegerArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Integer.class);
+        assertEquals(false, (boolean) m.invokeExact((Integer) null));
+    }
+
+    @Test
+    public void nullIntegerArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Integer.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Integer) null));
+    }
+
+    @Test
+    public void nullIntegerArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Integer.class);
+        assertEquals((char) 0, (char) m.invokeExact((Integer) null));
+    }
+
+    @Test
+    public void nullIntegerArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Integer.class);
+        assertEquals((short) 0, (short) m.invokeExact((Integer) null));
+    }
+
+    @Test
+    public void nullIntegerArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Integer.class);
+        assertEquals((int) 0, (int) m.invokeExact((Integer) null));
+    }
+
+    @Test
+    public void nullIntegerArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Integer.class);
+        assertEquals((long) 0, (long) m.invokeExact((Integer) null));
+    }
+
+    @Test
+    public void nullIntegerArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Integer.class);
+        assertEquals((float) 0, (float) m.invokeExact((Integer) null), 0.0);
+    }
+
+    @Test
+    public void nullIntegerArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Integer.class);
+        assertEquals((double) 0, (double) m.invokeExact((Integer) null), 0.0);
+    }
+
+    @Test
+    public void nullLongArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Long.class);
+        assertEquals(false, (boolean) m.invokeExact((Long) null));
+    }
+
+    @Test
+    public void nullLongArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Long.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Long) null));
+    }
+
+    @Test
+    public void nullLongArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Long.class);
+        assertEquals((char) 0, (char) m.invokeExact((Long) null));
+    }
+
+    @Test
+    public void nullLongArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Long.class);
+        assertEquals((short) 0, (short) m.invokeExact((Long) null));
+    }
+
+    @Test
+    public void nullLongArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Long.class);
+        assertEquals((int) 0, (int) m.invokeExact((Long) null));
+    }
+
+    @Test
+    public void nullLongArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Long.class);
+        assertEquals((long) 0, (long) m.invokeExact((Long) null));
+    }
+
+    @Test
+    public void nullLongArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Long.class);
+        assertEquals((float) 0, (float) m.invokeExact((Long) null), 0.0);
+    }
+
+    @Test
+    public void nullLongArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Long.class);
+        assertEquals((double) 0, (double) m.invokeExact((Long) null), 0.0);
+    }
+
+    @Test
+    public void nullFloatArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Float.class);
+        assertEquals(false, (boolean) m.invokeExact((Float) null));
+    }
+
+    @Test
+    public void nullFloatArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Float.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Float) null));
+    }
+
+    @Test
+    public void nullFloatArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Float.class);
+        assertEquals((char) 0, (char) m.invokeExact((Float) null));
+    }
+
+    @Test
+    public void nullFloatArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Float.class);
+        assertEquals((short) 0, (short) m.invokeExact((Float) null));
+    }
+
+    @Test
+    public void nullFloatArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Float.class);
+        assertEquals((int) 0, (int) m.invokeExact((Float) null));
+    }
+
+    @Test
+    public void nullFloatArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Float.class);
+        assertEquals((long) 0, (long) m.invokeExact((Float) null));
+    }
+
+    @Test
+    public void nullFloatArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Float.class);
+        assertEquals((float) 0, (float) m.invokeExact((Float) null), 0.0);
+    }
+
+    @Test
+    public void nullFloatArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Float.class);
+        assertEquals((double) 0, (double) m.invokeExact((Float) null), 0.0);
+    }
+
+    @Test
+    public void nullDoubleArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Double.class);
+        assertEquals(false, (boolean) m.invokeExact((Double) null));
+    }
+
+    @Test
+    public void nullDoubleArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Double.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Double) null));
+    }
+
+    @Test
+    public void nullDoubleArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Double.class);
+        assertEquals((char) 0, (char) m.invokeExact((Double) null));
+    }
+
+    @Test
+    public void nullDoubleArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Double.class);
+        assertEquals((short) 0, (short) m.invokeExact((Double) null));
+    }
+
+    @Test
+    public void nullDoubleArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Double.class);
+        assertEquals((int) 0, (int) m.invokeExact((Double) null));
+    }
+
+    @Test
+    public void nullDoubleArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Double.class);
+        assertEquals((long) 0, (long) m.invokeExact((Double) null));
+    }
+
+    @Test
+    public void nullDoubleArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Double.class);
+        assertEquals((float) 0, (float) m.invokeExact((Double) null), 0.0);
+    }
+
+    @Test
+    public void nullDoubleArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Double.class);
+        assertEquals((double) 0, (double) m.invokeExact((Double) null), 0.0);
+    }
+
+    @Test
+    public void nullObjectArgumentToZ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(boolean.class, Object.class);
+        assertEquals(false, (boolean) m.invokeExact((Object) null));
+    }
+
+    @Test
+    public void nullObjectArgumentToB() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(byte.class, Object.class);
+        assertEquals((byte) 0, (byte) m.invokeExact((Object) null));
+    }
+
+    @Test
+    public void nullObjectArgumentToC() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(char.class, Object.class);
+        assertEquals((char) 0, (char) m.invokeExact((Object) null));
+    }
+
+    @Test
+    public void nullObjectArgumentToS() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(short.class, Object.class);
+        assertEquals((short) 0, (short) m.invokeExact((Object) null));
+    }
+
+    @Test
+    public void nullObjectArgumentToI() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(int.class, Object.class);
+        assertEquals((int) 0, (int) m.invokeExact((Object) null));
+    }
+
+    @Test
+    public void nullObjectArgumentToJ() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(long.class, Object.class);
+        assertEquals((long) 0, (long) m.invokeExact((Object) null));
+    }
+
+    @Test
+    public void nullObjectArgumentToF() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(float.class, Object.class);
+        assertEquals((float) 0, (float) m.invokeExact((Object) null), 0.0);
+    }
+
+    @Test
+    public void nullObjectArgumentToD() throws Throwable {
+        MethodHandle m = explicitCastArgumentToIdentity(double.class, Object.class);
+        assertEquals((double) 0, (double) m.invokeExact((Object) null), 0.0);
+    }
+
+    //
+    // Explicit casting of null valued return values to primitive type values
+    // (zero/false).
+    //
+    @Test
+    public void returnValueNullBooleanToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Boolean.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullBooleanToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Boolean.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullBooleanToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Boolean.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullBooleanToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Boolean.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullBooleanToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Boolean.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullBooleanToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Boolean.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullBooleanToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Boolean.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullBooleanToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Boolean.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullByteToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Byte.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullByteToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Byte.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullByteToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Byte.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullByteToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Byte.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullByteToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Byte.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullByteToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Byte.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullByteToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Byte.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullByteToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Byte.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullCharacterToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Character.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullCharacterToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Character.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullCharacterToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Character.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullCharacterToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Character.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullCharacterToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Character.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullCharacterToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Character.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullCharacterToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Character.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullCharacterToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Character.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullShortToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Short.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullShortToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Short.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullShortToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Short.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullShortToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Short.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullShortToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Short.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullShortToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Short.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullShortToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Short.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullShortToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Short.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullIntegerToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Integer.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullIntegerToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Integer.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullIntegerToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Integer.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullIntegerToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Integer.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullIntegerToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Integer.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullIntegerToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Integer.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullIntegerToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Integer.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullIntegerToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Integer.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullLongToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Long.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullLongToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Long.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullLongToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Long.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullLongToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Long.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullLongToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Long.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullLongToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Long.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullLongToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Long.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullLongToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Long.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullFloatToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Float.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullFloatToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Float.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullFloatToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Float.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullFloatToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Float.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullFloatToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Float.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullFloatToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Float.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullFloatToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Float.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullFloatToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Float.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullDoubleToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Double.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullDoubleToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Double.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullDoubleToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Double.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullDoubleToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Double.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullDoubleToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Double.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullDoubleToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Double.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullDoubleToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Double.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullDoubleToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Double.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullObjectToZ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Object.class, boolean.class);
+        assertEquals(false, (boolean) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullObjectToB() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Object.class, byte.class);
+        assertEquals((byte) 0, (byte) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullObjectToC() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Object.class, char.class);
+        assertEquals((char) 0, (char) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullObjectToS() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Object.class, short.class);
+        assertEquals((short) 0, (short) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullObjectToI() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Object.class, int.class);
+        assertEquals((int) 0, (int) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullObjectToJ() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Object.class, long.class);
+        assertEquals((long) 0, (long) m.invokeExact());
+    }
+
+    @Test
+    public void returnValueNullObjectToF() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Object.class, float.class);
+        assertEquals((float) 0, (float) m.invokeExact(), 0.0);
+    }
+
+    @Test
+    public void returnValueNullObjectToD() throws Throwable
+    {
+        MethodHandle m = nullConstantExplicitCastToPrimitive(Object.class, double.class);
+        assertEquals((double) 0, (double) m.invokeExact(), 0.0);
+    }
+
+    //
+    // Check asType() behaviour of void return value cast to primitives yields
+    // zero/false/null.
+    //
+    @Test
+    public void testVoidReturnToZ() throws Throwable {
+        assertFalse((boolean) explicitCastVoidReturnValue(boolean.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToB() throws Throwable {
+        assertEquals((byte) 0, (byte) explicitCastVoidReturnValue(byte.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToC() throws Throwable {
+        assertEquals((char) 0, (char) explicitCastVoidReturnValue(char.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToS() throws Throwable {
+        assertEquals((short) 0, (short) explicitCastVoidReturnValue(short.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToI() throws Throwable {
+        assertEquals((int) 0, (int) explicitCastVoidReturnValue(int.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToJ() throws Throwable {
+        assertEquals((long) 0, (long) explicitCastVoidReturnValue(long.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToF() throws Throwable {
+        assertEquals((float) 0, (float) explicitCastVoidReturnValue(float.class).invokeExact(), 0.0);
+    }
+
+    @Test
+    public void testVoidReturnToD() throws Throwable {
+        assertEquals((double) 0, (double) explicitCastVoidReturnValue(double.class).invokeExact(), 0.0);
+    }
+
+    @Test
+    public void testVoidReturnToBoolean() throws Throwable {
+        assertNull((Boolean) explicitCastVoidReturnValue(Boolean.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToByte() throws Throwable {
+        assertNull((Byte) explicitCastVoidReturnValue(Byte.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToCharacter() throws Throwable {
+        assertNull((Character) explicitCastVoidReturnValue(Character.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToShort() throws Throwable {
+        assertNull((Short) explicitCastVoidReturnValue(Short.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToInteger() throws Throwable {
+        assertNull((Integer) explicitCastVoidReturnValue(Integer.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToLong() throws Throwable {
+        assertNull((Long) explicitCastVoidReturnValue(Long.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToFloat() throws Throwable {
+        assertNull((Float) explicitCastVoidReturnValue(Float.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToDouble() throws Throwable {
+        assertNull((Double) explicitCastVoidReturnValue(Double.class).invokeExact());
+    }
+
+    @Test
+    public void testVoidReturnToObject() throws Throwable {
+        assertNull((Object) explicitCastVoidReturnValue(Object.class).invokeExact());
+    }
+
+    //
+    // Check asType() behaviour of returning a value cast to void.
+    //
+    @Test
+    public void testReturnZToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(boolean.class, void.class);
+        m.invokeExact((boolean) BOOLEAN_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnBToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(byte.class, void.class);
+        m.invokeExact((byte) BYTE_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnCToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(char.class, void.class);
+        m.invokeExact((char) CHARACTER_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnSToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(short.class, void.class);
+        m.invokeExact((short) SHORT_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnIToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(int.class, void.class);
+        m.invokeExact((int) INTEGER_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnJToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(long.class, void.class);
+        m.invokeExact((long) LONG_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnFToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(float.class, void.class);
+        m.invokeExact((float) FLOAT_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnDToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(double.class, void.class);
+        m.invokeExact((double) DOUBLE_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnBooleanToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(Boolean.class, void.class);
+        m.invokeExact((Boolean) BOOLEAN_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnByteToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(Byte.class, void.class);
+        m.invokeExact((Byte) BYTE_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnCharacterToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(Character.class, void.class);
+        m.invokeExact((Character) CHARACTER_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnShortToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(Short.class, void.class);
+        m.invokeExact((Short) SHORT_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnIntegerToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(Integer.class, void.class);
+        m.invokeExact((Integer) INTEGER_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnLongToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(Long.class, void.class);
+        m.invokeExact((Long) LONG_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnFloatToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(Float.class, void.class);
+        m.invokeExact((Float) FLOAT_VALUES[0]);
+    }
+
+    @Test
+    public void testReturnDoubleToVoid() throws Throwable {
+        MethodHandle m = explicitCastReturnValueFromIdentity(Double.class, void.class);
+        m.invokeExact((Double) DOUBLE_VALUES[0]);
+    }
+
+}
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
index 5866ae4..a8cfa24 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
@@ -1214,7 +1214,7 @@
 
         Object ret = handle.invokeWithArguments(new Object[]{"a", "b", "c"});
         assertEquals(42, (int) ret);
-        ret = handle.invokeWithArguments(new String[]{"a", "b", "c"});
+        ret = handle.invokeWithArguments((Object[]) new String[]{"a", "b", "c"});
         assertEquals(42, (int) ret);
 
         // Also test the versions that take a List<?> instead of an array.
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
index fc18ab8..8e08a59 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
@@ -29,6 +29,7 @@
 import java.lang.reflect.Method;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.util.function.Consumer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -299,6 +300,18 @@
         public static final Lookup lookup = MethodHandles.lookup();
     }
 
+    public interface F {
+        public default void callInner(Consumer<Class<?>> c) {
+            c.accept(F.class);
+        }
+    }
+
+    public class G implements F {
+        public void callInner(Consumer<Class<?>> c) {
+            c.accept(G.class);
+        }
+    }
+
     public void testfindSpecial_invokeSuperBehaviour() throws Throwable {
         // This is equivalent to an invoke-super instruction where the referrer
         // is B.class.
@@ -364,6 +377,41 @@
         } catch (NoSuchMethodException e) {}
     }
 
+    public void testfindSpecial_invokeSuperInterfaceBehaviour() throws Throwable {
+        // Check interface invoke super on unrelated lookup (with some private access).
+        Class<?>[] res = new Class<?>[2];
+        MethodHandle mh = MethodHandles.lookup().findSpecial(F.class /* refC */, "callInner",
+                  MethodType.methodType(void.class, Consumer.class), G.class /* specialCaller */);
+        G g = new G();
+        Consumer<Class<?>> oc = (Class<?> c) -> { res[0] = c; };
+        mh.invokeExact(g, oc);
+        g.callInner((Class<?> c) -> { res[1] = c; });
+        // Make sure the method-handle calls the default implementatoin
+        assertTrue(res[0] == F.class);
+        // Make sure the normal one works as we expect.
+        assertTrue(res[1] == G.class);
+
+        // Check findSpecial always fails if the lookup has only public access
+        try {
+          MethodHandles.publicLookup().findSpecial(F.class /* refC */, "callInner",
+                  MethodType.methodType(void.class, Consumer.class), G.class /* specialCaller */);
+          fail();
+        } catch (IllegalAccessException e) {}
+
+        // Check doing invokeSpecial on abstract interface methods gets appropriate errors. We
+        // expect it to throw an IllegalAccessError.
+        MethodHandle mh2 =
+            MethodHandles.lookup().findSpecial(
+                    Foo.class /* refC */,
+                    "foo",
+                    MethodType.methodType(String.class),
+                    Bar.class /* specialCaller */);
+        try {
+          mh2.invoke(new BarImpl());
+          fail();
+        } catch (IllegalAccessException e) {}
+    }
+
     public void testfindSpecial_invokeDirectBehaviour() throws Throwable {
         D dInstance = new D();
 
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
index f833840..0c4d18b 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodTypeTest.java
@@ -96,7 +96,7 @@
         }
 
         try {
-            MethodType.methodType(int.class, String.class, null);
+            MethodType.methodType(int.class, String.class, (Class<?>) null);
             fail();
         } catch (NullPointerException expected) {
         }
@@ -334,7 +334,7 @@
         }
 
         try {
-            mt.insertParameterTypes(1, Arrays.asList(null));
+            mt.insertParameterTypes(1, Arrays.asList((Class<?>) null));
             fail();
         } catch (NullPointerException expected) {
         }
@@ -404,7 +404,7 @@
         }
 
         try {
-            mt.appendParameterTypes(Arrays.asList(null));
+            mt.appendParameterTypes(Arrays.asList((Class<?>) null));
             fail();
         } catch (NullPointerException expected) {
         }
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java
index 0e40644..a0b7066 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java
@@ -15,7 +15,6 @@
  */
 package libcore.java.lang.reflect.annotations;
 
-import java.lang.annotation.Annotation;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
@@ -23,19 +22,12 @@
 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB;
 
 import libcore.junit.junit3.TestCaseWithRules;
-import libcore.junit.util.SwitchTargetSdkVersionRule;
-import libcore.junit.util.SwitchTargetSdkVersionRule.TargetSdkVersion;
-import org.junit.Rule;
-import org.junit.rules.TestRule;
 
 /**
  * Tests for the behavior of Annotation instances at runtime.
  */
 public class AnnotationsTest extends TestCaseWithRules {
 
-    @Rule
-    public TestRule switchTargetSdkVersionRule = SwitchTargetSdkVersionRule.getInstance();
-
     enum Breakfast { WAFFLES, PANCAKES }
 
     @Retention(RetentionPolicy.RUNTIME)
@@ -80,39 +72,4 @@
     private static Object defaultValue(String name) throws NoSuchMethodException {
         return HasDefaultsAnnotation.class.getMethod(name).getDefaultValue();
     }
-
-    @Retention(RetentionPolicy.CLASS)
-    public @interface ClassRetentionAnnotation {}
-
-    @Retention(RetentionPolicy.RUNTIME)
-    public @interface RuntimeRetentionAnnotation {}
-
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SourceRetentionAnnotation {}
-
-    @ClassRetentionAnnotation @RuntimeRetentionAnnotation @SourceRetentionAnnotation
-    public static class RetentionAnnotations {}
-
-    // b/29500035
-    @TargetSdkVersion(23)
-    public void testRetentionPolicy_targetSdkVersion_23() {
-        // Test pre-N behavior
-        Annotation classRetentionAnnotation =
-                RetentionAnnotations.class.getAnnotation(ClassRetentionAnnotation.class);
-        assertNotNull(classRetentionAnnotation);
-    }
-
-    // b/29500035
-    @TargetSdkVersion(24)
-    public void testRetentionPolicy_targetSdkVersion_24() {
-        // Test N and later behavior
-        Annotation classRetentionAnnotation =
-            RetentionAnnotations.class.getAnnotation(ClassRetentionAnnotation.class);
-        assertNull(classRetentionAnnotation);
-    }
-
-    public void testRetentionPolicy() {
-        assertNotNull(RetentionAnnotations.class.getAnnotation(RuntimeRetentionAnnotation.class));
-        assertNull(RetentionAnnotations.class.getAnnotation(SourceRetentionAnnotation.class));
-    }
 }
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/RetentionPolicyTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/RetentionPolicyTest.java
new file mode 100644
index 0000000..5403910
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/RetentionPolicyTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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 libcore.java.lang.reflect.annotations;
+
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import libcore.io.Streams;
+import libcore.junit.util.SwitchTargetSdkVersionRule;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Runs tests against classes loaded from the annotations-test.jar.
+ *
+ * <p>The annotated classes are built separately in order to ensure class-retention annotations are
+ * kept which is no longer the default behavior of the platform dexer.
+ */
+@RunWith(JUnit4.class)
+public class RetentionPolicyTest {
+
+    @Rule
+    public TestRule switchTargetSdkVersionRule = SwitchTargetSdkVersionRule.getInstance();
+
+    @ClassRule
+    public static TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+    /**
+     * Static reference to the classloader created for annotations-test.jar.
+     *
+     * <p>This is created statically as it is expensive to create.
+     */
+    private static ClassLoader classLoader;
+
+    @BeforeClass
+    public static void openClassLoader() throws IOException {
+        ClassLoader myClassLoader = RetentionPolicyTest.class.getClassLoader();
+        assertNotNull(myClassLoader);
+
+        // Load the annotated class (and annotation classes) from the annotations-test.jar.
+        File jarFile = new File(temporaryFolder.getRoot(), "annotations-test.jar");
+        try (InputStream in = myClassLoader.getResourceAsStream("annotations-test.jar");
+             OutputStream out = new FileOutputStream(jarFile)) {
+            Streams.copy(in, out);
+        }
+
+        classLoader = new PathClassLoader(jarFile.getAbsolutePath(), myClassLoader);
+    }
+
+    @AfterClass
+    public static void closeClassLoader() {
+        // Null the reference to allow it to be garbage collected if necessary.
+        classLoader = null;
+    }
+
+    @SuppressWarnings("unchecked")
+    private Class<? extends Annotation> getAnnotationClass(String name) throws Exception {
+        return (Class<? extends Annotation>) classLoader.loadClass(name);
+    }
+
+    private Class<?> getRetentionAnnotationsClass() throws Exception {
+        return classLoader.loadClass("libcore.tests.annotations.RetentionAnnotations");
+    }
+
+    // b/29500035
+    @SwitchTargetSdkVersionRule.TargetSdkVersion(23)
+    @Test
+    public void testRetentionPolicy_targetSdkVersion_23() throws Exception {
+        Class<? extends Annotation> annotationClass = getAnnotationClass(
+                "libcore.tests.annotations.ClassRetentionAnnotation");
+        // Test pre-N behavior
+        Annotation classRetentionAnnotation =
+                getRetentionAnnotationsClass().getAnnotation(annotationClass);
+        assertNotNull(classRetentionAnnotation);
+    }
+
+    // b/29500035
+    @SwitchTargetSdkVersionRule.TargetSdkVersion(24)
+    @Test
+    public void testRetentionPolicy_targetSdkVersion_24() throws Exception {
+        // Test N and later behavior
+        Class<? extends Annotation> annotationClass = getAnnotationClass(
+                "libcore.tests.annotations.ClassRetentionAnnotation");
+        Annotation classRetentionAnnotation =
+                getRetentionAnnotationsClass().getAnnotation(annotationClass);
+        assertNull(classRetentionAnnotation);
+    }
+
+    @Test
+    public void testRetentionPolicy() throws Exception {
+        Class<?> retentionAnnotationsClass = getRetentionAnnotationsClass();
+        assertNotNull(retentionAnnotationsClass.getAnnotation(getAnnotationClass(
+                "libcore.tests.annotations.RuntimeRetentionAnnotation")));
+        assertNull(retentionAnnotationsClass.getAnnotation(getAnnotationClass(
+                "libcore.tests.annotations.SourceRetentionAnnotation")));
+    }
+}
diff --git a/luni/src/test/java/libcore/java/math/BigIntegerTest.java b/luni/src/test/java/libcore/java/math/BigIntegerTest.java
index 80041c2..6c1d11e 100644
--- a/luni/src/test/java/libcore/java/math/BigIntegerTest.java
+++ b/luni/src/test/java/libcore/java/math/BigIntegerTest.java
@@ -195,4 +195,35 @@
         assertEquals("-9223372036854775808", negV.toString());
         assertEquals( "9223372036854775808", posV.toString());
     }
+
+    private void try_gcd_variants(BigInteger arg1, BigInteger arg2, BigInteger result)
+            throws Exception {
+        // Test both argument orders, and all 4 combinations of negation.
+        assertEquals(arg1.gcd(arg2), result);
+        assertEquals(arg2.gcd(arg1), result);
+        assertEquals(arg1.negate().gcd(arg2), result);
+        assertEquals(arg2.gcd(arg1.negate()), result);
+        assertEquals(arg1.gcd(arg2.negate()), result);
+        assertEquals(arg2.negate().gcd(arg1), result);
+        assertEquals(arg1.negate().gcd(arg2.negate()), result);
+        assertEquals(arg2.negate().gcd(arg1.negate()), result);
+    }
+
+    /**
+     * Test gcd(), with emphasis on arguments of very different size.
+     */
+    public void test_gcd() throws Exception {
+        BigInteger two = BigInteger.valueOf(2); // BigInteger.TWO added in OpenJDK 9
+        BigInteger three = BigInteger.valueOf(3);
+        try_gcd_variants(BigInteger.TEN, two, two);
+        try_gcd_variants(BigInteger.TEN, BigInteger.TEN, BigInteger.TEN);
+        try_gcd_variants(BigInteger.TEN, BigInteger.ZERO, BigInteger.TEN);
+        try_gcd_variants(BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO);
+        BigInteger large = three.shiftLeft(500);
+        try_gcd_variants(large, three, three);
+        try_gcd_variants(large, large, large);
+        try_gcd_variants(large, two, two);
+        try_gcd_variants(large, BigInteger.valueOf(5), BigInteger.ONE);
+        try_gcd_variants(large, BigInteger.ZERO, large);
+    }
 }
diff --git a/luni/src/test/java/libcore/java/net/AuditInputStream.java b/luni/src/test/java/libcore/java/net/AuditInputStream.java
new file mode 100644
index 0000000..2a76cac
--- /dev/null
+++ b/luni/src/test/java/libcore/java/net/AuditInputStream.java
@@ -0,0 +1,61 @@
+/*
+ * 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 libcore.java.net;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Objects;
+
+/**
+ * An {@link InputStream} that reads from a delegate and also writes an audit log of all data
+ * that was read to the given {@code audit} {@link OutputStream}.
+ */
+class AuditInputStream extends FilterInputStream {
+    private final OutputStream audit;
+
+    protected AuditInputStream(InputStream in, OutputStream audit) {
+        super(in);
+        this.audit = Objects.requireNonNull(audit);
+    }
+
+    @Override
+    public int read() throws IOException {
+        int result = super.read();
+        audit.write(result);
+        return result;
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException {
+        int result = super.read(b);
+        if (result > 0) {
+            audit.write(b, 0, result);
+        }
+        return result;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        int result = super.read(b, off, len);
+        if (result > 0) {
+            audit.write(b, off, result);
+        }
+        return result;
+    }
+}
diff --git a/luni/src/test/java/libcore/java/net/InetAddressTest.java b/luni/src/test/java/libcore/java/net/InetAddressTest.java
index 307cd1d..6bbfe01 100644
--- a/luni/src/test/java/libcore/java/net/InetAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetAddressTest.java
@@ -36,6 +36,7 @@
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
 import libcore.libcore.util.SerializationTester;
+import libcore.net.InetAddressUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -281,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));
@@ -312,8 +320,12 @@
     public void test_getByName_invalid(String invalid) throws Exception {
         try {
             InetAddress.getByName(invalid);
-            fail("Invalid IP address incorrectly recognized as valid: "
-                + invalid);
+            String msg = "Invalid IP address incorrectly recognized as valid: \"" + invalid + "\"";
+            if (InetAddressUtils.parseNumericAddressNoThrowStripOptionalBrackets(invalid) == null) {
+                msg += " (it was probably unexpectedly resolved by this network's DNS)";
+            }
+            msg += ".";
+            fail(msg);
         } catch (UnknownHostException expected) {
         }
 
diff --git a/luni/src/test/java/libcore/java/net/NetworkInterfaceTest.java b/luni/src/test/java/libcore/java/net/NetworkInterfaceTest.java
index 51c8b04..f0f79ad 100644
--- a/luni/src/test/java/libcore/java/net/NetworkInterfaceTest.java
+++ b/luni/src/test/java/libcore/java/net/NetworkInterfaceTest.java
@@ -18,6 +18,7 @@
 
 import junit.framework.TestCase;
 
+import android.system.StructIfaddrs;
 import java.io.BufferedReader;
 import java.io.FileDescriptor;
 import java.io.InputStreamReader;
@@ -29,6 +30,7 @@
 import java.net.MulticastSocket;
 import java.net.NetworkInterface;
 import java.net.SocketException;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
@@ -100,7 +102,6 @@
             }
             // Ethernet
             if (isEthernet(nif.getName())) {
-                assertEquals(6, nif.getHardwareAddress().length);
                 for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
                     if (ia.getAddress() instanceof Inet4Address) {
                         assertNotNull(ia.getBroadcast());
@@ -110,6 +111,13 @@
         }
     }
 
+    public void testGetHardwareAddress_returnsNull() throws Exception {
+        // Hardware addresses should be unavailable to non-system apps.
+        for (NetworkInterface nif : Collections.list(getNetworkInterfaces())) {
+            assertNull(nif.getHardwareAddress());
+        }
+    }
+
     public void testLoopback() throws Exception {
         NetworkInterface lo = NetworkInterface.getByName("lo");
         assertNull(lo.getHardwareAddress());
@@ -201,31 +209,16 @@
         } catch(SocketException expected) {}
     }
 
-    // b/29243557
-    public void testGetNetworkInterfaces() throws Exception {
-        // Check that the interfaces we get from #getNetworkInterfaces agrees with IP-LINK(8).
+    public void testGetNetworkInterfaces_matchesIfaddrs() throws Exception {
+        StructIfaddrs[] ifaddrs = Libcore.os.getifaddrs();
+        Set<String> ifaddrsNames = new HashSet<>();
+        Arrays.asList(ifaddrs).forEach(ifa -> ifaddrsNames.add(ifa.ifa_name));
 
-        // Parse output of ip link.
-        String[] cmd = { "ip", "link" };
-        Process proc = Runtime.getRuntime().exec(cmd);
-        BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
-        Set<String> expectedNiNames = new HashSet<>();
-        for (String s; (s = stdInput.readLine()) != null; ) {
-            String[] split = s.split(": |@");
-            try {
-                if (split.length > 2) {
-                    expectedNiNames.add(split[1]);
-                }
-            } catch (NumberFormatException e) {
-                // Skip this line.
-            }
-        }
-
-        Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();
+        List<NetworkInterface> nifs = Collections.list(NetworkInterface.getNetworkInterfaces());
         Set<String> actualNiNames = new HashSet<>();
-        Collections.list(nifs).forEach(ni -> actualNiNames.add(ni.getName()));
+        nifs.forEach(ni -> actualNiNames.add(ni.getName()));
 
-        assertEquals(expectedNiNames, actualNiNames);
+        assertEquals(ifaddrsNames, actualNiNames);
     }
 
     // Calling getSubInterfaces on interfaces with no subinterface should not throw NPE.
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index 1574caf..ddd447a 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -16,17 +16,19 @@
 
 package libcore.java.net;
 
-import com.google.mockwebserver.Dispatcher;
-import com.google.mockwebserver.MockResponse;
-import com.google.mockwebserver.MockWebServer;
-import com.google.mockwebserver.RecordedRequest;
-import com.google.mockwebserver.SocketPolicy;
-
 import com.android.okhttp.AndroidShimResponseCache;
 import com.android.okhttp.internal.Platform;
 import com.android.okhttp.internal.tls.TrustRootIndex;
+import com.google.mockwebserver.Dispatcher;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.MockWebServer;
+import com.google.mockwebserver.QueueDispatcher;
+import com.google.mockwebserver.RecordedRequest;
+import com.google.mockwebserver.SocketPolicy;
 
-import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -57,6 +59,7 @@
 import java.net.URLConnection;
 import java.net.UnknownHostException;
 import java.nio.channels.SocketChannel;
+import java.nio.charset.StandardCharsets;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
@@ -86,8 +89,10 @@
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
+import libcore.content.type.MimeMap;
 import libcore.java.security.TestKeyStore;
 import libcore.javax.net.ssl.TestSSLContext;
+import libcore.testing.io.TestIoUtils;
 
 import static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_END;
 import static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_START;
@@ -95,23 +100,26 @@
 import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_INPUT_AT_END;
 import static com.google.mockwebserver.SocketPolicy.SHUTDOWN_OUTPUT_AT_END;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-public final class URLConnectionTest extends TestCase {
+public final class URLConnectionTest {
 
     private MockWebServer server;
     private AndroidShimResponseCache cache;
     private String hostName;
     private List<TestSSLContext> testSSLContextsToClose;
 
-    @Override protected void setUp() throws Exception {
-        super.setUp();
+    @Before public void setUp() throws Exception {
         server = new MockWebServer();
         hostName = server.getHostName();
         testSSLContextsToClose = new ArrayList<>();
     }
 
-    @Override protected void tearDown() throws Exception {
+    @After public void tearDown() throws Exception {
         ResponseCache.setDefault(null);
         Authenticator.setDefault(null);
         System.clearProperty("proxyHost");
@@ -129,10 +137,9 @@
         for (TestSSLContext testSSLContext : testSSLContextsToClose) {
             testSSLContext.close();
         }
-        super.tearDown();
     }
 
-    public void testRequestHeaderValidation() throws Exception {
+    @Test public void requestHeaderValidation() throws Exception {
         // Android became more strict after M about which characters were allowed in request header
         // names and values: previously almost anything was allowed if it didn't contain \0.
 
@@ -225,7 +232,7 @@
         return urlConnection.getRequestProperty("key");
     }
 
-    public void testRequestHeaders() throws IOException, InterruptedException {
+    @Test public void requestHeaders() throws IOException, InterruptedException {
         server.enqueue(new MockResponse());
         server.play();
 
@@ -288,7 +295,7 @@
         }
     }
 
-    public void testGetRequestPropertyReturnsLastValue() throws Exception {
+    @Test public void getRequestPropertyReturnsLastValue() throws Exception {
         server.play();
         HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection();
         urlConnection.addRequestProperty("A", "value1");
@@ -296,7 +303,7 @@
         assertEquals("value2", urlConnection.getRequestProperty("A"));
     }
 
-    public void testResponseHeaders() throws IOException, InterruptedException {
+    @Test public void responseHeaders() throws IOException, InterruptedException {
         server.enqueue(new MockResponse()
                 .setStatus("HTTP/1.0 200 Fantastic")
                 .addHeader("A: c")
@@ -331,24 +338,24 @@
         assertEquals("e", urlConnection.getHeaderField(2));
     }
 
-    public void testGetErrorStreamOnSuccessfulRequest() throws Exception {
+    @Test public void getErrorStreamOnSuccessfulRequest() throws Exception {
         server.enqueue(new MockResponse().setBody("A"));
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         assertNull(connection.getErrorStream());
     }
 
-    public void testGetErrorStreamOnUnsuccessfulRequest() throws Exception {
+    @Test public void getErrorStreamOnUnsuccessfulRequest() throws Exception {
         server.enqueue(new MockResponse().setResponseCode(404).setBody("A"));
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("A", readAscii(connection.getErrorStream(), Integer.MAX_VALUE));
+        assertEquals("A", readAscii(connection.getErrorStream()));
     }
 
     // Check that if we don't read to the end of a response, the next request on the
     // recycled connection doesn't get the unread tail of the first request's response.
     // http://code.google.com/p/android/issues/detail?id=2939
-    public void test_2939() throws Exception {
+    @Test public void bug2939() throws Exception {
         MockResponse response = new MockResponse().setChunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8);
 
         server.enqueue(response);
@@ -361,12 +368,12 @@
 
     // Check that we recognize a few basic mime types by extension.
     // http://code.google.com/p/android/issues/detail?id=10100
-    public void test_10100() throws Exception {
+    @Test public void bug10100() throws Exception {
         assertEquals("image/jpeg", URLConnection.guessContentTypeFromName("someFile.jpg"));
         assertEquals("application/pdf", URLConnection.guessContentTypeFromName("stuff.pdf"));
     }
 
-    public void testConnectionsArePooled() throws Exception {
+    @Test public void connectionsArePooled() throws Exception {
         MockResponse response = new MockResponse().setBody("ABCDEFGHIJKLMNOPQR");
 
         server.enqueue(response);
@@ -382,7 +389,7 @@
         assertEquals(2, server.takeRequest().getSequenceNumber());
     }
 
-    public void testChunkedConnectionsArePooled() throws Exception {
+    @Test public void chunkedConnectionsArePooled() throws Exception {
         MockResponse response = new MockResponse().setChunkedBody("ABCDEFGHIJKLMNOPQR", 5);
 
         server.enqueue(response);
@@ -402,24 +409,24 @@
      * Test that connections are added to the pool as soon as the response has
      * been consumed.
      */
-    public void testConnectionsArePooledWithoutExplicitDisconnect() throws Exception {
+    @Test public void connectionsArePooledWithoutExplicitDisconnect() throws Exception {
         server.enqueue(new MockResponse().setBody("ABC"));
         server.enqueue(new MockResponse().setBody("DEF"));
         server.play();
 
         URLConnection connection1 = server.getUrl("/").openConnection();
-        assertEquals("ABC", readAscii(connection1.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("ABC", readAscii(connection1.getInputStream()));
         assertEquals(0, server.takeRequest().getSequenceNumber());
         URLConnection connection2 = server.getUrl("/").openConnection();
-        assertEquals("DEF", readAscii(connection2.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("DEF", readAscii(connection2.getInputStream()));
         assertEquals(1, server.takeRequest().getSequenceNumber());
     }
 
-    public void testServerClosesSocket() throws Exception {
+    @Test public void serverClosesSocket() throws Exception {
         testServerClosesSocket(DISCONNECT_AT_END);
     }
 
-    public void testServerShutdownInput() throws Exception {
+    @Test public void serverShutdownInput() throws Exception {
         testServerClosesSocket(SHUTDOWN_INPUT_AT_END);
     }
 
@@ -437,7 +444,7 @@
         assertEquals(0, server.takeRequest().getSequenceNumber());
     }
 
-    public void testServerShutdownOutput() throws Exception {
+    @Test public void serverShutdownOutput() throws Exception {
         // This test causes MockWebServer to log a "connection failed" stack trace
 
         // Setting the server workerThreads to 1 ensures the responses are generated in the order
@@ -461,27 +468,27 @@
 
     enum WriteKind { BYTE_BY_BYTE, SMALL_BUFFERS, LARGE_BUFFERS }
 
-    public void test_chunkedUpload_byteByByte() throws Exception {
+    @Test public void chunkedUpload_byteByByte() throws Exception {
         doUpload(TransferKind.CHUNKED, WriteKind.BYTE_BY_BYTE);
     }
 
-    public void test_chunkedUpload_smallBuffers() throws Exception {
+    @Test public void chunkedUpload_smallBuffers() throws Exception {
         doUpload(TransferKind.CHUNKED, WriteKind.SMALL_BUFFERS);
     }
 
-    public void test_chunkedUpload_largeBuffers() throws Exception {
+    @Test public void chunkedUpload_largeBuffers() throws Exception {
         doUpload(TransferKind.CHUNKED, WriteKind.LARGE_BUFFERS);
     }
 
-    public void test_fixedLengthUpload_byteByByte() throws Exception {
+    @Test public void fixedLengthUpload_byteByByte() throws Exception {
         doUpload(TransferKind.FIXED_LENGTH, WriteKind.BYTE_BY_BYTE);
     }
 
-    public void test_fixedLengthUpload_smallBuffers() throws Exception {
+    @Test public void fixedLengthUpload_smallBuffers() throws Exception {
         doUpload(TransferKind.FIXED_LENGTH, WriteKind.SMALL_BUFFERS);
     }
 
-    public void test_fixedLengthUpload_largeBuffers() throws Exception {
+    @Test public void fixedLengthUpload_largeBuffers() throws Exception {
         doUpload(TransferKind.FIXED_LENGTH, WriteKind.LARGE_BUFFERS);
     }
 
@@ -522,7 +529,7 @@
         }
     }
 
-    public void testGetResponseCodeNoResponseBody() throws Exception {
+    @Test public void getResponseCodeNoResponseBody() throws Exception {
         server.enqueue(new MockResponse()
                 .addHeader("abc: def"));
         server.play();
@@ -539,7 +546,11 @@
         }
     }
 
-    public void testConnectViaHttps() throws IOException, InterruptedException {
+    @Test public void connectViaHttps() throws IOException, InterruptedException {
+        checkConnectViaHttps();
+    }
+
+    private void checkConnectViaHttps() throws IOException, InterruptedException {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
 
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
@@ -556,7 +567,7 @@
         assertEquals("TLSv1.2", request.getSslProtocol());
     }
 
-    public void testConnectViaHttpsReusingConnections() throws IOException, InterruptedException {
+    @Test public void connectViaHttpsReusingConnections() throws IOException, InterruptedException {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         SSLSocketFactory clientSocketFactory = testSSLContext.clientContext.getSocketFactory();
 
@@ -577,7 +588,7 @@
         assertEquals(1, server.takeRequest().getSequenceNumber());
     }
 
-    public void testConnectViaHttpsReusingConnectionsDifferentFactories()
+    @Test public void connectViaHttpsReusingConnectionsDifferentFactories()
             throws IOException, InterruptedException {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
 
@@ -593,7 +604,7 @@
 
         connection = (HttpsURLConnection) server.getUrl("/").openConnection();
         try {
-            readAscii(connection.getInputStream(), Integer.MAX_VALUE);
+            readAscii(connection.getInputStream());
             fail("without an SSL socket factory, the connection should fail");
         } catch (SSLException expected) {
         }
@@ -604,7 +615,7 @@
      *
      * http://code.google.com/p/android/issues/detail?id=13178
      */
-    public void testConnectViaHttpsToUntrustedServer() throws IOException, InterruptedException {
+    @Test public void connectViaHttpsToUntrustedServer() throws IOException, InterruptedException {
         TestSSLContext testSSLContext = TestSSLContext.create(TestKeyStore.getClientCA2(),
                                                               TestKeyStore.getServer());
         testSSLContextsToClose.add(testSSLContext);
@@ -624,29 +635,29 @@
         assertEquals(0, server.getRequestCount());
     }
 
-    public void testConnectViaProxy_emptyPath() throws Exception {
+    @Test public void connectViaProxy_emptyPath() throws Exception {
         // expected normalization http://android -> http://android/ per b/30107354
         checkConnectViaProxy(
                 ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY, "http://android.com",
                 "http://android.com/", "android.com");
     }
 
-    public void testConnectViaProxy_complexUrlWithNoPath() throws Exception {
+    @Test public void connectViaProxy_complexUrlWithNoPath() throws Exception {
         checkConnectViaProxy(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY,
                 "http://android.com:8080?height=100&width=42",
                 "http://android.com:8080/?height=100&width=42",
                 "android.com:8080");
     }
 
-    public void testConnectViaProxyUsingProxyArg() throws Exception {
+    @Test public void connectViaProxyUsingProxyArg() throws Exception {
         checkConnectViaProxy(ProxyConfig.CREATE_ARG);
     }
 
-    public void testConnectViaProxyUsingProxySystemProperty() throws Exception {
+    @Test public void connectViaProxyUsingProxySystemProperty() throws Exception {
         checkConnectViaProxy(ProxyConfig.PROXY_SYSTEM_PROPERTY);
     }
 
-    public void testConnectViaProxyUsingHttpProxySystemProperty() throws Exception {
+    @Test public void connectViaProxyUsingHttpProxySystemProperty() throws Exception {
         checkConnectViaProxy(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY);
     }
 
@@ -670,7 +681,7 @@
         assertContains(request.getHeaders(), "Host: " + expectedHost);
     }
 
-    public void testContentDisagreesWithContentLengthHeader() throws IOException {
+    @Test public void contentDisagreesWithContentLengthHeader() throws IOException {
         server.enqueue(new MockResponse()
                 .setBody("abc\r\nYOU SHOULD NOT SEE THIS")
                 .clearHeaders()
@@ -680,7 +691,7 @@
         assertContent("abc", server.getUrl("/").openConnection());
     }
 
-    public void testContentDisagreesWithChunkedHeader() throws IOException {
+    @Test public void contentDisagreesWithChunkedHeader() throws IOException {
         MockResponse mockResponse = new MockResponse();
         mockResponse.setChunkedBody("abc", 3);
         ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
@@ -696,16 +707,16 @@
         assertContent("abc", server.getUrl("/").openConnection());
     }
 
-    public void testConnectViaHttpProxyToHttpsUsingProxyArgWithNoProxy() throws Exception {
-        testConnectViaDirectProxyToHttps(ProxyConfig.NO_PROXY);
+    @Test public void connectViaHttpProxyToHttpsUsingProxyArgWithNoProxy() throws Exception {
+        checkConnectViaDirectProxyToHttps(ProxyConfig.NO_PROXY);
     }
 
-    public void testConnectViaHttpProxyToHttpsUsingHttpProxySystemProperty() throws Exception {
+    @Test public void connectViaHttpProxyToHttpsUsingHttpProxySystemProperty() throws Exception {
         // https should not use http proxy
-        testConnectViaDirectProxyToHttps(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY);
+        checkConnectViaDirectProxyToHttps(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY);
     }
 
-    private void testConnectViaDirectProxyToHttps(ProxyConfig proxyConfig) throws Exception {
+    private void checkConnectViaDirectProxyToHttps(ProxyConfig proxyConfig) throws Exception {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
 
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
@@ -723,27 +734,27 @@
     }
 
 
-    public void testConnectViaHttpProxyToHttpsUsingProxyArg() throws Exception {
-        testConnectViaHttpProxyToHttps(ProxyConfig.CREATE_ARG);
+    @Test public void connectViaHttpProxyToHttpsUsingProxyArg() throws Exception {
+        checkConnectViaHttpProxyToHttps(ProxyConfig.CREATE_ARG);
     }
 
     /**
      * We weren't honoring all of the appropriate proxy system properties when
      * connecting via HTTPS. http://b/3097518
      */
-    public void testConnectViaHttpProxyToHttpsUsingProxySystemProperty() throws Exception {
-        testConnectViaHttpProxyToHttps(ProxyConfig.PROXY_SYSTEM_PROPERTY);
+    @Test public void connectViaHttpProxyToHttpsUsingProxySystemProperty() throws Exception {
+        checkConnectViaHttpProxyToHttps(ProxyConfig.PROXY_SYSTEM_PROPERTY);
     }
 
-    public void testConnectViaHttpProxyToHttpsUsingHttpsProxySystemProperty() throws Exception {
-        testConnectViaHttpProxyToHttps(ProxyConfig.HTTPS_PROXY_SYSTEM_PROPERTY);
+    @Test public void connectViaHttpProxyToHttpsUsingHttpsProxySystemProperty() throws Exception {
+        checkConnectViaHttpProxyToHttps(ProxyConfig.HTTPS_PROXY_SYSTEM_PROPERTY);
     }
 
     /**
      * We were verifying the wrong hostname when connecting to an HTTPS site
      * through a proxy. http://b/3097277
      */
-    private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exception {
+    private void checkConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exception {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
 
@@ -776,7 +787,8 @@
     /**
      * Tolerate bad https proxy response when using HttpResponseCache. http://b/6754912
      */
-    public void testConnectViaHttpProxyToHttpsUsingBadProxyAndHttpResponseCache() throws Exception {
+    @Test public void connectViaHttpProxyToHttpsUsingBadProxyAndHttpResponseCache()
+            throws Exception {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
 
         initResponseCache();
@@ -817,7 +829,7 @@
      * Test Etag headers are returned correctly when a client-side cache is not installed.
      * https://code.google.com/p/android/issues/detail?id=108949
      */
-    public void testEtagHeaders_uncached() throws Exception {
+    @Test public void etagHeaders_uncached() throws Exception {
         final String etagValue1 = "686897696a7c876b7e";
         final String body1 = "Response with etag 1";
         final String etagValue2 = "686897696a7c876b7f";
@@ -854,32 +866,100 @@
         assertNull(request.getHeader("If-None-Match"));
     }
 
+    @Test public void getFileNameMap_null() {
+        assertThrowsNpe(() -> URLConnection.getFileNameMap().getContentTypeFor(null));
+        assertThrowsNpe(() -> URLConnection.guessContentTypeFromName(null));
+    }
+
+    private static void assertThrowsNpe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+
     /**
      * Checks that paths ending in '/' (directory listings) are identified as HTML.
      */
-    public void testGetFileNameMap_directory() {
+    @Test public void getFileNameMap_directory() {
         checkFileNameMap("text/html", "/directory/path/");
         checkFileNameMap("text/html", "http://example.com/path/");
+        checkFileNameMap("text/html", "http://example.com/path/#fragment");
     }
 
-    public void testGetFileNameMap_simple() {
+    @Test public void getFileNameMap_simple() {
         checkFileNameMap("text/plain", "example.txt");
         checkFileNameMap("text/plain", "example.com/file.txt");
     }
 
+    @Test public void getFileNameMap_compositeExtension() {
+        checkFileNameMap("text/plain", "example.html.txt"); // html.txt isn't known, but txt is
+        checkFileNameMap("application/x-font-pcf", "filename.pcf.Z"); // pcf.Z is known
+    }
+
+    @Test public void getFileNameMap_compositeExtension_customMimeMap() {
+        MimeMap testMimeMap = MimeMap.builder()
+                .put("text/html", "html")
+                .put("application/gzip", "gz")
+                .put("application/tar+gzip", "tar.gz")
+                .build();
+        MimeMap defaultMimeMap = MimeMap.getDefault();
+        MimeMap.setDefaultSupplier(() -> testMimeMap);
+        try {
+            checkFileNameMap("application/gzip", "filename.gz");
+            checkFileNameMap("application/gzip", "filename.foobar.gz");
+            checkFileNameMap("application/gzip", "filename.html.gz");
+            checkFileNameMap("application/tar+gzip", "filename.tar.gz"); // tar.gz is found
+        } finally {
+            MimeMap.setDefaultSupplier(() -> defaultMimeMap);
+        }
+    }
+
     /**
-     * Checks that the *last* dot is considered for determining a file extension.
+     * Checks that as long as there are no '.' or '/', a file name that matches
+     * a known extension is interpreted as that extension, as if it was preceded by ".".
      */
-    public void testGetFileNameMap_multipleDots() {
+    @Test public void getFileNameMap_plainExtension() {
+        checkFileNameMap("text/plain", "txt");
+        checkFileNameMap("text/plain", "txt#fragment");
+        checkFileNameMap(null, "example.com/txt");
+        checkFileNameMap(null, "example.com/txt#fragment");
+        checkFileNameMap(null, "example/txt");
+        checkFileNameMap(null, "http://example/txt#fragment");
+    }
+
+    /**
+     * Checks cases where there's a '.' in the fragment, path or as an earlier path
+     * of a file name (only the last '.' that is part of the filename should count).
+     */
+    @Test public void getFileNameMap_dotsInOtherPlaces() {
+        // '.' in path
         checkFileNameMap("text/html", "example.com/foo.txt/bar.html");
         checkFileNameMap("text/plain", "example.com/foo.html/bar.txt");
+        checkFileNameMap(null, "/path.txt/noextensionfound");
+
+        // '.' earlier in filename
         checkFileNameMap("text/plain", "example.html.txt");
+
+        // '.' in fragment
+        checkFileNameMap(null, "/path/noextensionfound#fragment.html");
+
+        // multiple additional dots that shouldn't count
+        checkFileNameMap("text/plain", "/path.html/foo/../readme.html.txt#fragment.html");
+    }
+
+    @Test public void getFileNameMap_multipleHashCharacters() {
+        // Based on RFC 3986, URLs can only contain a single '#' but android.net.Uri
+        // considers the fragment to start after the first, rather than the last, '#'.
+        // We check that FileNameMap cuts off after the first '#', consistent with Uri.
+        checkFileNameMap(null, "/path/noextensionfound#frag.txt#ment.html");
     }
 
     /**
      * Checks that fragments are stripped when determining file extension.
      */
-    public void testGetFileNameMap_fragment() {
+    @Test public void getFileNameMap_fragment() {
         checkFileNameMap("text/plain", "example.txt#fragment");
         checkFileNameMap("text/plain", "example.com/path/example.txt#fragment");
     }
@@ -889,7 +969,7 @@
      * of file type.
      * This matches RI behavior, but it'd be reasonable to change behavior here.
      */
-    public void testGetFileNameMap_queryParameter() {
+    @Test public void getFileNameMap_queryParameter() {
         checkFileNameMap(null, "example.txt?key=value");
         checkFileNameMap(null, "example.txt?key=value#fragment");
     }
@@ -908,7 +988,7 @@
      * data is unchanged.
      * https://code.google.com/p/android/issues/detail?id=108949
      */
-    public void testEtagHeaders_cachedWithServerHit() throws Exception {
+    @Test public void etagHeaders_cachedWithServerHit() throws Exception {
         final String etagValue = "686897696a7c876b7e";
         final String body = "Response with etag";
 
@@ -951,7 +1031,7 @@
      * data has changed.
      * https://code.google.com/p/android/issues/detail?id=108949
      */
-    public void testEtagHeaders_cachedWithServerMiss() throws Exception {
+    @Test public void etagHeaders_cachedWithServerMiss() throws Exception {
         final String etagValue1 = "686897696a7c876b7e";
         final String body1 = "Response with etag 1";
         final String etagValue2 = "686897696a7c876b7f";
@@ -998,7 +1078,7 @@
     /**
      * Test which headers are sent unencrypted to the HTTP proxy.
      */
-    public void testProxyConnectIncludesProxyHeadersOnly()
+    @Test public void proxyConnectIncludesProxyHeadersOnly()
             throws IOException, InterruptedException {
         Authenticator.setDefault(new SimpleAuthenticator());
         RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
@@ -1052,7 +1132,7 @@
         assertEquals(Arrays.asList("verify android.com"), hostnameVerifier.calls);
     }
 
-    public void testProxyAuthenticateOnConnect() throws Exception {
+    @Test public void proxyAuthenticateOnConnect() throws Exception {
         Authenticator.setDefault(new SimpleAuthenticator());
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
@@ -1088,7 +1168,7 @@
 
     // Don't disconnect after building a tunnel with CONNECT
     // http://code.google.com/p/android/issues/detail?id=37221
-    public void testProxyWithConnectionClose() throws IOException {
+    @Test public void proxyWithConnectionClose() throws IOException {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
         server.enqueue(new MockResponse()
@@ -1107,7 +1187,7 @@
         assertContent("this response comes via a proxy", connection);
     }
 
-    public void testDisconnectedConnection() throws IOException {
+    @Test public void disconnectedConnection() throws IOException {
         server.enqueue(new MockResponse()
                 .throttleBody(2, 100, TimeUnit.MILLISECONDS)
                 .setBody("ABCD"));
@@ -1127,23 +1207,122 @@
         }
     }
 
+    @Test public void disconnectFromBackgroundThread_blockedRead_beforeHeader()
+            throws IOException {
+        QueueDispatcher dispatcher = new QueueDispatcher() {
+            @Override
+            public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
+                Thread.sleep(6000);
+                return super.dispatch(request);
+            }
+        };
+        server.setDispatcher(dispatcher);
+        server.enqueue(new MockResponse().setHeader("Key", "Value").setBody("Response body"));
+        checkDisconnectFromBackgroundThread_blockedRead(2000, null /* disconnectMillis */);
+    }
+
+    @Test public void disconnectFromBackgroundThread_blockedRead_beforeBody()
+            throws IOException {
+        server.enqueue(new MockResponse().setHeader("Key", "Value")
+                .setBody("Response body").setBodyDelayTimeMs(6000));
+        checkDisconnectFromBackgroundThread_blockedRead(2000, "" /* disconnectMillis */);
+    }
+
+    /**
+     *
+     * @throws IOException
+     */
+    @Test public void disconnectFromBackgroundThread_blockedRead_duringBody()
+            throws IOException {
+        server.enqueue(new MockResponse().setHeader("Key", "Value")
+                .setBody("Response body").throttleBody(3, 1333, TimeUnit.MILLISECONDS));
+        // After 2 sec, we should have read about 6 bytes (we sleep 1333msec after every 3 bytes).
+        checkDisconnectFromBackgroundThread_blockedRead(2000, "Respon");
+    }
+
+    /**
+     * Checks that {@link HttpURLConnection#disconnect() disconnecting} a blocked read
+     * from a background thread unblocks the reading thread quickly and that the headers/body
+     * read so far are as given.
+     *
+     * The disconnect happens after approximately {@code disconnectMillis} msec (between half
+     * and double that is tolerated), so the server must already be set up such that reading
+     * the headers and the entire request takes comfortably more than that, eg.
+     * {@code 3 * disconnectMillis}.
+     *
+     * @param disconnectMillis number of milliseconds until the connection should be
+     *        {@link HttpURLConnection#disconnect() disconnected} by a background thread.
+     * @param expectedResponseContent The part of the body that is expected to have been read by
+     *        the time the connection is disconnected, or null if not even the headers
+     *        are expected to have been read at the time.
+     * @throws IOException if one occurs unexpectedly while establishing the connection.
+     */
+    private void checkDisconnectFromBackgroundThread_blockedRead(
+            long disconnectMillis, String expectedResponseContent) throws IOException {
+        server.play();
+        HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
+
+        Thread disconnectThread = new Thread("Disconnect after " + disconnectMillis + "msec") {
+            @Override
+            public void run() {
+                try {
+                    Thread.sleep(disconnectMillis);
+                } catch (InterruptedException e) {
+                    // Even if an AssertionFailedError on this background thread doesn't
+                    // cause the test to fail directly, we'd still prematurely disconnect()
+                    // and that would (if significant) be detected further down by the
+                    // assertion on the number of elapsed milliseconds observed by the
+                    // main thread.
+                    fail("Unexpectedly interrupted: " + e);
+                }
+                connection.disconnect();
+            }
+        };
+
+        ByteArrayOutputStream auditStream = new ByteArrayOutputStream();
+        AuditInputStream inputStream = null;
+        boolean headerRead = false;
+        long start = System.currentTimeMillis();
+        disconnectThread.start();
+        try {
+            inputStream = new AuditInputStream(connection.getInputStream(), auditStream);
+            connection.getHeaderFields();
+            headerRead = true;
+            readAscii(inputStream);
+            fail("Didn't expect to successfully read all of the data");
+        } catch (IOException expected) {
+        } finally {
+            TestIoUtils.closeQuietly(inputStream);
+        }
+        long elapsed = System.currentTimeMillis() - start;
+
+        assertTrue("Expected approx. " + disconnectMillis + " msec elapsed, got " + elapsed,
+                disconnectMillis / 2 <= elapsed && elapsed <= 2 * disconnectMillis);
+        String readBody = new String(auditStream.toByteArray(), StandardCharsets.UTF_8);
+
+        String actualResponse = headerRead ? readBody : null;
+        assertEquals("Headers read: " + headerRead + "; read response body: " +  readBody,
+                expectedResponseContent, actualResponse);
+    }
+
+
     // http://b/33763156
-    public void testDisconnectDuringConnect_getInputStream() throws IOException {
+    @Test public void disconnectDuringConnect_getInputStream() throws IOException {
         checkDisconnectDuringConnect(HttpURLConnection::getInputStream);
     }
 
     // http://b/33763156
-    public void testDisconnectDuringConnect_getOutputStream() throws IOException {
+    @Test public void disconnectDuringConnect_getOutputStream() throws IOException {
         checkDisconnectDuringConnect(HttpURLConnection::getOutputStream);
     }
 
     // http://b/33763156
-    public void testDisconnectDuringConnect_getResponseCode() throws IOException {
+    @Test public void disconnectDuringConnect_getResponseCode() throws IOException {
         checkDisconnectDuringConnect(HttpURLConnection::getResponseCode);
     }
 
     // http://b/33763156
-    public void testDisconnectDuringConnect_getResponseMessage() throws IOException {
+    @Test public void disconnectDuringConnect_getResponseMessage() throws IOException {
         checkDisconnectDuringConnect(HttpURLConnection::getResponseMessage);
     }
 
@@ -1188,7 +1367,7 @@
         }
     }
 
-    public void testDisconnectBeforeConnect() throws IOException {
+    @Test public void disconnectBeforeConnect() throws IOException {
         server.enqueue(new MockResponse().setBody("A"));
         server.play();
 
@@ -1199,7 +1378,7 @@
         assertEquals(200, connection.getResponseCode());
     }
 
-    public void testDisconnectAfterOnlyResponseCodeCausesNoCloseGuardWarning() throws IOException {
+    @Test public void disconnectAfterOnlyResponseCodeCausesNoCloseGuardWarning() throws IOException {
         server.enqueue(new MockResponse()
                 .setBody(gzip("ABCABCABC".getBytes("UTF-8")))
                 .addHeader("Content-Encoding: gzip"));
@@ -1213,7 +1392,7 @@
         }
     }
 
-    public void testDefaultRequestProperty() throws Exception {
+    @Test public void defaultRequestProperty() throws Exception {
         URLConnection.setDefaultRequestProperty("X-testSetDefaultRequestProperty", "A");
         assertNull(URLConnection.getDefaultRequestProperty("X-setDefaultRequestProperty"));
     }
@@ -1223,7 +1402,7 @@
      * exhausted before {@code count} characters can be read, the remaining
      * characters are returned and the stream is closed.
      */
-    private String readAscii(InputStream in, int count) throws IOException {
+    private static String readAscii(InputStream in, int count) throws IOException {
         StringBuilder result = new StringBuilder();
         for (int i = 0; i < count; i++) {
             int value = in.read();
@@ -1236,15 +1415,19 @@
         return result.toString();
     }
 
-    public void testMarkAndResetWithContentLengthHeader() throws IOException {
+    private static String readAscii(InputStream in) throws IOException {
+        return readAscii(in, Integer.MAX_VALUE);
+    }
+
+    @Test public void markAndResetWithContentLengthHeader() throws IOException {
         testMarkAndReset(TransferKind.FIXED_LENGTH);
     }
 
-    public void testMarkAndResetWithChunkedEncoding() throws IOException {
+    @Test public void markAndResetWithChunkedEncoding() throws IOException {
         testMarkAndReset(TransferKind.CHUNKED);
     }
 
-    public void testMarkAndResetWithNoLengthHeaders() throws IOException {
+    @Test public void markAndResetWithNoLengthHeaders() throws IOException {
         testMarkAndReset(TransferKind.END_OF_STREAM);
     }
 
@@ -1264,7 +1447,7 @@
             fail();
         } catch (IOException expected) {
         }
-        assertEquals("FGHIJKLMNOPQRSTUVWXYZ", readAscii(in, Integer.MAX_VALUE));
+        assertEquals("FGHIJKLMNOPQRSTUVWXYZ", readAscii(in));
         assertContent("ABCDEFGHIJKLMNOPQRSTUVWXYZ", server.getUrl("/").openConnection());
     }
 
@@ -1273,7 +1456,7 @@
      * code 401. This causes a new HTTP request to be issued for every call into
      * the URLConnection.
      */
-    public void testUnauthorizedResponseHandling() throws IOException {
+    @Test public void unauthorizedResponseHandling() throws IOException {
         MockResponse response = new MockResponse()
                 .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
                 .setResponseCode(401) // UNAUTHORIZED
@@ -1292,7 +1475,7 @@
         assertEquals(1, server.getRequestCount());
     }
 
-    public void testNonHexChunkSize() throws IOException {
+    @Test public void nonHexChunkSize() throws IOException {
         server.enqueue(new MockResponse()
                 .setBody("5\r\nABCDE\r\nG\r\nFGHIJKLMNOPQRSTU\r\n0\r\n\r\n")
                 .clearHeaders()
@@ -1301,13 +1484,13 @@
 
         URLConnection connection = server.getUrl("/").openConnection();
         try {
-            readAscii(connection.getInputStream(), Integer.MAX_VALUE);
+            readAscii(connection.getInputStream());
             fail();
         } catch (IOException e) {
         }
     }
 
-    public void testMissingChunkBody() throws IOException {
+    @Test public void missingChunkBody() throws IOException {
         server.enqueue(new MockResponse()
                 .setBody("5")
                 .clearHeaders()
@@ -1317,7 +1500,7 @@
 
         URLConnection connection = server.getUrl("/").openConnection();
         try {
-            readAscii(connection.getInputStream(), Integer.MAX_VALUE);
+            readAscii(connection.getInputStream());
             fail();
         } catch (IOException e) {
         }
@@ -1328,14 +1511,14 @@
      * behavior in not required by the API, so a failure of this test does not
      * imply a bug in the implementation.
      */
-    public void testGzipEncodingEnabledByDefault() throws IOException, InterruptedException {
+    @Test public void gzipEncodingEnabledByDefault() throws IOException, InterruptedException {
         server.enqueue(new MockResponse()
                 .setBody(gzip("ABCABCABC".getBytes("UTF-8")))
                 .addHeader("Content-Encoding: gzip"));
         server.play();
 
         URLConnection connection = server.getUrl("/").openConnection();
-        assertEquals("ABCABCABC", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("ABCABCABC", readAscii(connection.getInputStream()));
         assertNull(connection.getContentEncoding());
         assertEquals(-1, connection.getContentLength());
 
@@ -1343,7 +1526,7 @@
         assertContains(request.getHeaders(), "Accept-Encoding: gzip");
     }
 
-    public void testClientConfiguredGzipContentEncoding() throws Exception {
+    @Test public void clientConfiguredGzipContentEncoding() throws Exception {
         byte[] bodyBytes = gzip("ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes("UTF-8"));
         server.enqueue(new MockResponse()
                 .setBody(bodyBytes)
@@ -1354,7 +1537,7 @@
         URLConnection connection = server.getUrl("/").openConnection();
         connection.addRequestProperty("Accept-Encoding", "gzip");
         InputStream gunzippedIn = new GZIPInputStream(connection.getInputStream());
-        assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", readAscii(gunzippedIn, Integer.MAX_VALUE));
+        assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", readAscii(gunzippedIn));
         assertEquals(bodyBytes.length, connection.getContentLength());
 
         RecordedRequest request = server.takeRequest();
@@ -1362,15 +1545,15 @@
         assertEquals("gzip", connection.getContentEncoding());
     }
 
-    public void testGzipAndConnectionReuseWithFixedLength() throws Exception {
+    @Test public void gzipAndConnectionReuseWithFixedLength() throws Exception {
         testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind.FIXED_LENGTH);
     }
 
-    public void testGzipAndConnectionReuseWithChunkedEncoding() throws Exception {
+    @Test public void gzipAndConnectionReuseWithChunkedEncoding() throws Exception {
         testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind.CHUNKED);
     }
 
-    public void testClientConfiguredCustomContentEncoding() throws Exception {
+    @Test public void clientConfiguredCustomContentEncoding() throws Exception {
         server.enqueue(new MockResponse()
                 .setBody("ABCDE")
                 .addHeader("Content-Encoding: custom"));
@@ -1378,7 +1561,7 @@
 
         URLConnection connection = server.getUrl("/").openConnection();
         connection.addRequestProperty("Accept-Encoding", "custom");
-        assertEquals("ABCDE", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("ABCDE", readAscii(connection.getInputStream()));
 
         RecordedRequest request = server.takeRequest();
         assertContains(request.getHeaders(), "Accept-Encoding: custom");
@@ -1403,11 +1586,11 @@
         URLConnection connection = server.getUrl("/").openConnection();
         connection.addRequestProperty("Accept-Encoding", "gzip");
         InputStream gunzippedIn = new GZIPInputStream(connection.getInputStream());
-        assertEquals("one (gzipped)", readAscii(gunzippedIn, Integer.MAX_VALUE));
+        assertEquals("one (gzipped)", readAscii(gunzippedIn));
         assertEquals(0, server.takeRequest().getSequenceNumber());
 
         connection = server.getUrl("/").openConnection();
-        assertEquals("two (identity)", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("two (identity)", readAscii(connection.getInputStream()));
         assertEquals(1, server.takeRequest().getSequenceNumber());
     }
 
@@ -1415,7 +1598,7 @@
      * Test that HEAD requests don't have a body regardless of the response
      * headers. http://code.google.com/p/android/issues/detail?id=24672
      */
-    public void testHeadAndContentLength() throws Exception {
+    @Test public void headAndContentLength() throws Exception {
         server.enqueue(new MockResponse()
                 .clearHeaders()
                 .addHeader("Content-Length: 100"));
@@ -1428,7 +1611,7 @@
         assertContent("", connection1);
 
         HttpURLConnection connection2 = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("A", readAscii(connection2.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("A", readAscii(connection2.getInputStream()));
 
         assertEquals(0, server.takeRequest().getSequenceNumber());
         assertEquals(1, server.takeRequest().getSequenceNumber());
@@ -1441,7 +1624,7 @@
      * the fixed chunk size. Instead, we check that chunking takes place
      * and we force the chunk size with flushes.
      */
-    public void testSetChunkedStreamingMode() throws IOException, InterruptedException {
+    @Test public void setChunkedStreamingMode() throws IOException, InterruptedException {
         server.enqueue(new MockResponse());
         server.play();
 
@@ -1468,11 +1651,11 @@
         assertEquals(Arrays.asList(3, 3, 2), request.getChunkSizes());
     }
 
-    public void testAuthenticateWithFixedLengthStreaming() throws Exception {
+    @Test public void authenticateWithFixedLengthStreaming() throws Exception {
         testAuthenticateWithStreamingPost(StreamingMode.FIXED_LENGTH);
     }
 
-    public void testAuthenticateWithChunkedStreaming() throws Exception {
+    @Test public void authenticateWithChunkedStreaming() throws Exception {
         testAuthenticateWithStreamingPost(StreamingMode.CHUNKED);
     }
 
@@ -1508,7 +1691,7 @@
         assertEquals(Arrays.toString(requestBody), Arrays.toString(request.getBody()));
     }
 
-    public void testSetValidRequestMethod() throws Exception {
+    @Test public void setValidRequestMethod() throws Exception {
         server.play();
         assertValidRequestMethod("GET");
         assertValidRequestMethod("DELETE");
@@ -1525,12 +1708,12 @@
         assertEquals(requestMethod, connection.getRequestMethod());
     }
 
-    public void testSetInvalidRequestMethodLowercase() throws Exception {
+    @Test public void setInvalidRequestMethodLowercase() throws Exception {
         server.play();
         assertInvalidRequestMethod("get");
     }
 
-    public void testSetInvalidRequestMethodConnect() throws Exception {
+    @Test public void setInvalidRequestMethodConnect() throws Exception {
         server.play();
         assertInvalidRequestMethod("CONNECT");
     }
@@ -1544,7 +1727,7 @@
         }
     }
 
-    public void testCannotSetNegativeFixedLengthStreamingMode() throws Exception {
+    @Test public void cannotSetNegativeFixedLengthStreamingMode() throws Exception {
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         try {
@@ -1554,17 +1737,17 @@
         }
     }
 
-    public void testCanSetNegativeChunkedStreamingMode() throws Exception {
+    @Test public void canSetNegativeChunkedStreamingMode() throws Exception {
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         connection.setChunkedStreamingMode(-2);
     }
 
-    public void testCannotSetFixedLengthStreamingModeAfterConnect() throws Exception {
+    @Test public void cannotSetFixedLengthStreamingModeAfterConnect() throws Exception {
         server.enqueue(new MockResponse().setBody("A"));
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("A", readAscii(connection.getInputStream()));
         try {
             connection.setFixedLengthStreamingMode(1);
             fail();
@@ -1572,11 +1755,11 @@
         }
     }
 
-    public void testCannotSetChunkedStreamingModeAfterConnect() throws Exception {
+    @Test public void cannotSetChunkedStreamingModeAfterConnect() throws Exception {
         server.enqueue(new MockResponse().setBody("A"));
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("A", readAscii(connection.getInputStream()));
         try {
             connection.setChunkedStreamingMode(1);
             fail();
@@ -1584,7 +1767,7 @@
         }
     }
 
-    public void testCannotSetFixedLengthStreamingModeAfterChunkedStreamingMode() throws Exception {
+    @Test public void cannotSetFixedLengthStreamingModeAfterChunkedStreamingMode() throws Exception {
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         connection.setChunkedStreamingMode(1);
@@ -1595,7 +1778,8 @@
         }
     }
 
-    public void testCannotSetChunkedStreamingModeAfterFixedLengthStreamingMode() throws Exception {
+    @Test public void cannotSetChunkedStreamingModeAfterFixedLengthStreamingMode()
+            throws Exception {
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         connection.setFixedLengthStreamingMode(1);
@@ -1606,11 +1790,11 @@
         }
     }
 
-    public void testSecureFixedLengthStreaming() throws Exception {
+    @Test public void secureFixedLengthStreaming() throws Exception {
         testSecureStreamingPost(StreamingMode.FIXED_LENGTH);
     }
 
-    public void testSecureChunkedStreaming() throws Exception {
+    @Test public void secureChunkedStreaming() throws Exception {
         testSecureStreamingPost(StreamingMode.CHUNKED);
     }
 
@@ -1636,7 +1820,7 @@
         OutputStream outputStream = connection.getOutputStream();
         outputStream.write(requestBody);
         outputStream.close();
-        assertEquals("Success!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("Success!", readAscii(connection.getInputStream()));
 
         RecordedRequest request = server.takeRequest();
         assertEquals("POST / HTTP/1.1", request.getRequestLine());
@@ -1652,7 +1836,7 @@
         FIXED_LENGTH, CHUNKED
     }
 
-    public void testAuthenticateWithPost() throws Exception {
+    @Test public void authenticateWithPost() throws Exception {
         MockResponse pleaseAuthenticate = new MockResponse()
                 .setResponseCode(401)
                 .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
@@ -1672,7 +1856,7 @@
         OutputStream outputStream = connection.getOutputStream();
         outputStream.write(requestBody);
         outputStream.close();
-        assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("Successful auth!", readAscii(connection.getInputStream()));
 
         // no authorization header for the first request...
         RecordedRequest request = server.takeRequest();
@@ -1688,7 +1872,7 @@
         }
     }
 
-    public void testAuthenticateWithGet() throws Exception {
+    @Test public void authenticateWithGet() throws Exception {
         MockResponse pleaseAuthenticate = new MockResponse()
                 .setResponseCode(401)
                 .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
@@ -1704,7 +1888,7 @@
         SimpleAuthenticator authenticator = new SimpleAuthenticator();
         Authenticator.setDefault(authenticator);
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("Successful auth!", readAscii(connection.getInputStream()));
         assertEquals(Authenticator.RequestorType.SERVER, authenticator.requestorType);
         assertEquals(server.getPort(), authenticator.requestingPort);
         assertEquals(InetAddress.getByName(server.getHostName()), authenticator.requestingSite);
@@ -1726,7 +1910,7 @@
     }
 
     // bug 11473660
-    public void testAuthenticateWithLowerCaseHeadersAndScheme() throws Exception {
+    @Test public void authenticateWithLowerCaseHeadersAndScheme() throws Exception {
         MockResponse pleaseAuthenticate = new MockResponse()
                 .setResponseCode(401)
                 .addHeader("www-authenticate: basic realm=\"protected area\"")
@@ -1742,7 +1926,7 @@
         SimpleAuthenticator authenticator = new SimpleAuthenticator();
         Authenticator.setDefault(authenticator);
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("Successful auth!", readAscii(connection.getInputStream()));
         assertEquals(Authenticator.RequestorType.SERVER, authenticator.requestorType);
         assertEquals(server.getPort(), authenticator.requestingPort);
         assertEquals(InetAddress.getByName(server.getHostName()), authenticator.requestingSite);
@@ -1752,7 +1936,7 @@
     }
 
     // http://code.google.com/p/android/issues/detail?id=19081
-    public void testAuthenticateWithCommaSeparatedAuthenticationMethods() throws Exception {
+    @Test public void authenticateWithCommaSeparatedAuthenticationMethods() throws Exception {
         server.enqueue(new MockResponse()
                 .setResponseCode(401)
                 .addHeader("WWW-Authenticate: Scheme1 realm=\"a\", Basic realm=\"b\", "
@@ -1765,7 +1949,7 @@
         authenticator.expectedPrompt = "b";
         Authenticator.setDefault(authenticator);
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("Successful auth!", readAscii(connection.getInputStream()));
 
         assertContainsNoneMatching(server.takeRequest().getHeaders(), "Authorization: .*");
         assertContains(server.takeRequest().getHeaders(),
@@ -1773,7 +1957,7 @@
         assertEquals("Basic", authenticator.requestingScheme);
     }
 
-    public void testAuthenticateWithMultipleAuthenticationHeaders() throws Exception {
+    @Test public void authenticateWithMultipleAuthenticationHeaders() throws Exception {
         server.enqueue(new MockResponse()
                 .setResponseCode(401)
                 .addHeader("WWW-Authenticate: Scheme1 realm=\"a\"")
@@ -1787,7 +1971,7 @@
         authenticator.expectedPrompt = "b";
         Authenticator.setDefault(authenticator);
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("Successful auth!", readAscii(connection.getInputStream()));
 
         assertContainsNoneMatching(server.takeRequest().getHeaders(), "Authorization: .*");
         assertContains(server.takeRequest().getHeaders(),
@@ -1795,15 +1979,15 @@
         assertEquals("Basic", authenticator.requestingScheme);
     }
 
-    public void testRedirectedWithChunkedEncoding() throws Exception {
+    @Test public void redirectedWithChunkedEncoding() throws Exception {
         testRedirected(TransferKind.CHUNKED, true);
     }
 
-    public void testRedirectedWithContentLengthHeader() throws Exception {
+    @Test public void redirectedWithContentLengthHeader() throws Exception {
         testRedirected(TransferKind.FIXED_LENGTH, true);
     }
 
-    public void testRedirectedWithNoLengthHeaders() throws Exception {
+    @Test public void redirectedWithNoLengthHeaders() throws Exception {
         testRedirected(TransferKind.END_OF_STREAM, false);
     }
 
@@ -1817,8 +2001,7 @@
         server.play();
 
         URLConnection connection = server.getUrl("/").openConnection();
-        assertEquals("This is the new location!",
-                readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("This is the new location!", readAscii(connection.getInputStream()));
 
         RecordedRequest first = server.takeRequest();
         assertEquals("GET / HTTP/1.1", first.getRequestLine());
@@ -1829,7 +2012,7 @@
         }
     }
 
-    public void testRedirectedOnHttps() throws IOException, InterruptedException {
+    @Test public void redirectedOnHttps() throws IOException, InterruptedException {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
         server.enqueue(new MockResponse()
@@ -1841,8 +2024,7 @@
 
         HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
         connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
-        assertEquals("This is the new location!",
-                readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("This is the new location!", readAscii(connection.getInputStream()));
 
         RecordedRequest first = server.takeRequest();
         assertEquals("GET / HTTP/1.1", first.getRequestLine());
@@ -1851,7 +2033,7 @@
         assertEquals("Expected connection reuse", 1, retry.getSequenceNumber());
     }
 
-    public void testNotRedirectedFromHttpsToHttp() throws IOException, InterruptedException {
+    @Test public void notRedirectedFromHttpsToHttp() throws IOException, InterruptedException {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
         server.enqueue(new MockResponse()
@@ -1862,11 +2044,10 @@
 
         HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
         connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
-        assertEquals("This page has moved!",
-                readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("This page has moved!", readAscii(connection.getInputStream()));
     }
 
-    public void testNotRedirectedFromHttpToHttps() throws IOException, InterruptedException {
+    @Test public void notRedirectedFromHttpToHttps() throws IOException, InterruptedException {
         server.enqueue(new MockResponse()
                 .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
                 .addHeader("Location: https://anyhost/foo")
@@ -1874,11 +2055,10 @@
         server.play();
 
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-        assertEquals("This page has moved!",
-                readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("This page has moved!", readAscii(connection.getInputStream()));
     }
 
-    public void testRedirectToAnotherOriginServer() throws Exception {
+    @Test public void redirectToAnotherOriginServer() throws Exception {
         MockWebServer server2 = new MockWebServer();
         server2.enqueue(new MockResponse().setBody("This is the 2nd server!"));
         server2.play();
@@ -1891,13 +2071,11 @@
         server.play();
 
         URLConnection connection = server.getUrl("/").openConnection();
-        assertEquals("This is the 2nd server!",
-                readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("This is the 2nd server!", readAscii(connection.getInputStream()));
         assertEquals(server2.getUrl("/"), connection.getURL());
 
         // make sure the first server was careful to recycle the connection
-        assertEquals("This is the first server again!",
-                readAscii(server.getUrl("/").openStream(), Integer.MAX_VALUE));
+        assertEquals("This is the first server again!", readAscii(server.getUrl("/").openStream()));
 
         RecordedRequest first = server.takeRequest();
         assertContains(first.getHeaders(), "Host: " + hostName + ":" + server.getPort());
@@ -1911,7 +2089,7 @@
 
     // http://b/27590872 - assert we do not throw a runtime exception if a server responds with
     // a location that cannot be represented directly by URI.
-    public void testRedirectWithInvalidRedirectUrl() throws Exception {
+    @Test public void redirectWithInvalidRedirectUrl() throws Exception {
         // The first server hosts a redirect to a second. We need two so that the ProxySelector
         // installed is used for the redirect. Otherwise the second request will be handled via the
         // existing keep-alive connection.
@@ -1963,7 +2141,7 @@
 
         try {
             HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
-            assertEquals("Target", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+            assertEquals("Target", readAscii(connection.getInputStream()));
 
             // Inspect the redirect request to see what request was actually made.
             RecordedRequest actualRequest = server2.takeRequest();
@@ -1981,7 +2159,7 @@
         }
     }
 
-    public void testInstanceFollowsRedirects() throws Exception {
+    @Test public void instanceFollowsRedirects() throws Exception {
         testInstanceFollowsRedirects("http://www.google.com/");
         testInstanceFollowsRedirects("https://www.google.com/");
     }
@@ -1995,7 +2173,7 @@
         assertFalse(urlConnection.getInstanceFollowRedirects());
     }
 
-    public void testFollowRedirects() throws Exception {
+    @Test public void followRedirects() throws Exception {
         testFollowRedirects("http://www.google.com/");
         testFollowRedirects("https://www.google.com/");
     }
@@ -2020,20 +2198,20 @@
         }
     }
 
-    public void testResponse300MultipleChoiceWithPost() throws Exception {
+    @Test public void response300MultipleChoiceWithPost() throws Exception {
         // Chrome doesn't follow the redirect, but Firefox and the RI both do
         testResponseRedirectedWithPost(HttpURLConnection.HTTP_MULT_CHOICE);
     }
 
-    public void testResponse301MovedPermanentlyWithPost() throws Exception {
+    @Test public void response301MovedPermanentlyWithPost() throws Exception {
         testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_PERM);
     }
 
-    public void testResponse302MovedTemporarilyWithPost() throws Exception {
+    @Test public void response302MovedTemporarilyWithPost() throws Exception {
         testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_TEMP);
     }
 
-    public void testResponse303SeeOtherWithPost() throws Exception {
+    @Test public void response303SeeOtherWithPost() throws Exception {
         testResponseRedirectedWithPost(HttpURLConnection.HTTP_SEE_OTHER);
     }
 
@@ -2051,7 +2229,7 @@
         OutputStream outputStream = connection.getOutputStream();
         outputStream.write(requestBody);
         outputStream.close();
-        assertEquals("Page 2", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("Page 2", readAscii(connection.getInputStream()));
         assertTrue(connection.getDoOutput());
 
         RecordedRequest page1 = server.takeRequest();
@@ -2062,7 +2240,7 @@
         assertEquals("GET /page2 HTTP/1.1", page2.getRequestLine());
     }
 
-    public void testResponse305UseProxy() throws Exception {
+    @Test public void response305UseProxy() throws Exception {
         server.play();
         server.enqueue(new MockResponse()
                 .setResponseCode(HttpURLConnection.HTTP_USE_PROXY)
@@ -2072,15 +2250,14 @@
 
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/foo").openConnection();
         // Fails on the RI, which gets "Proxy Response"
-        assertEquals("This page has moved!",
-                readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("This page has moved!", readAscii(connection.getInputStream()));
 
         RecordedRequest page1 = server.takeRequest();
         assertEquals("GET /foo HTTP/1.1", page1.getRequestLine());
         assertEquals(1, server.getRequestCount());
     }
 
-    public void testHttpsWithCustomTrustManager() throws Exception {
+    @Test public void httpsWithCustomTrustManager() throws Exception {
         RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
         RecordingTrustManager trustManager = new RecordingTrustManager();
         SSLContext sc = SSLContext.getInstance("TLS");
@@ -2099,9 +2276,9 @@
             server.play();
 
             URL url = server.getUrl("/");
-            assertEquals("ABC", readAscii(url.openStream(), Integer.MAX_VALUE));
-            assertEquals("DEF", readAscii(url.openStream(), Integer.MAX_VALUE));
-            assertEquals("GHI", readAscii(url.openStream(), Integer.MAX_VALUE));
+            assertEquals("ABC", readAscii(url.openStream()));
+            assertEquals("DEF", readAscii(url.openStream()));
+            assertEquals("GHI", readAscii(url.openStream()));
 
             assertEquals(Arrays.asList("verify " + hostName), hostnameVerifier.calls);
             assertEquals(Arrays.asList("checkServerTrusted ["
@@ -2116,7 +2293,7 @@
         }
     }
 
-    public void testSetSSLSocketFactory_null() throws Exception {
+    @Test public void setSSLSocketFactory_null() throws Exception {
         URL url = new URL("https://google.com");
         HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
         try {
@@ -2126,7 +2303,7 @@
         }
     }
 
-    public void testSetDefaultSSLSocketFactory_null() {
+    @Test public void setDefaultSSLSocketFactory_null() {
         try {
             HttpsURLConnection.setDefaultSSLSocketFactory(null);
             fail();
@@ -2139,7 +2316,7 @@
      * connection attempt. If a hostname resolves to multiple IPs HttpURLConnection will wait the
      * full timeout for each.
      */
-    public void testConnectTimeouts() throws IOException {
+    @Test public void connectTimeouts() throws IOException {
         // During CTS tests we are limited in what host names we can depend on and unfortunately
         // DNS lookups are not pluggable through standard APIs. During manual testing you should be
         // able to change this to any name that can be resolved to multiple IPs and it should still
@@ -2186,7 +2363,7 @@
         }
     }
 
-    public void testReadTimeouts() throws IOException {
+    @Test public void readTimeouts() throws IOException {
         /*
          * This relies on the fact that MockWebServer doesn't close the
          * connection after a response has been sent. This causes the client to
@@ -2213,7 +2390,8 @@
         }
     }
 
-    public void testSetChunkedEncodingAsRequestProperty() throws IOException, InterruptedException {
+    @Test public void setChunkedEncodingAsRequestProperty()
+            throws IOException, InterruptedException {
         server.enqueue(new MockResponse());
         server.play();
 
@@ -2227,7 +2405,7 @@
         assertEquals("ABC", new String(request.getBody(), "UTF-8"));
     }
 
-    public void testConnectionCloseInRequest() throws IOException, InterruptedException {
+    @Test public void connectionCloseInRequest() throws IOException, InterruptedException {
         server.enqueue(new MockResponse()); // server doesn't honor the connection: close header!
         server.enqueue(new MockResponse());
         server.play();
@@ -2244,7 +2422,7 @@
                 0, server.takeRequest().getSequenceNumber());
     }
 
-    public void testConnectionCloseInResponse() throws IOException, InterruptedException {
+    @Test public void connectionCloseInResponse() throws IOException, InterruptedException {
         server.enqueue(new MockResponse().addHeader("Connection: close"));
         server.enqueue(new MockResponse());
         server.play();
@@ -2260,7 +2438,7 @@
                 0, server.takeRequest().getSequenceNumber());
     }
 
-    public void testConnectionCloseWithRedirect() throws IOException, InterruptedException {
+    @Test public void connectionCloseWithRedirect() throws IOException, InterruptedException {
         MockResponse response = new MockResponse()
                 .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
                 .addHeader("Location: /foo")
@@ -2270,26 +2448,24 @@
         server.play();
 
         URLConnection connection = server.getUrl("/").openConnection();
-        assertEquals("This is the new location!",
-                readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("This is the new location!", readAscii(connection.getInputStream()));
 
         assertEquals(0, server.takeRequest().getSequenceNumber());
         assertEquals("When connection: close is used, each request should get its own connection",
                 0, server.takeRequest().getSequenceNumber());
     }
 
-    public void testResponseCodeDisagreesWithHeaders() throws IOException, InterruptedException {
+    @Test public void responseCodeDisagreesWithHeaders() throws IOException, InterruptedException {
         server.enqueue(new MockResponse()
                 .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)
                 .setBody("This body is not allowed!"));
         server.play();
 
         URLConnection connection = server.getUrl("/").openConnection();
-        assertEquals("This body is not allowed!",
-                readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("This body is not allowed!", readAscii(connection.getInputStream()));
     }
 
-    public void testSingleByteReadIsSigned() throws IOException {
+    @Test public void singleByteReadIsSigned() throws IOException {
         server.enqueue(new MockResponse().setBody(new byte[] { -2, -1 }));
         server.play();
 
@@ -2300,15 +2476,15 @@
         assertEquals(-1, in.read());
     }
 
-    public void testFlushAfterStreamTransmittedWithChunkedEncoding() throws IOException {
+    @Test public void flushAfterStreamTransmittedWithChunkedEncoding() throws IOException {
         testFlushAfterStreamTransmitted(TransferKind.CHUNKED);
     }
 
-    public void testFlushAfterStreamTransmittedWithFixedLength() throws IOException {
+    @Test public void flushAfterStreamTransmittedWithFixedLength() throws IOException {
         testFlushAfterStreamTransmitted(TransferKind.FIXED_LENGTH);
     }
 
-    public void testFlushAfterStreamTransmittedWithNoLengthHeaders() throws IOException {
+    @Test public void flushAfterStreamTransmittedWithNoLengthHeaders() throws IOException {
         testFlushAfterStreamTransmitted(TransferKind.END_OF_STREAM);
     }
 
@@ -2333,7 +2509,7 @@
 
         OutputStream out = connection.getOutputStream();
         out.write(upload);
-        assertEquals("abc", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("abc", readAscii(connection.getInputStream()));
 
         out.flush(); // dubious but permitted
         try {
@@ -2343,7 +2519,7 @@
         }
     }
 
-    public void testGetHeadersThrows() throws IOException {
+    @Test public void getHeadersThrows() throws IOException {
         server.enqueue(new MockResponse().setSocketPolicy(DISCONNECT_AT_START));
         server.play();
 
@@ -2361,7 +2537,7 @@
         }
     }
 
-    public void testReadTimeoutsOnRecycledConnections() throws Exception {
+    @Test public void readTimeoutsOnRecycledConnections() throws Exception {
         server.enqueue(new MockResponse().setBody("ABC"));
         server.play();
 
@@ -2370,7 +2546,7 @@
         // Read timeout of a day, sure to cause the test to timeout and fail.
         connection.setReadTimeout(24 * 3600 * 1000);
         InputStream input = connection.getInputStream();
-        assertEquals("ABC", readAscii(input, Integer.MAX_VALUE));
+        assertEquals("ABC", readAscii(input));
         input.close();
         try {
             connection = server.getUrl("").openConnection();
@@ -2390,7 +2566,7 @@
      * After M, Android's HttpURLConnection started canonicalizing hostnames to lower case, IDN
      * encoding and being more strict about invalid characters.
      */
-    public void testUrlCharacterMapping() throws Exception {
+    @Test public void urlCharacterMapping() throws Exception {
         server.setDispatcher(new Dispatcher() {
             @Override public MockResponse dispatch(RecordedRequest request)
                 throws InterruptedException {
@@ -2613,7 +2789,7 @@
             backdoorUrlToUri(new URL("http://host.tld/file#" + asFragment + "-x")).toString());
     }
 
-    public void testHostWithNul() throws Exception {
+    @Test public void hostWithNul() throws Exception {
         URL url = new URL("http://host\u0000/");
         try {
             url.openStream();
@@ -2624,7 +2800,7 @@
     /**
      * Don't explode if the cache returns a null body. http://b/3373699
      */
-    public void testResponseCacheReturnsNullOutputStream() throws Exception {
+    @Test public void responseCacheReturnsNullOutputStream() throws Exception {
         final AtomicBoolean aborted = new AtomicBoolean();
         ResponseCache.setDefault(new ResponseCache() {
             @Override public CacheResponse get(URI uri, String requestMethod,
@@ -2657,7 +2833,7 @@
     /**
      * http://code.google.com/p/android/issues/detail?id=14562
      */
-    public void testReadAfterLastByte() throws Exception {
+    @Test public void readAfterLastByte() throws Exception {
         server.enqueue(new MockResponse()
                 .setBody("ABC")
                 .clearHeaders()
@@ -2672,15 +2848,15 @@
         assertEquals(-1, in.read()); // throws IOException in Gingerbread
     }
 
-    public void testGetContent() throws Exception {
+    @Test public void getContent() throws Exception {
         server.enqueue(new MockResponse().setBody("A"));
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
         InputStream in = (InputStream) connection.getContent();
-        assertEquals("A", readAscii(in, Integer.MAX_VALUE));
+        assertEquals("A", readAscii(in));
     }
 
-    public void testGetContentOfType() throws Exception {
+    @Test public void getContentOfType() throws Exception {
         server.enqueue(new MockResponse().setBody("A"));
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
@@ -2698,7 +2874,7 @@
         connection.disconnect();
     }
 
-    public void testGetOutputStreamOnGetFails() throws Exception {
+    @Test public void getOutputStreamOnGetFails() throws Exception {
         server.enqueue(new MockResponse());
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
@@ -2709,7 +2885,7 @@
         }
     }
 
-    public void testGetOutputAfterGetInputStreamFails() throws Exception {
+    @Test public void getOutputAfterGetInputStreamFails() throws Exception {
         server.enqueue(new MockResponse());
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
@@ -2722,7 +2898,7 @@
         }
     }
 
-    public void testSetDoOutputOrDoInputAfterConnectFails() throws Exception {
+    @Test public void setDoOutputOrDoInputAfterConnectFails() throws Exception {
         server.enqueue(new MockResponse());
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
@@ -2740,7 +2916,7 @@
         connection.disconnect();
     }
 
-    public void testLastModified() throws Exception {
+    @Test public void lastModified() throws Exception {
         server.enqueue(new MockResponse()
                 .addHeader("Last-Modified", "Wed, 27 Nov 2013 11:26:00 GMT")
                 .setBody("Hello"));
@@ -2753,7 +2929,7 @@
         assertEquals(1385551560000L, connection.getHeaderFieldDate("Last-Modified", -1));
     }
 
-    public void testClientSendsContentLength() throws Exception {
+    @Test public void clientSendsContentLength() throws Exception {
         server.enqueue(new MockResponse().setBody("A"));
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
@@ -2761,12 +2937,12 @@
         OutputStream out = connection.getOutputStream();
         out.write(new byte[] { 'A', 'B', 'C' });
         out.close();
-        assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
+        assertEquals("A", readAscii(connection.getInputStream()));
         RecordedRequest request = server.takeRequest();
         assertContains(request.getHeaders(), "Content-Length: 3");
     }
 
-    public void testGetContentLengthConnects() throws Exception {
+    @Test public void getContentLengthConnects() throws Exception {
         server.enqueue(new MockResponse().setBody("ABC"));
         server.play();
         HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
@@ -2774,7 +2950,7 @@
         connection.disconnect();
     }
 
-    public void testGetContentTypeConnects() throws Exception {
+    @Test public void getContentTypeConnects() throws Exception {
         server.enqueue(new MockResponse()
                 .addHeader("Content-Type: text/plain")
                 .setBody("ABC"));
@@ -2784,7 +2960,7 @@
         connection.disconnect();
     }
 
-    public void testGetContentEncodingConnects() throws Exception {
+    @Test public void getContentEncodingConnects() throws Exception {
         server.enqueue(new MockResponse()
                 .addHeader("Content-Encoding: identity")
                 .setBody("ABC"));
@@ -2795,29 +2971,29 @@
     }
 
     // http://b/4361656
-    public void testUrlContainsQueryButNoPath() throws Exception {
+    @Test public void urlContainsQueryButNoPath() throws Exception {
         server.enqueue(new MockResponse().setBody("A"));
         server.play();
         URL url = new URL("http", server.getHostName(), server.getPort(), "?query");
-        assertEquals("A", readAscii(url.openConnection().getInputStream(), Integer.MAX_VALUE));
+        assertEquals("A", readAscii(url.openConnection().getInputStream()));
         RecordedRequest request = server.takeRequest();
         assertEquals("GET /?query HTTP/1.1", request.getRequestLine());
     }
 
     // http://code.google.com/p/android/issues/detail?id=20442
-    public void testInputStreamAvailableWithChunkedEncoding() throws Exception {
-        testInputStreamAvailable(TransferKind.CHUNKED);
+    @Test public void inputStreamAvailableWithChunkedEncoding() throws Exception {
+        checkInputStreamAvailable(TransferKind.CHUNKED);
     }
 
-    public void testInputStreamAvailableWithContentLengthHeader() throws Exception {
-        testInputStreamAvailable(TransferKind.FIXED_LENGTH);
+    @Test public void inputStreamAvailableWithContentLengthHeader() throws Exception {
+        checkInputStreamAvailable(TransferKind.FIXED_LENGTH);
     }
 
-    public void testInputStreamAvailableWithNoLengthHeaders() throws Exception {
-        testInputStreamAvailable(TransferKind.END_OF_STREAM);
+    @Test public void inputStreamAvailableWithNoLengthHeaders() throws Exception {
+        checkInputStreamAvailable(TransferKind.END_OF_STREAM);
     }
 
-    private void testInputStreamAvailable(TransferKind transferKind) throws IOException {
+    private void checkInputStreamAvailable(TransferKind transferKind) throws IOException {
         String body = "ABCDEFGH";
         MockResponse response = new MockResponse();
         transferKind.setBody(response, body, 4);
@@ -2834,7 +3010,7 @@
     }
 
     // http://code.google.com/p/android/issues/detail?id=28095
-    public void testInvalidIpv4Address() throws Exception {
+    @Test public void invalidIpv4Address() throws Exception {
         try {
             URI uri = new URI("http://1111.111.111.111/index.html");
             uri.toURL().openConnection().connect();
@@ -2843,7 +3019,7 @@
         }
     }
 
-    public void testConnectIpv6() throws Exception {
+    @Test public void connectIpv6() throws Exception {
         server.enqueue(new MockResponse().setBody("testConnectIpv6 body"));
         server.play();
         URL url = new URL("http://[::1]:" + server.getPort() + "/");
@@ -2852,7 +3028,7 @@
     }
 
     // http://code.google.com/p/android/issues/detail?id=16895
-    public void testUrlWithSpaceInHost() throws Exception {
+    @Test public void urlWithSpaceInHost() throws Exception {
         URLConnection urlConnection = new URL("http://and roid.com/").openConnection();
         try {
             urlConnection.getInputStream();
@@ -2862,7 +3038,7 @@
     }
 
     // http://code.google.com/p/android/issues/detail?id=16895
-    public void testUrlWithSpaceInHostViaHttpProxy() throws Exception {
+    @Test public void urlWithSpaceInHostViaHttpProxy() throws Exception {
         server.enqueue(new MockResponse());
         server.play();
         URLConnection urlConnection = new URL("http://and roid.com/")
@@ -2903,7 +3079,7 @@
                 false /* expectedWasFallbackScsvSet */, expectedProtocols);
     }
 
-    public void testNoSslFallback_specifiedProtocols() throws Exception {
+    @Test public void noSslFallback_specifiedProtocols() throws Exception {
         String[] enabledProtocols = { "TLSv1.2", "TLSv1.1" };
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         SSLSocketFactory serverSocketFactory =
@@ -2916,7 +3092,7 @@
                 enabledProtocols);
     }
 
-    public void testNoSslFallback_defaultProtocols() throws Exception {
+    @Test public void noSslFallback_defaultProtocols() throws Exception {
         // Will need to be updated if the enabled protocols in Android's SSLSocketFactory change
         String[] expectedEnabledProtocols = { "TLSv1.2", "TLSv1.1", "TLSv1" };
 
@@ -2936,7 +3112,7 @@
         assertEquals(expectedWasFallbackScsvSet, socket.wasTlsFallbackScsvSet());
     }
 
-    public void testInspectSslBeforeConnect() throws Exception {
+    @Test public void inspectSslBeforeConnect() throws Exception {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
         server.enqueue(new MockResponse());
@@ -2971,7 +3147,7 @@
      * Test that we can inspect the SSL session after connect().
      * http://code.google.com/p/android/issues/detail?id=24431
      */
-    public void testInspectSslAfterConnect() throws Exception {
+    @Test public void inspectSslAfterConnect() throws Exception {
         TestSSLContext testSSLContext = createDefaultTestSSLContext();
         server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
         server.enqueue(new MockResponse());
@@ -3008,10 +3184,10 @@
      * the minimal implementation of these methods to get OkHttp's tests to pass, so
      * they should never be invoked outside of OkHttp's tests.
      */
-    public void testTrustManagerAndTrustRootIndex_unusedForHttpsConnection() throws Exception {
+    @Test public void trustManagerAndTrustRootIndex_unusedForHttpsConnection() throws Exception {
         Platform platform = Platform.getAndSetForTest(new PlatformWithoutTrustManager());
         try {
-            testConnectViaHttps();
+            checkConnectViaHttps();
         } finally {
             Platform.getAndSetForTest(platform);
         }
@@ -3024,7 +3200,7 @@
      * be going wrong in order for this test to (unexpectedly) invoke the corresponding
      * Platform methods.
      */
-    public void testTrustManagerAndTrustRootIndex_unusedForHttpConnection() throws Exception {
+    @Test public void trustManagerAndTrustRootIndex_unusedForHttpConnection() throws Exception {
         Platform platform = Platform.getAndSetForTest(new PlatformWithoutTrustManager());
         try {
             server.enqueue(new MockResponse().setBody("response").setResponseCode(200));
diff --git a/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
index 113779d..f7f4e32 100644
--- a/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
@@ -16,6 +16,14 @@
 
 package libcore.java.nio.channels;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
@@ -28,28 +36,33 @@
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
 import java.nio.channels.UnresolvedAddressException;
-import java.nio.channels.UnsupportedAddressTypeException;
 import java.util.Enumeration;
-import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class ServerSocketChannelTest extends junit.framework.TestCase {
+@RunWith(JUnit4.class)
+public class ServerSocketChannelTest {
     // http://code.google.com/p/android/issues/detail?id=16579
+    @Test
     public void testNonBlockingAccept() throws Exception {
-        ServerSocketChannel ssc = ServerSocketChannel.open();
-        try {
+        try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
             ssc.configureBlocking(false);
             ssc.socket().bind(null);
             // Should return immediately, since we're non-blocking.
             assertNull(ssc.accept());
-        } finally {
-            ssc.close();
         }
     }
 
     /** Checks the state of the ServerSocketChannel and associated ServerSocket after open() */
-    public void test_open_initialState() throws Exception {
-        ServerSocketChannel ssc = ServerSocketChannel.open();
-        try {
+    @Test
+    public void open_initialState() throws Exception {
+        try (ServerSocketChannel ssc = ServerSocketChannel.open()) {
             assertNull(ssc.socket().getLocalSocketAddress());
 
             ServerSocket socket = ssc.socket();
@@ -61,12 +74,11 @@
             assertTrue(socket.getReuseAddress());
 
             assertSame(ssc, socket.getChannel());
-        } finally {
-            ssc.close();
         }
     }
 
-    public void test_bind_unresolvedAddress() throws IOException {
+    @Test
+    public void bind_unresolvedAddress() throws IOException {
         ServerSocketChannel ssc = ServerSocketChannel.open();
         try {
             ssc.socket().bind(new InetSocketAddress("unresolvedname", 31415));
@@ -80,7 +92,8 @@
         ssc.close();
     }
 
-    public void test_bind_nullBindsToAll() throws Exception {
+    @Test
+    public void bind_nullBindsToAll() throws Exception {
         ServerSocketChannel ssc = ServerSocketChannel.open();
         ssc.socket().bind(null);
         InetSocketAddress boundAddress = (InetSocketAddress) ssc.socket().getLocalSocketAddress();
@@ -106,9 +119,55 @@
         ssc.close();
     }
 
-    public void test_bind_loopback() throws Exception {
+    /**
+     * Server that can be used to generate a Future containing the count of incoming connections it
+     * accepts.  Uses a latch to block the main thread until it is ready to start counting.
+     */
+    private static class CountingServer implements Callable<Integer> {
+        private final ServerSocketChannel channel;
+        private final CountDownLatch latch;
+        private Integer connectionCount = 0;
+
+        private CountingServer(ServerSocketChannel channel, CountDownLatch latch) {
+            this.channel = channel;
+            this.latch = latch;
+        }
+
+        @Override
+        public Integer call() throws IOException {
+            // Clear any pending connections.
+            clearAcceptQueue();
+            // Release the main thread.
+            latch.countDown();
+            // Loop accepting and counting connections until the main thread closes the socket,
+            // triggering an IOException.
+            while (true) {
+                try {
+                    SocketChannel client = channel.accept();
+                    connectionCount++;
+                    client.close();
+                } catch (IOException e) {
+                    break;
+                }
+            }
+            return connectionCount;
+        }
+
+        private void clearAcceptQueue() throws IOException {
+            channel.configureBlocking(false);
+            SocketChannel client;
+            while ((client = channel.accept()) != null) {
+                client.close();
+            }
+            channel.configureBlocking(true);
+        }
+    }
+
+    @Test
+    public void bind_loopback() throws Exception {
+        ExecutorService executor = Executors.newSingleThreadExecutor();
         ServerSocketChannel ssc = ServerSocketChannel.open();
-        ssc.socket().bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
+        ssc.socket().bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 5);
         InetSocketAddress boundAddress = (InetSocketAddress) ssc.socket().getLocalSocketAddress();
         assertFalse(boundAddress.getAddress().isAnyLocalAddress());
         assertFalse(boundAddress.getAddress().isLinkLocalAddress());
@@ -121,9 +180,16 @@
                 new InetSocketAddress(InetAddress.getLoopbackAddress(), boundAddress.getPort());
         assertTrue(canConnect(loopbackAddress));
 
+        CountDownLatch latch = new CountDownLatch(1);
+        Future<Integer> countFuture = executor.submit(new CountingServer(ssc, latch));
+        // Wait until the CountingServer thread starts, otherwise there is a risk of
+        // canConnect() connecting and closing the socket before the server is ready.
+        latch.await();
+
         // Go through all local IPs and try to connect to each in turn - all should fail except
         // for the loopback.
         Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
+        assertNotNull(interfaces);
         while (interfaces.hasMoreElements()) {
             NetworkInterface nic = interfaces.nextElement();
             Enumeration<InetAddress> inetAddresses = nic.getInetAddresses();
@@ -131,15 +197,19 @@
                 InetSocketAddress address =
                         new InetSocketAddress(inetAddresses.nextElement(), boundAddress.getPort());
                 if (!address.equals(loopbackAddress)) {
-                    assertFalse(canConnect(address));
+                    // Return value ignored in favour of using countFuture below.
+                    canConnect(address);
                 }
             }
         }
-
         ssc.close();
+        executor.shutdown();
+        // If connectionCount is non-zero then we connected to our own server which is a failure.
+        assertEquals(0, (int) countFuture.get());
     }
 
-    public void test_bind$SocketAddress() throws IOException {
+    @Test
+    public void bind_socketAddress() throws IOException {
         ServerSocketChannel ssc = ServerSocketChannel.open();
         ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
         assertEquals(InetAddress.getLoopbackAddress(),
@@ -168,7 +238,8 @@
         }
     }
 
-    public void test_setOption() throws Exception {
+    @Test
+    public void set_option() throws Exception {
         ServerSocketChannel sc = ServerSocketChannel.open();
         sc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
 
diff --git a/luni/src/test/java/libcore/java/nio/charset/ModifiedUtf8Test.java b/luni/src/test/java/libcore/java/nio/charset/ModifiedUtf8Test.java
deleted file mode 100644
index f7c91ba..0000000
--- a/luni/src/test/java/libcore/java/nio/charset/ModifiedUtf8Test.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2015 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.nio.charset;
-
-import junit.framework.TestCase;
-
-import java.io.UTFDataFormatException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.ModifiedUtf8;
-import java.util.Arrays;
-
-/**
- * Tests for {@code ModifiedUtf8}.
- */
-public class ModifiedUtf8Test extends TestCase {
-    public void test_decode_singleChar() throws Exception {
-        assertEquals("A", ModifiedUtf8.decode(new byte[] { 'A' }, new char[1], 0, 1));
-    }
-
-    public void test_decode_checkOffsetAndLength() throws Exception {
-        assertEquals("BC", ModifiedUtf8.decode(
-                new byte[] { 'A', 'B', 'C', 'D' }, new char[2], 1, 2));
-    }
-
-    public void test_decode_unexpectedEndOfStreamAfterC2_throws() {
-        // We need at least one byte after 0xc2.
-        try {
-            ModifiedUtf8.decode(new byte[]{'B', (byte) 0xc2}, new char[2], 0, 2);
-            fail("Should throw " + UTFDataFormatException.class.getName());
-        } catch(UTFDataFormatException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_decode_unexpectedEndOfStreamAfterE0_throws() {
-        // We need at least two bytes after 0xe0.
-        try {
-            ModifiedUtf8.decode(
-                    new byte[] { 'B', (byte) 0xe0, (byte) 0xab }, new char[2], 0, 3);
-            fail("Should throw " + UTFDataFormatException.class.getName());
-        } catch(UTFDataFormatException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_decode_endOfStreamAfterC2() throws Exception {
-        assertEquals("B\u00a0", ModifiedUtf8.decode(
-                new byte[] { 'B', (byte) 0xc2, (byte) 0xa0 },
-                new char[2],
-                0,
-                3));
-    }
-
-    public void test_decode_endOfStreamAfterE0() throws Exception {
-        assertEquals("B\u0830", ModifiedUtf8.decode(
-                new byte[] { 'B', (byte) 0xe0, (byte) 0xa0, (byte) 0xb0 },
-                new char[2],
-                0,
-                4));
-    }
-
-    public void test_decode_invalidByte_characterUnknown() throws Exception {
-        try {
-            ModifiedUtf8.decode(new byte[]{'A', (byte) 0xf0}, new char[2], 0, 2);
-            fail("Should throw " + UTFDataFormatException.class.getName());
-        } catch (UTFDataFormatException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_decode_someC2Character() throws Exception {
-        assertEquals("A\u00a6", ModifiedUtf8.decode(
-                new byte[] { 'A', (byte) 0xc2, (byte) 0xa6 }, new char[2], 0, 3));
-    }
-
-    public void test_decode_lastC2Character() throws Exception {
-        assertEquals("A\u00bf", ModifiedUtf8.decode(
-                new byte[] { 'A', (byte) 0xc2, (byte) 0xbf }, new char[2], 0, 3));
-    }
-
-    public void test_decode_someTwoByteCharacter() throws Exception {
-        // Make sure bit masking works
-        assertEquals("A\u0606", ModifiedUtf8.decode(
-                new byte[] { 'A', (byte) 0xd8, (byte) 0x86 }, new char[3], 0, 3));
-    }
-
-    public void test_decode_lastTwoByteCharacter() throws Exception {
-        assertEquals("A\u07ff", ModifiedUtf8.decode(
-                new byte[] { 'A', (byte) 0xdf, (byte) 0xbf }, new char[2], 0, 3));
-    }
-
-    public void test_decode_firstE0Character() throws Exception {
-        assertEquals("A\u0800", ModifiedUtf8.decode(
-                new byte[] { 'A', (byte) 0xe0, (byte) 0xa0, (byte) 0x80 },
-                new char[2],
-                0,
-                4));
-    }
-
-    public void test_decode_someThreeBytesCharacter() throws Exception {
-        assertEquals("A\u31c6", ModifiedUtf8.decode(
-                new byte[]{ 'A', (byte) 0xe3, (byte) 0x87, (byte) 0x86 },
-                new char[2],
-                0,
-                4));
-    }
-
-    public void test_decode_lastThreeBytesCharacter() throws Exception {
-        assertEquals("A\uffff", ModifiedUtf8.decode(
-                new byte[] { 'A', (byte) 0xef, (byte) 0xbf, (byte) 0xbf },
-                new char[2],
-                0,
-                4));
-    }
-
-    public void test_decode_twoByteCharacterAfterThreeByteCharacter() throws Exception {
-        assertEquals("\uffff\u0606A", ModifiedUtf8.decode(
-                new byte[] { (byte) 0xef, (byte) 0xbf, (byte) 0xbf, (byte) 0xd8, (byte) 0x86, 'A' },
-                new char[3],
-                0,
-                6));
-    }
-
-    public void test_decode_c080isZero() throws Exception {
-        assertEquals("A\u0000A", ModifiedUtf8.decode(
-                new byte[] { 'A', (byte) 0xc0, (byte) 0x80, 'A' }, new char[3], 0, 4));
-    }
-
-    public void test_decode_00isZero() throws Exception {
-        assertEquals("A\u0000A", ModifiedUtf8.decode(
-                new byte[] { 'A', (byte) 0, 'A' }, new char[3], 0, 3));
-    }
-
-    public void test_decode_insufficientOutputSpace_throws() throws Exception{
-        try {
-            ModifiedUtf8.decode(new byte[] { 'A', (byte) 0, 'A' }, new char[2], 0,  3);
-            fail("Should throw " + ArrayIndexOutOfBoundsException.class.getName());
-        } catch(ArrayIndexOutOfBoundsException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_decode_checkBadSecondByteOfTwo() throws Exception {
-        try {
-            ModifiedUtf8.decode(new byte[]{(byte) 0xc0, (byte) 0xc0}, new char[2], 0, 2);
-            fail("Should throw " + UTFDataFormatException.class.getName());
-        } catch (UTFDataFormatException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_decode_checkBadSecondByteOfThree() throws Exception{
-        try {
-            ModifiedUtf8.decode(new byte[]{
-                    (byte) 0xe0, (byte) 0xc0, (byte) 0x80}, new char[2], 0, 2);
-            fail("Should throw " + UTFDataFormatException.class.getName());
-        } catch (UTFDataFormatException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_decode_checkBadThirdByteOfThree() throws Exception{
-        try {
-            ModifiedUtf8.decode(new byte[]{
-                    (byte) 0xe0, (byte) 0x80, (byte) 0xc0}, new char[2], 0, 2);
-            fail("Should throw " + UTFDataFormatException.class.getName());
-        } catch (UTFDataFormatException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_decode_insufficientInput_throws() throws Exception{
-        try {
-            ModifiedUtf8.decode(new byte[] { 'A', (byte) 0, 'A' }, new char[8], 0,  100);
-            fail("Should throw " + ArrayIndexOutOfBoundsException.class.getName());
-        } catch(ArrayIndexOutOfBoundsException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_decode_extraCharsInArray_ignored() throws Exception {
-        assertEquals("A", ModifiedUtf8.decode(new byte[] { 'A' }, new char[] { 'B', 'Z' }, 0,  1));
-    }
-
-    public void test_countBytes_rightCount() throws Exception {
-        assertEquals(0, ModifiedUtf8.countBytes("", false));
-        assertEquals(2, ModifiedUtf8.countBytes("\u0000", false));
-        assertEquals(1, ModifiedUtf8.countBytes("A", false));
-        assertEquals(1, ModifiedUtf8.countBytes("\u007f", false));
-        assertEquals(2, ModifiedUtf8.countBytes("\u0080", false));
-        assertEquals(2, ModifiedUtf8.countBytes("\u07ff", false));
-        assertEquals(3, ModifiedUtf8.countBytes("\u0800", false));
-        assertEquals(3, ModifiedUtf8.countBytes("\uffff", false));
-    }
-
-    public void test_countBytes_checkExceptionThrown() throws Exception {
-        // These two mustn't throw...
-        ModifiedUtf8.countBytes("", true);
-        ModifiedUtf8.countBytes("A", true);
-
-        char[] unsignedShortSizedCharArray = new char[2 * Short.MAX_VALUE + 1];
-        for (int i = 0; i < unsignedShortSizedCharArray.length; i++) {
-            unsignedShortSizedCharArray[i] = 'A';
-        }
-        String unsignedShortSizedString = String.copyValueOf(unsignedShortSizedCharArray);
-
-        char[] sizeLongerThanUnsignedShortCharArray = new char[2 * Short.MAX_VALUE + 2];
-        for (int i = 0; i < sizeLongerThanUnsignedShortCharArray.length; i++) {
-            sizeLongerThanUnsignedShortCharArray[i] = 'A';
-        }
-        String sizeLongerThanUnsignedShortString = String.copyValueOf(
-                sizeLongerThanUnsignedShortCharArray);
-
-        // Mustn't throw.
-        ModifiedUtf8.countBytes(unsignedShortSizedString, true);
-
-        try {
-            // Must throw.
-            ModifiedUtf8.countBytes(sizeLongerThanUnsignedShortString, true);
-            fail();
-        } catch (UTFDataFormatException expected) {
-            // Expected.
-        }
-
-        // Mustn't throw.
-        ModifiedUtf8.countBytes(unsignedShortSizedString, false);
-        ModifiedUtf8.countBytes(sizeLongerThanUnsignedShortString, false);
-    }
-
-    public void test_encode() throws Exception {
-        assertTrue(Arrays.equals(new byte[]{0, 1, 'A'}, ModifiedUtf8.encode("A")));
-        assertTrue(Arrays.equals(new byte[] { 0, 3, 'A', 'B', 'C' }, ModifiedUtf8.encode("ABC")));
-        assertTrue(Arrays.equals(new byte[] { 0, 3, 'A', (byte) 0xc2, (byte) 0xa0 },
-                ModifiedUtf8.encode("A\u00a0")));
-        assertTrue(Arrays.equals(new byte[] { 0, 4, 'A', (byte) 0xe0, (byte) 0xa0, (byte) 0xb0 },
-                ModifiedUtf8.encode("A\u0830")));
-        assertTrue(Arrays.equals(new byte[] { 0, 3, 'A', (byte) 0xc2, (byte) 0xa6 },
-                ModifiedUtf8.encode("A\u00a6")));
-        assertTrue(Arrays.equals(new byte[] { 0, 3, 'A', (byte) 0xc2, (byte) 0xbf },
-                ModifiedUtf8.encode("A\u00bf")));
-        assertTrue(Arrays.equals(new byte[] { 0, 3, 'A', (byte) 0xd8, (byte) 0x86 },
-                ModifiedUtf8.encode("A\u0606")));
-        assertTrue(Arrays.equals(new byte[] { 0, 3, 'A', (byte) 0xdf, (byte) 0xbf },
-                ModifiedUtf8.encode("A\u07ff")));
-        assertTrue(Arrays.equals(new byte[] { 0, 4, 'A', (byte) 0xe0, (byte) 0xa0, (byte) 0x80 },
-                ModifiedUtf8.encode("A\u0800")));
-        assertTrue(Arrays.equals(new byte[] { 0, 4, 'A', (byte) 0xe3, (byte) 0x87, (byte) 0x86 },
-                ModifiedUtf8.encode("A\u31c6")));
-        assertTrue(Arrays.equals(new byte[] { 0, 4, 'A', (byte) 0xef, (byte) 0xbf, (byte) 0xbf },
-                ModifiedUtf8.encode("A\uffff")));
-        assertTrue(Arrays.equals(new byte[] { 0, 3, 'A', (byte) 0xc0, (byte) 0x80 },
-                ModifiedUtf8.encode("A\u0000")));
-        assertTrue(
-                Arrays.equals(new byte[] { 0, 8, (byte) 0xe3, (byte) 0x87, (byte) 0x86,
-                                (byte) 0xd8, (byte) 0x86, (byte) 0xc0, (byte) 0x80, 'A' },
-                ModifiedUtf8.encode("\u31c6\u0606\u0000A")));
-    }
-
-    public void test_encode_throws() throws Exception {
-        char[] unsignedShortSizedCharArray = new char[Short.MAX_VALUE * 2 + 1];
-        for (int i = 0; i < unsignedShortSizedCharArray.length; i++) {
-            unsignedShortSizedCharArray[i] = 'A';
-        }
-        String unsignedShortSizedString = String.copyValueOf(unsignedShortSizedCharArray);
-
-        char[] sizeLongerThanUnsignedShortCharArray = new char[Short.MAX_VALUE * 2 + 2];
-        for (int i = 0; i < sizeLongerThanUnsignedShortCharArray.length; i++) {
-            sizeLongerThanUnsignedShortCharArray[i] = 'A';
-        }
-        String sizeLongerThanUnsignedShortString =
-                String.copyValueOf(sizeLongerThanUnsignedShortCharArray);
-
-        // Mustn't throw.
-        ModifiedUtf8.encode(unsignedShortSizedString);
-        try {
-            // Must throw.
-            ModifiedUtf8.encode(sizeLongerThanUnsignedShortString);
-            fail("Should throw " + UTFDataFormatException.class.getName());
-        } catch (UTFDataFormatException expected) {
-            // Expected.
-        }
-    }
-
-    public void test_encode_lengthAtBeginning() throws Exception {
-        int testStringLength = 20000;
-        char[] charArray = new char[testStringLength];
-        for (int i = 0; i < charArray.length; i++) {
-            charArray[i] = 'A';
-        }
-        String testString = String.copyValueOf(charArray);
-
-        // Mustn't throw.
-        byte[] result = ModifiedUtf8.encode(testString);
-        ByteBuffer b = ByteBuffer.wrap(result);
-        b.order(ByteOrder.BIG_ENDIAN);
-        assertEquals(testStringLength, b.getShort());
-    }
-
-}
diff --git a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java
index 2916b03..42d0f05 100644
--- a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java
+++ b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java
@@ -600,7 +600,8 @@
         } catch (NullPointerException expected) {}
 
         try {
-            provider.newByteChannel(filesSetup.getTestPath(), new HashSet<>(), null);
+            provider.newByteChannel(filesSetup.getTestPath(), new HashSet<>(),
+                (FileAttribute<?>) null);
             fail();
         } catch (NullPointerException expected) {}
     }
diff --git a/luni/src/test/java/libcore/java/nio/file/DefaultSecureDirectoryStreamTest.java b/luni/src/test/java/libcore/java/nio/file/DefaultSecureDirectoryStreamTest.java
index 2c9c2cd..273ff8f 100644
--- a/luni/src/test/java/libcore/java/nio/file/DefaultSecureDirectoryStreamTest.java
+++ b/luni/src/test/java/libcore/java/nio/file/DefaultSecureDirectoryStreamTest.java
@@ -185,7 +185,7 @@
 
             // NPE
             try (DirectoryStream<Path> ds_path_dir1 =  ds_path_root.newDirectoryStream(path_root.
-                    relativize(path_f1), null)) {
+                    relativize(path_f1), (LinkOption) null)) {
                 fail();
             } catch (NullPointerException expected) {}
 
@@ -380,7 +380,7 @@
 
         try {
             ds_path_dir1.move(path_dir1, ds_path_dir1,
-                    Paths.get(path_root.getParent().toString(), null));
+                    Paths.get(path_root.getParent().toString(), (String) null));
             fail();
         } catch (NullPointerException expected) {}
 
@@ -498,7 +498,7 @@
         try (SecureDirectoryStream<Path> ds_path_root = (SecureDirectoryStream<Path>)
                 Files.newDirectoryStream(path_root)) {
             ds_path_root.getFileAttributeView(path_root.relativize(path_f1),
-                    BasicFileAttributeView.class, null);
+                    BasicFileAttributeView.class, (LinkOption) null);
             fail();
         } catch (NullPointerException expected) {}
     }
diff --git a/luni/src/test/java/libcore/java/nio/file/Files2Test.java b/luni/src/test/java/libcore/java/nio/file/Files2Test.java
index 436d3e3..a3357e3 100644
--- a/luni/src/test/java/libcore/java/nio/file/Files2Test.java
+++ b/luni/src/test/java/libcore/java/nio/file/Files2Test.java
@@ -1683,7 +1683,7 @@
         } catch (NullPointerException expected) {}
 
         try {
-            Files.createTempDirectory(filesSetup.getTestDirPath(), tmpDir, null);
+            Files.createTempDirectory(filesSetup.getTestDirPath(), tmpDir, (FileAttribute<?>) null);
             fail();
         } catch (NullPointerException expected) {}
     }
@@ -1710,7 +1710,7 @@
         assertEquals(attr.value(), Files.getAttribute(tmpDirPath, attr.name()));
 
         try {
-            Files.createTempDirectory(tmpDir, null);
+            Files.createTempDirectory(tmpDir, (FileAttribute<?>) null);
             fail();
         } catch (NullPointerException expected) {}
     }
@@ -1757,7 +1757,7 @@
 
         try {
             Files.createTempFile(filesSetup.getTestDirPath(), tmpFilePrefix, tmpFileSuffix,
-                    null);
+                (FileAttribute<?>) null);
             fail();
         } catch (NullPointerException expected) {}
     }
@@ -1796,7 +1796,7 @@
         assertEquals(attr.value(), Files.getAttribute(tmpFilePath, attr.name()));
 
         try {
-            Files.createTempFile(tmpFilePrefix, tmpFileSuffix, null);
+            Files.createTempFile(tmpFilePrefix, tmpFileSuffix, (FileAttribute<?>) null);
             fail();
         } catch (NullPointerException expected) {}
     }
diff --git a/luni/src/test/java/libcore/java/nio/file/LinuxPathTest.java b/luni/src/test/java/libcore/java/nio/file/LinuxPathTest.java
index e95f5bc..458804c 100644
--- a/luni/src/test/java/libcore/java/nio/file/LinuxPathTest.java
+++ b/luni/src/test/java/libcore/java/nio/file/LinuxPathTest.java
@@ -18,6 +18,7 @@
 
 import com.sun.nio.file.ExtendedWatchEventModifier;
 
+import java.nio.file.WatchEvent.Kind;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -454,7 +455,7 @@
         } catch (NullPointerException expected) {}
 
         try {
-            directory.register(watchService, null);
+            directory.register(watchService, (Kind<?>) null);
             fail();
         } catch (NullPointerException expected) {}
     }
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index a9a5318..946f602 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -55,29 +55,19 @@
 import javax.crypto.Cipher;
 import javax.crypto.EncryptedPrivateKeyInfo;
 import javax.crypto.NoSuchPaddingException;
-import junit.framework.TestCase;
 import libcore.javax.crypto.MockKey;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
-
-public class ProviderTest extends TestCase {
+public class ProviderTest extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     private static final boolean LOG_DEBUG = false;
 
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index 3750742..9c014d2 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -37,29 +37,19 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import junit.framework.TestCase;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
 import libcore.util.HexEncoding;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
-
-public class SignatureTest extends TestCase {
+public class SignatureTest extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     private static abstract class MockProvider extends Provider {
         public MockProvider(String name) {
diff --git a/luni/src/test/java/libcore/java/security/cert/CertPathValidatorTest.java b/luni/src/test/java/libcore/java/security/cert/CertPathValidatorTest.java
index 0f84e91..fc09ae8 100644
--- a/luni/src/test/java/libcore/java/security/cert/CertPathValidatorTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/CertPathValidatorTest.java
@@ -32,8 +32,9 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
-import junit.framework.TestCase;
 import libcore.java.security.TestKeyStore;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
 import org.bouncycastle.asn1.x509.CRLReason;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
 import org.bouncycastle.cert.X509CertificateHolder;
@@ -48,27 +49,16 @@
 import org.bouncycastle.operator.DigestCalculatorProvider;
 import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
-
-public class CertPathValidatorTest extends TestCase {
+public class CertPathValidatorTest extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     private OCSPResp generateOCSPResponse(X509Certificate serverCertJca, X509Certificate caCertJca,
             PrivateKey caKey, CertificateStatus status) throws Exception {
diff --git a/luni/src/test/java/libcore/java/security/cert/PKIXParametersTest.java b/luni/src/test/java/libcore/java/security/cert/PKIXParametersTest.java
index a26c631..1836aac 100644
--- a/luni/src/test/java/libcore/java/security/cert/PKIXParametersTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/PKIXParametersTest.java
@@ -16,32 +16,22 @@
 
 package libcore.java.security.cert;
 
-import junit.framework.TestCase;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.KeyStore;
 import java.security.cert.PKIXParameters;
 import libcore.java.security.TestKeyStore;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
-
-public class PKIXParametersTest extends TestCase {
+public class PKIXParametersTest extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     public void testKeyStoreConstructor() throws Exception {
         TestKeyStore server = TestKeyStore.getServer();
diff --git a/luni/src/test/java/libcore/java/security/cert/PKIXRevocationCheckerTest.java b/luni/src/test/java/libcore/java/security/cert/PKIXRevocationCheckerTest.java
index e2066ae..0e420cb 100644
--- a/luni/src/test/java/libcore/java/security/cert/PKIXRevocationCheckerTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/PKIXRevocationCheckerTest.java
@@ -14,13 +14,20 @@
 import java.util.Collections;
 import java.util.Map;
 
-import junit.framework.TestCase;
 import libcore.java.security.TestKeyStore;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
+public class PKIXRevocationCheckerTest extends TestCaseWithRules {
 
-public class PKIXRevocationCheckerTest extends TestCase {
+    // Allow access to deprecated BC algorithms in this test, so we can ensure they
+    // continue to work
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+
     PKIXRevocationChecker checker;
 
     PrivateKeyEntry entity;
@@ -31,11 +38,6 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        // Allow access to deprecated BC algorithms in this test, so we can ensure they
-        // continue to work
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-
         CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
         CertPathChecker rc = cpb.getRevocationChecker();
         assertNotNull(rc);
@@ -49,13 +51,6 @@
         issuer = intermediate.getPrivateKey("RSA", "RSA");
     }
 
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
-
     public void test_Initializes() throws Exception {
         assertEquals(0, checker.getOcspResponses().size());
         assertEquals(0, checker.getOcspExtensions().size());
diff --git a/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java b/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
index b11b40e..ca612be 100644
--- a/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/X509CRLTest.java
@@ -18,8 +18,10 @@
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 import sun.security.provider.X509Factory;
 import sun.security.x509.X509CRLImpl;
 import tests.support.resource.Support_Resources;
@@ -49,27 +51,20 @@
 import java.util.Map;
 import java.util.Set;
 
-import junit.framework.TestCase;
 import libcore.java.security.StandardNames;
 
-public class X509CRLTest extends TestCase {
+public class X509CRLTest extends TestCaseWithRules {
+
+    // Allow access to deprecated BC algorithms in this test, so we can ensure they
+    // continue to work
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
         mX509Providers = Security.getProviders("CertificateFactory.X509");
-
-        // Allow access to deprecated BC algorithms in this test, so we can ensure they
-        // continue to work
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
     }
 
     private Provider[] mX509Providers;
diff --git a/luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java b/luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java
index 95a95c0..d694214 100644
--- a/luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java
+++ b/luni/src/test/java/libcore/java/security/cert/X509CertificateTest.java
@@ -57,32 +57,26 @@
 import java.util.Locale;
 import java.util.Set;
 import javax.security.auth.x500.X500Principal;
-import junit.framework.TestCase;
 import libcore.java.security.StandardNames;
-
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 import tests.support.resource.Support_Resources;
 
-public class X509CertificateTest extends TestCase {
+public class X509CertificateTest extends TestCaseWithRules {
+
+    // Allow access to deprecated BC algorithms in this test, so we can ensure they
+    // continue to work
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
         mX509Providers = Security.getProviders("CertificateFactory.X509");
-
-        // Allow access to deprecated BC algorithms in this test, so we can ensure they
-        // continue to work
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
     }
 
     private Provider[] mX509Providers;
diff --git a/luni/src/test/java/libcore/java/text/CollatorTest.java b/luni/src/test/java/libcore/java/text/CollatorTest.java
index 75a245e..66ea0d2 100644
--- a/luni/src/test/java/libcore/java/text/CollatorTest.java
+++ b/luni/src/test/java/libcore/java/text/CollatorTest.java
@@ -22,7 +22,11 @@
 import java.text.ParseException;
 import java.text.RuleBasedCollator;
 import java.text.StringCharacterIterator;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Locale;
+import java.util.Set;
 
 public class CollatorTest extends junit.framework.TestCase {
     public void test_setStrengthI() throws Exception {
@@ -164,4 +168,15 @@
     public void testGetCollationElementIteratorCharacterIterator_de_DE() throws Exception {
         assertGetCollationElementIteratorCharacterIterator(new Locale("de", "DE", ""), "\u00e6b", 0, 1, 1, 2);
     }
+
+    public void testGetAvailableLocales_icuConsistency() {
+        Locale[] javaLocales = Collator.getAvailableLocales();
+        Locale[] icuLocales = android.icu.text.Collator.getAvailableLocales();
+        Set<Locale> javaSet = new HashSet<>(Arrays.asList(javaLocales));
+        Set<Locale> icuSet = new HashSet<>(Arrays.asList(icuLocales));
+        assertEquals(javaSet, icuSet);
+        // Assert no duplicated entries
+        assertEquals(javaLocales.length, javaSet.size());
+        assertEquals(icuLocales.length, icuSet.size());
+    }
 }
diff --git a/luni/src/test/java/libcore/java/text/DecimalFormatTest.java b/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
index 740e7a5..e2be925 100644
--- a/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
@@ -16,6 +16,7 @@
 
 package libcore.java.text;
 
+import dalvik.system.VMRuntime;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.RoundingMode;
@@ -248,11 +249,29 @@
       } catch (NullPointerException expected) {
       }
 
-      // These just ignore null.
-      df.setNegativePrefix(null);
-      df.setNegativeSuffix(null);
-      df.setPositivePrefix(null);
-      df.setPositiveSuffix(null);
+      try {
+        df.setNegativePrefix(null);
+        fail();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        df.setNegativeSuffix(null);
+        fail();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        df.setPositivePrefix(null);
+        fail();
+      } catch (NullPointerException expected) {
+      }
+
+      try {
+        df.setPositiveSuffix(null);
+        fail();
+      } catch (NullPointerException expected) {
+      }
 
       try {
         df.setRoundingMode(null);
@@ -582,7 +601,7 @@
             // toLocalizedPattern() returns no pattern separator when input pattern has no prefix.
             // Add prefixes 'AAA'/'BBB' to force pattern separator in output pattern.
             df.applyLocalizedPattern("'AAA'+0;'BBB'-0");
-            assertEquals("'AAA'+#0;'BBB'-#0", df.toLocalizedPattern());
+            assertEquals("'AAA'+0;'BBB'-0", df.toLocalizedPattern());
             assertEquals("BBB-123", df.format(-123));
         }
         // Test a locale using non-ascii-semi-colon pattern separator.
@@ -591,7 +610,7 @@
                 Locale.forLanguageTag("ar-EG"));
             assertEquals('\u061b', df.getDecimalFormatSymbols().getPatternSeparator());
             df.applyLocalizedPattern("'AAA'+\u0660\u061b'BBB'-\u0660");
-            assertEquals("'AAA'+#\u0660\u061b'BBB'-#\u0660", df.toLocalizedPattern());
+            assertEquals("'AAA'+\u0660\u061b'BBB'-\u0660", df.toLocalizedPattern());
             assertEquals("BBB-\u0661\u0662\u0663", df.format(-123));
         }
     }
@@ -635,8 +654,6 @@
         assertParsed("0; 0", " 1 ", -1, 2);
         // Leading space in prefix is accepted.
         assertParsed(" 0", " 1 ", 1, 2);
-        // Extra space after prefix with space is accepted.
-        assertParsed(" 0", "  1 ", 1, 3);
     }
 
     // http://b/68143370
@@ -653,6 +670,71 @@
         assertParseError("0", " 1");
         // Space in prefix is expected to be present.
         assertParseError(" 0", "1");
+        // Extra space after prefix with space is not tolerated.
+        assertParseError(" 0", "  1 ");
+    }
+
+    // Test that Bidi control character is not tolerated
+    public void testParseBidi() {
+        assertParseError("0", "\u200e1");
+        assertParsed("0", "1\u200e", 1, 1);
+        assertParseError("0%", "\u200e1%");
+    }
+
+    public void testParseGroupingSeparator() {
+        // Test that grouping separator is optional when the group separator is specified
+        assertParsedAndConsumedAll("#,##0", "9,999", 9999);
+        assertParsedAndConsumedAll("#,##0", "9999", 9999);
+        assertParsedAndConsumedAll("#,###0", "9,9999", 99999);
+
+        // Test that grouping size doesn't affect parsing at all
+        assertParsedAndConsumedAll("#,##0", "9,9999", 99999);
+        assertParsedAndConsumedAll("#,###0", "99,999", 99999);
+
+        assertParsedAndConsumedAll("###0", "9999", 9999);
+        assertParsedAndConsumedAll("###0", "99999", 99999);
+
+        // Test that grouping separator must not be present when the group separator is NOT specified
+        // Only the 1st character in front of separator , should be consumed.
+        assertParsed("###0", "9,9999", 9, 1);
+        assertParsed("###0", "9,999", 9, 1);
+    }
+
+    public void testParseScienificNotation() {
+        assertParsedAndConsumedAll("0.###E0", "1E-3", 0.001);
+        assertParsedAndConsumedAll("0.###E0", "1E0", 1);
+        assertParsedAndConsumedAll("0.###E0", "1E3", 1000);
+        assertParsedAndConsumedAll("0.###E0", "1.111E3", 1111);
+        assertParsedAndConsumedAll("0.###E0", "1.1E3", 1100);
+
+        // "0.###E0" is engineering notation, i.e. the exponent should be a multiple of 3
+        // for formatting. But it shouldn't affect parsing.
+        assertParsedAndConsumedAll("0.###E0", "1E1", 10);
+
+        // Test that exponent is not required for parsing
+        assertParsedAndConsumedAll("0.###E0", "1.1", 1.1);
+        assertParsedAndConsumedAll("0.###E0", "1100", 1100);
+
+        // Test that the max of fraction, integer or signficant digits don't affect parsing
+        // Note that the max of signficant digits is 4 = min integer digits (1)
+        //   + max fraction digits (3)
+        assertParsedAndConsumedAll("0.###E0", "1111.4E3", 1111400);
+        assertParsedAndConsumedAll("0.###E0", "1111.9999E3", 1111999.9);
+    }
+
+    /*
+     * ISO currency code parsing is case insensitive. http://b/112469513
+     */
+    public void testParseCurrencyIsoCode() {
+        assertParsedAndConsumedAll("¤¤0", "USD10", 10);
+        assertParsedAndConsumedAll("¤¤0", "usd10", 10);
+        assertParsedAndConsumedAll("¤¤0", "Usd10", 10);
+        assertParsedAndConsumedAll("¤¤0", "Usd10", 10);
+
+        // DecimalFormat.parse is only required to parse the local currency for the Locale
+        // associated with the DecimalFormat. assertParseError() uses Locale.US so it is expected to
+        // fail to parse valid ISO codes except for USD.
+        assertParseError("¤¤0", "GBP10");
     }
 
     // Test that getMaximumIntegerDigits should return value >= 309 by default, even though a
@@ -693,6 +775,13 @@
         }
     }
 
+    /**
+     * Assert the expected number and the whole input string is consumed and parsed successfully.
+     */
+    private static void assertParsedAndConsumedAll(String pattern, String input, Number expected) {
+        assertParsed(pattern, input, expected, input.length());
+    }
+
     private static void assertParsed(String pattern, String input, Number expected,
             int expectedIndex) {
         ParsePosition expectedPos = new ParsePosition(expectedIndex);
diff --git a/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java b/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
index 205faac..eb3f4ca 100644
--- a/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
+++ b/luni/src/test/java/libcore/java/text/OldDecimalFormatTestICU.java
@@ -60,14 +60,6 @@
         } catch (IllegalArgumentException e) {
             // expected
         }
-
-        try {
-            format.applyPattern("@.###");
-            fail("expected IllegalArgumentException was not thrown for "
-                    + "pattern \"@.###\".");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
     }
 
     // AndroidOnly: special feature of icu4c
diff --git a/luni/src/test/java/libcore/java/text/OldNumberFormatTest.java b/luni/src/test/java/libcore/java/text/OldNumberFormatTest.java
index 619f788..9df9e43 100644
--- a/luni/src/test/java/libcore/java/text/OldNumberFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/OldNumberFormatTest.java
@@ -68,7 +68,10 @@
         assertEquals("Wrong result: case 1", "23", format.format(123));
 
         format.setMaximumIntegerDigits(Integer.MIN_VALUE);
-        assertEquals("Wrong result: case 2", "0", format.format(123));
+        assertEquals("Wrong result: case 2", ".0", format.format(123));
+
+        format.setMaximumIntegerDigits(0);
+        assertEquals("Wrong result: case 2", ".0", format.format(123));
     }
 
     public void test_setCurrencyLjava_util_Currency() {
@@ -196,7 +199,7 @@
         nf2.setMaximumIntegerDigits(100);
         assertFalse("Different NumberFormat are equal", nf1.equals(nf2));
 
-        nf2.setMaximumIntegerDigits(nf1.getMaximumIntegerDigits());
+        nf1.setMaximumIntegerDigits(100);
         assertTrue("Equivalent Objects are not equal", nf1.equals(nf2));
 
         nf1 = NumberFormat.getIntegerInstance();
diff --git a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
index 2d85c1b..a4ebad3 100644
--- a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
@@ -16,16 +16,22 @@
 
 package libcore.java.text;
 
+import libcore.util.Nullable;
 import java.text.DateFormat;
 import java.text.DateFormatSymbols;
 import java.text.ParseException;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.GregorianCalendar;
+import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map;
 import java.util.TimeZone;
+import java.util.TreeMap;
 
 public class SimpleDateFormatTest extends junit.framework.TestCase {
 
@@ -771,6 +777,68 @@
         assertEquals("leden", formatDateNonGregorianCalendar("LLLLL", cs));
     }
 
+    /**
+     * This test demonstrates that optimization with special case handling of
+     * {@link java.util.SortedMap} in
+     * {@link SimpleDateFormat#matchString(java.lang.String, int, int, java.util.Map, java.text.CalendarBuilder)}
+     * is buggy. It makes use of {@link NonGregorianCalendarWithTreeMapDisplayNames}
+     * which returns {@link TreeMap} instead of {@link HashMap}.
+     *
+     * @see NonGregorianCalendarWithTreeMapDisplayNames
+     * @see http://b/119913354
+     */
+    public void testMatchStringSortedMap_treeMap() {
+        Calendar cal = new NonGregorianCalendarWithTreeMapDisplayNames(null);
+        checkMatchStringSortedMap_formatParseCzechJuly(cal);
+    }
+
+    /**
+     * Same as {@link SimpleDateFormatTest#testMatchStringSortedMap_treeMap()} but also using
+     * reverse order comparator for a {@link TreeMap} returned from
+     * {@link Calendar#getDisplayNames(int, int, java.util.Locale)}.
+     *
+     * Reverse order comparator demonstrates that even iterating key set in descending order may
+     * still behave incorrectly.
+     */
+    public void testMatchStringSortedMap_treeMapWithReverseOrderComparator() {
+        Calendar cal = new NonGregorianCalendarWithTreeMapDisplayNames(Comparator.reverseOrder());
+        checkMatchStringSortedMap_formatParseCzechJuly(cal);
+    }
+
+    /**
+     * Helper method for {@link #testMatchStringSortedMap_treeMap()} and
+     * {@link #testMatchStringSortedMap_treeMapWithReverseOrderComparator()}
+     * that formats "15 July 1997" using Czech locale. June in Czech (Červen) is a
+     * prefix of July (Červenec) which can break the logic that relies on matching
+     * first rather than longest match when parsing months names.
+     *
+     * For example, imagine matching "15 července 1997" which is "15 June 1997" in Czech.
+     * When {@link SimpleDateFormat} parses the whole string it tries to match all field names
+     * with "current" text chunk (in case of month this would match againsg "července").
+     * This set of field names in this case would contain month names in nominative and genitive
+     * cases so it contains "července" (July in genitive) and "červen" (July in nominative).
+     * Since the real answer is "července" but "červen" would still match, {@link SimpleDateFormat}
+     * picks the wrong shorter field. The next parsed field is year but parsing is attempted
+     * from "ce 1997" chunk, not from " 1997", so it fails.
+     */
+    private static void checkMatchStringSortedMap_formatParseCzechJuly(Calendar calendar) {
+        DateFormat fmt = new SimpleDateFormat("dd MMMM yyyy", new Locale("cs", "", ""));
+        calendar.clear();
+        calendar.setTimeZone(UTC);
+        fmt.setCalendar(calendar);
+
+        final String julyStr = fmt.format(new Date(97, Calendar.JULY, 15));
+
+        try {
+            Date d = fmt.parse(julyStr);
+            String s = fmt.format(d);
+            int month = d.getMonth();
+            assertEquals(Calendar.JULY, month);
+        } catch (ParseException e) {
+            fail("Exception occurred: " + e);
+        }
+    }
+
     private void assertDayPeriodParseFailure(String pattern, String source) {
         SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern, Locale.US);
         ParsePosition parsePosition = new ParsePosition(0);
@@ -866,4 +934,31 @@
         }
     }
 
+    /**
+     * A GregorianCalendar whose {@code getDisplayNames(int, int, Locale)} returns a
+     * {@link NavigableMap} which is needed to make {@link SimpleDateFormat#useDateFormatSymbols}
+     * explicitly use date format symbols for {@link #testMatchStringSortedMap_treeMap()} and
+     * {@link #testMatchStringSortedMap_treeMapWithReverseOrderComparator()} which test for usage of
+     * instances of {@link java.util.SortedMap} in
+     * {@link SimpleDateFormat#matchString(java.lang.String, int, int, java.util.Map, java.text.CalendarBuilder)}.
+     *
+     * @see http://b/119913354
+     */
+    private static class NonGregorianCalendarWithTreeMapDisplayNames extends GregorianCalendar {
+
+        private Comparator<String> mapComparator;
+
+        NonGregorianCalendarWithTreeMapDisplayNames(@Nullable Comparator<String> comparator) {
+            this.mapComparator = comparator;
+        }
+
+        @Override
+        public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
+            Map<String, Integer> result = super.getDisplayNames(field, style, locale);
+            TreeMap<String, Integer> treeMap = new TreeMap<>(this.mapComparator);
+            treeMap.putAll(result);
+            return treeMap;
+        }
+    }
+
 }
diff --git a/luni/src/test/java/libcore/java/time/chrono/JapaneseChronologyTest.java b/luni/src/test/java/libcore/java/time/chrono/JapaneseChronologyTest.java
index 3c1f0cf..5e920b3 100644
--- a/luni/src/test/java/libcore/java/time/chrono/JapaneseChronologyTest.java
+++ b/luni/src/test/java/libcore/java/time/chrono/JapaneseChronologyTest.java
@@ -15,7 +15,9 @@
  */
 package libcore.java.time.chrono;
 
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
 import java.time.Instant;
 import java.time.LocalDate;
 import java.time.LocalTime;
@@ -26,10 +28,11 @@
 import java.time.chrono.JapaneseChronology;
 import java.time.chrono.JapaneseDate;
 import java.time.chrono.JapaneseEra;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
 import java.time.temporal.ChronoField;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
+import java.util.Locale;
+import org.junit.Test;
 
 /**
  * Additional tests for {@link JapaneseChronology} and {@link JapaneseDate}.
@@ -110,4 +113,35 @@
         assertEquals(true, date.isSupported(ChronoField.YEAR));
         assertEquals(true, date.isSupported(ChronoField.YEAR_OF_ERA));
     }
+
+    @Test
+    public void test_JapaneseEras_dateTimeFormatter() {
+        DateTimeFormatter formatter = DateTimeFormatter
+            .ofLocalizedDate(FormatStyle.FULL)
+            .withChronology(JapaneseChronology.INSTANCE);
+
+        final LocalDate heisei = LocalDate.of(2018, 1, 1);
+        final Locale ja = Locale.forLanguageTag("ja-JP-u-ca-japanese");
+        assertEquals("平成30年1月1日月曜日", heisei.format(formatter.withLocale(ja)));
+        assertEquals("Monday, January 1, 30 Heisei",
+            heisei.format(formatter.withLocale(Locale.ENGLISH)));
+
+        final LocalDate reiwa = LocalDate.of(2019, 5, 1);
+        assertEquals("令和1年5月1日水曜日", reiwa.format(formatter.withLocale(ja)));
+        assertEquals("Wednesday, May 1, 1 Reiwa",
+            reiwa.format(formatter.withLocale(Locale.ENGLISH)));
+    }
+
+    // This tests era names from calendars.properties file
+    @Test
+    public void test_JapaneseEras_calendarsDotProperties() {
+        final LocalDate heisei = LocalDate.of(2018, 1, 1);
+        final LocalDate reiwa = LocalDate.of(2019, 5, 1);
+        JapaneseDate heiseiDate = JapaneseChronology.INSTANCE.date(heisei);
+        JapaneseDate reiwaDate = JapaneseChronology.INSTANCE.date(reiwa);
+
+        assertEquals("Heisei", heiseiDate.getEra().toString());
+        assertEquals("Reiwa", reiwaDate.getEra().toString());
+    }
+
 }
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/ArraysTest.java b/luni/src/test/java/libcore/java/util/ArraysTest.java
index b48e8ea..5a2bfe2 100644
--- a/luni/src/test/java/libcore/java/util/ArraysTest.java
+++ b/luni/src/test/java/libcore/java/util/ArraysTest.java
@@ -16,15 +16,31 @@
 
 package libcore.java.util;
 
-import java.util.Arrays;
-import java.util.Random;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-public class ArraysTest extends junit.framework.TestCase {
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ArraysTest {
+    private static final int[] TEST_ARRAY_SIZES = { 0, 1, 2, 10, 100, 1000 };
+
 
     /**
      * java.util.Arrays#setAll(int[], java.util.function.IntUnaryOperator)
      */
-    public void test_setAll$I() {
+    @Test
+    public void setAll$I() {
         int[] list = new int[3];
         list[0] = 0;
         list[1] = 1;
@@ -51,7 +67,8 @@
     /**
      * java.util.Arrays#parallelSetAll(int[], java.util.function.IntUnaryOperator)
      */
-    public void test_parallelSetAll$I() {
+    @Test
+    public void parallelSetAll$I() {
         int[] list = new int[3];
         list[0] = 0;
         list[1] = 1;
@@ -78,7 +95,8 @@
     /**
      * java.util.Arrays#setAll(long[], java.util.function.IntToLongFunction)
      */
-    public void test_setAll$L() {
+    @Test
+    public void setAll$L() {
         long[] list = new long[3];
         list[0] = 0;
         list[1] = 1;
@@ -105,7 +123,8 @@
     /**
      * java.util.Arrays#parallelSetAll(long[], java.util.function.IntToLongFunction)
      */
-    public void test_parallelSetAll$L() {
+    @Test
+    public void parallelSetAll$L() {
         long[] list = new long[3];
         list[0] = 0;
         list[1] = 1;
@@ -132,16 +151,17 @@
     /**
      * java.util.Arrays#setAll(double[], java.util.function.IntToDoubleFunction)
      */
-    public void test_setAll$D() {
+    @Test
+    public void setAll$D() {
         double[] list = new double[3];
         list[0] = 0.0d;
         list[1] = 1.0d;
         list[2] = 2.0d;
 
         Arrays.setAll(list, x -> x + 0.5);
-        assertEquals(0.5d, list[0]);
-        assertEquals(1.5d, list[1]);
-        assertEquals(2.5d, list[2]);
+        assertEquals(0.5d, list[0], 0.0);
+        assertEquals(1.5d, list[1], 0.0);
+        assertEquals(2.5d, list[2], 0.0);
 
         try {
             Arrays.setAll(list, null);
@@ -159,16 +179,17 @@
     /**
      * java.util.Arrays#parallelSetAll(double[], java.util.function.IntToDoubleFunction)
      */
-    public void test_parallelSetAll$D() {
+    @Test
+    public void parallelSetAll$D() {
         double[] list = new double[3];
         list[0] = 0.0d;
         list[1] = 1.0d;
         list[2] = 2.0d;
 
         Arrays.parallelSetAll(list, x -> x + 0.5);
-        assertEquals(0.5d, list[0]);
-        assertEquals(1.5d, list[1]);
-        assertEquals(2.5d, list[2]);
+        assertEquals(0.5d, list[0], 0.0);
+        assertEquals(1.5d, list[1], 0.0);
+        assertEquals(2.5d, list[2], 0.0);
 
         try {
             Arrays.parallelSetAll(list, null);
@@ -186,7 +207,8 @@
     /**
      * java.util.Array#setAll(T[], java.util.function.IntFunction<\? extends T>)
      */
-    public void test_setAll$T() {
+    @Test
+    public void setAll$T() {
         String[] strings = new String[3];
         strings[0] = "a";
         strings[0] = "b";
@@ -213,7 +235,8 @@
     /**
      * java.util.Array#parallelSetAll(T[], java.util.function.IntFunction<\? extends T>)
      */
-    public void test_parallelSetAll$T() {
+    @Test
+    public void parallelSetAll$T() {
         String[] strings = new String[3];
         strings[0] = "a";
         strings[0] = "b";
@@ -240,7 +263,8 @@
     /**
      * java.util.Array#parallelPrefix(int[], java.util.function.IntBinaryOperator)
      */
-    public void test_parallelPrefix$I() {
+    @Test
+    public void parallelPrefix$I() {
         // Get an arbitrary array of ints.
         Random rand = new Random(0);
         int[] list = new int[1000];
@@ -256,7 +280,7 @@
         }
 
         Arrays.parallelPrefix(list, (x, y) -> x + y);
-        assertTrue(Arrays.equals(seqResult, list));
+        assertArrayEquals(seqResult, list);
 
         try {
             Arrays.parallelPrefix(list, null);
@@ -274,7 +298,8 @@
     /**
      * java.util.Array#parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator)
      */
-    public void test_parallelPrefix$III() {
+    @Test
+    public void parallelPrefix$III() {
         // Get an arbitrary array of ints.
         Random rand = new Random(0);
         int[] list = new int[1000];
@@ -291,7 +316,7 @@
         }
 
         Arrays.parallelPrefix(list, begin, end, (x, y) -> x + y);
-        assertTrue(Arrays.equals(seqResult, list));
+        assertArrayEquals(seqResult, list);
 
         try {
             Arrays.parallelPrefix(list, begin, end, null);
@@ -315,7 +340,8 @@
     /**
      * java.util.Array#parallelPrefix(long[], java.util.function.LongBinaryOperator)
      */
-    public void test_parallelPrefix$L() {
+    @Test
+    public void parallelPrefix$L() {
         // Get an arbitrary array of ints.
         Random rand = new Random(0);
         long[] list = new long[1000];
@@ -331,7 +357,7 @@
         }
 
         Arrays.parallelPrefix(list, (x, y) -> x + y);
-        assertTrue(Arrays.equals(seqResult, list));
+        assertArrayEquals(seqResult, list);
 
         try {
             Arrays.parallelPrefix(list, null);
@@ -349,7 +375,8 @@
     /**
      * java.util.Array#parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator)
      */
-    public void test_parallelPrefix$LII() {
+    @Test
+    public void parallelPrefix$LII() {
         // Get an arbitrary array of ints.
         Random rand = new Random(0);
         long[] list = new long[1000];
@@ -366,7 +393,7 @@
         }
 
         Arrays.parallelPrefix(list, begin, end, (x, y) -> x + y);
-        assertTrue(Arrays.equals(seqResult, list));
+        assertArrayEquals(seqResult, list);
 
         try {
             Arrays.parallelPrefix(list, begin, end, null);
@@ -390,7 +417,8 @@
     /**
      * java.util.Array#parallelPrefix(double[], java.util.function.DoubleBinaryOperator)
      */
-    public void test_parallelPrefix$D() {
+    @Test
+    public void parallelPrefix$D() {
         // Get an arbitrary array of ints.
         Random rand = new Random(0);
         double[] list = new double[1000];
@@ -410,7 +438,7 @@
         // Parallel double arithmetic contains error, reduce to integer for comparison.
         int[] listInInt = Arrays.stream(list).mapToInt(x -> (int) x).toArray();
         int[] seqResultInInt = Arrays.stream(seqResult).mapToInt(x -> (int) x).toArray();
-        assertTrue(Arrays.equals(seqResultInInt, listInInt));
+        assertArrayEquals(seqResultInInt, listInInt);
 
         try {
             Arrays.parallelPrefix(list, null);
@@ -428,7 +456,8 @@
     /**
      * java.util.Array#parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator)
      */
-    public void test_parallelPrefix$DII() {
+    @Test
+    public void parallelPrefix$DII() {
         // Get an arbitrary array of ints.
         Random rand = new Random(0);
         double[] list = new double[1000];
@@ -449,7 +478,7 @@
         // Parallel double arithmetic contains error, reduce to integer for comparison.
         int[] listInInt = Arrays.stream(list).mapToInt(x -> (int) x).toArray();
         int[] seqResultInInt = Arrays.stream(seqResult).mapToInt(x -> (int) x).toArray();
-        assertTrue(Arrays.equals(seqResultInInt, listInInt));
+        assertArrayEquals(seqResultInInt, listInInt);
 
         try {
             Arrays.parallelPrefix(list, begin, end, null);
@@ -473,7 +502,8 @@
     /**
      * java.util.Array#parallelPrefix(T[], java.util.function.BinaryOperator<T>)
      */
-    public void test_parallelPrefix$T() {
+    @Test
+    public void parallelPrefix$T() {
         String[] strings = new String[3];
         strings[0] = "a";
         strings[1] = "b";
@@ -500,7 +530,8 @@
     /**
      * java.util.Array#parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>)
      */
-    public void test_parallelPrefix$TII() {
+    @Test
+    public void parallelPrefix$TII() {
         String[] strings = new String[5];
         strings[0] = "a";
         strings[1] = "b";
@@ -536,9 +567,389 @@
     }
 
     // http://b/74236526
-    public void test_deepEquals_nestedArraysOfDifferentTypesButEqualValues() {
+    @Test
+    public void deepEquals_nestedArraysOfDifferentTypesButEqualValues() {
         assertTrue(Arrays.deepEquals(
             new Object[] { new Object[] { "Hello", "world" } },
             new Object[] { new String[] { "Hello", "world" } }));
     }
+
+    @Test
+    public void streamInt() {
+        for (int size : TEST_ARRAY_SIZES) {
+            int[] sourceArray = intTestArray(size);
+
+            // Stream, map, accumulate
+            int sum = Arrays.stream(sourceArray)
+                .map(i -> i + i)
+                .sum();
+            assertEquals(size * (size - 1), sum);
+
+            // Stream, collect as array again
+            int[] destArray = Arrays.stream(sourceArray)
+                .toArray();
+            assertArrayEquals(sourceArray, destArray);
+            assertNotSame(sourceArray, destArray);
+
+            // Stream, box, collect as list
+            List<Integer> destList = Arrays.stream(sourceArray)
+                .boxed()
+                .collect(Collectors.toList());
+
+            assertEquals(size, destList.size());
+            for (int i = 0; i < size; i++) {
+                assertEquals((int) destList.get(i), i);
+            }
+        }
+    }
+
+    @Test
+    public void streamIntStartEnd() {
+        final int size = 10;
+        int[] sourceArray = intTestArray(size);
+        for (int start = 0; start < size - 1; start++) {
+            for (int end = start; end < size; end++) {
+                int[] destArray = Arrays.stream(sourceArray, start, end)
+                    .toArray();
+                int len = end - start;
+                assertEquals(len, destArray.length);
+                if (len > 0) {
+                    assertEquals(start, destArray[0]);
+                    assertEquals(end - 1, destArray[len - 1]);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void streamIntStartEnd_Exceptions() {
+        int[] sourceArray = intTestArray(10);
+        try {
+            int unused = Arrays.stream(sourceArray, -1, 9)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            int unused = Arrays.stream(sourceArray, 0, 11)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            int unused = Arrays.stream(sourceArray, 11, 11)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            int unused = Arrays.stream(sourceArray, 0, -1)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            int unused = Arrays.stream(sourceArray, 4, 3)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void streamLong() {
+        for (int size : TEST_ARRAY_SIZES) {
+            long[] sourceArray = longTestArray(size);
+
+            // Stream, map, accumulate
+            long sum = Arrays.stream(sourceArray)
+                .map(i -> i + i)
+                .sum();
+            assertEquals(size * (size - 1), sum);
+
+            // Stream, collect as array again
+            long[] destArray = Arrays.stream(sourceArray)
+                .toArray();
+            assertArrayEquals(sourceArray, destArray);
+            assertNotSame(sourceArray, destArray);
+
+            // Stream, box, collect as list
+            List<Long> destList = Arrays.stream(sourceArray)
+                .boxed()
+                .collect(Collectors.toList());
+
+            assertEquals(size, destList.size());
+            for (int i = 0; i < size; i++) {
+                assertEquals((long) destList.get(i), i);
+            }
+        }
+    }
+
+    @Test
+    public void streamLongStartEnd() {
+        final int size = 10;
+        long[] sourceArray = longTestArray(size);
+        for (int start = 0; start < size - 1; start++) {
+            for (int end = start; end < size; end++) {
+                long[] destArray = Arrays.stream(sourceArray, start, end)
+                    .toArray();
+                int len = end - start;
+                assertEquals(len, destArray.length);
+                if (len > 0) {
+                    assertEquals(start, destArray[0]);
+                    assertEquals(end - 1, destArray[len - 1]);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void streamLongStartEnd_Exceptions() {
+        long[] sourceArray = longTestArray(10);
+        try {
+            long unused = Arrays.stream(sourceArray, -1, 9)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            long unused = Arrays.stream(sourceArray, 0, 11)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            long unused = Arrays.stream(sourceArray, 11, 11)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            long unused = Arrays.stream(sourceArray, 0, -1)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            long unused = Arrays.stream(sourceArray, 4, 3)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void streamDouble() {
+        for (int size : TEST_ARRAY_SIZES) {
+            double[] sourceArray = doubleTestArray(size);
+
+            // Stream, map, accumulate
+            double sum = Arrays.stream(sourceArray)
+                .map(i -> i + i)
+                .sum();
+            assertEquals(size * (size - 1), sum, 0.001);
+
+            // Stream, collect as array again
+            double[] destArray = Arrays.stream(sourceArray)
+                .toArray();
+            assertArrayEquals(sourceArray, destArray, 0.001);
+            assertNotSame(sourceArray, destArray);
+
+            // Stream, box, collect as list
+            List<Double> destList = Arrays.stream(sourceArray)
+                .boxed()
+                .collect(Collectors.toList());
+
+            assertEquals(size, destList.size());
+            for (int i = 0; i < size; i++) {
+                assertEquals(destList.get(i), i, 0.001);
+            }
+        }
+    }
+
+    @Test
+    public void streamDoubleStartEnd() {
+        final int size = 10;
+        double[] sourceArray = doubleTestArray(size);
+        for (int start = 0; start < size - 1; start++) {
+            for (int end = start; end < size; end++) {
+                double[] destArray = Arrays.stream(sourceArray, start, end)
+                    .toArray();
+                int len = end - start;
+                assertEquals(len, destArray.length);
+                if (len > 0) {
+                    assertEquals(start, destArray[0], 0.0);
+                    assertEquals(end - 1, destArray[len - 1], 0.0);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void streamDoubleStartEnd_Exceptions() {
+        double[] sourceArray = doubleTestArray(10);
+        try {
+            double unused = Arrays.stream(sourceArray, -1, 9)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            double unused = Arrays.stream(sourceArray, 0, 11)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            double unused = Arrays.stream(sourceArray, 11, 11)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            double unused = Arrays.stream(sourceArray, 0, -1)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            double unused = Arrays.stream(sourceArray, 4, 3)
+                .sum();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void streamObject() {
+      for (int size : TEST_ARRAY_SIZES) {
+        String[] sourceArray = stringTestArray(size);
+
+        // Stream, map, accumulate
+        int sum = Arrays.stream(sourceArray)
+            .mapToInt(i -> Integer.parseInt(i) * 2)
+            .sum();
+        assertEquals(size * (size - 1), sum);
+
+        // Stream, collect as array again
+        String[] destArray = Arrays.stream(sourceArray)
+            .toArray(String[]::new);
+        assertArrayEquals(sourceArray, destArray);
+        assertNotSame(sourceArray, destArray);
+
+        // Stream, collect as list
+        List<String> destList = Arrays.stream(sourceArray)
+            .collect(Collectors.toList());
+
+        assertEquals(size, destList.size());
+        for (int i = 0; i < size; i++) {
+          assertSame(destList.get(i), sourceArray[i]);
+        }
+      }
+    }
+
+    @Test
+    public void streamObjectStartEnd() {
+        final int size = 10;
+        String[] sourceArray = stringTestArray(size);
+        for (int start = 0; start < size - 1; start++) {
+            for (int end = start; end < size; end++) {
+                String[] destArray = Arrays.stream(sourceArray, start, end)
+                    .toArray(String[]::new);
+                int len = end - start;
+                assertEquals(len, destArray.length);
+                if (len > 0) {
+                    assertSame(sourceArray[start], destArray[0]);
+                    assertSame(sourceArray[end - 1], destArray[len - 1]);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void streamObjectStartEnd_Exceptions() {
+        String[] sourceArray = stringTestArray(10);
+        try {
+            long unused = Arrays.stream(sourceArray, -1, 9)
+                .count();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            long unused = Arrays.stream(sourceArray, 0, 11)
+                .count();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            long unused = Arrays.stream(sourceArray, 11, 11)
+                .count();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            long unused = Arrays.stream(sourceArray, 0, -1)
+                .count();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+        try {
+            long unused = Arrays.stream(sourceArray, 4, 3)
+                .count();
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Expected
+        }
+    }
+
+    private int[] intTestArray(int size) {
+        int[] array = new int[size];
+        for (int i = 0; i < size; i++) {
+            array[i] = i;
+        }
+        return array;
+    }
+
+    private long[] longTestArray(int size) {
+        long[] array = new long[size];
+        for (int i = 0; i < size; i++) {
+            array[i] = i;
+        }
+        return array;
+    }
+
+    private double[] doubleTestArray(int size) {
+        double[] array = new double[size];
+        for (int i = 0; i < size; i++) {
+            array[i] = i;
+        }
+        return array;
+    }
+
+    private String[] stringTestArray(int size) {
+        String[] array = new String[size];
+        for (int i = 0; i < size; i++) {
+            array[i] = String.valueOf(i);
+        }
+        return array;
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/ComparatorTest.java b/luni/src/test/java/libcore/java/util/ComparatorTest.java
index a636ea6..6516df5 100644
--- a/luni/src/test/java/libcore/java/util/ComparatorTest.java
+++ b/luni/src/test/java/libcore/java/util/ComparatorTest.java
@@ -16,6 +16,7 @@
 
 package libcore.java.util;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
@@ -35,17 +36,22 @@
     private static final Item ONEZERO = new Item(1, 0);
     private static final Item ONEONE = new Item(1, 1);
 
-    private static final Item[] orderedItems = new Item[]{ZERO, ONE, TWO, THREE, FOUR};
-    private static final Item[] nullsFirstItems = new Item[]{null, ZERO, ONE, TWO, THREE, FOUR};
-    private static final Item[] nullsLastItems = new Item[]{ZERO, ONE, TWO, THREE, FOUR, null};
-    private static final Item[] orderedItemsMatrix = new Item[]{ZEROZERO, ZEROONE, ONEZERO, ONEONE};
+    private final List<Item> orderedItems = listOf(ZERO, ONE, TWO, THREE, FOUR);
+    private final List<Item> nullsFirstItems = listOf(null, ZERO, ONE, TWO, THREE, FOUR);
+    private final List<Item> nullsLastItems = listOf(ZERO, ONE, TWO, THREE, FOUR, null);
+    private final List<Item> orderedItemsMatrix = listOf(ZEROZERO, ZEROONE, ONEZERO, ONEONE);
 
-    private <T> void checkComparison(Comparator<T> comparator, T[] items) {
-        for (int i = 0; i < items.length - 1; ++i) {
-            assertEquals(0, comparator.compare(items[i], items[i]));
-            for (int j = i + 1; j < items.length; ++j) {
-                assertTrue(comparator.compare(items[i], items[j]) < 0);
-                assertTrue(comparator.compare(items[j], items[i]) > 0);
+    private static<T> List<T> listOf(T... values) {
+        return Collections.unmodifiableList(Arrays.asList(values));
+    }
+
+    private <T> void checkComparison(Comparator<T> comparator, List<T> items) {
+        for (int i = 0; i < items.size() - 1; ++i) {
+            T a = items.get(i);
+            assertEquals(0, comparator.compare(a, a));
+            for (T b : items.subList(i+1, items.size())) {
+                assertTrue(comparator.compare(a, b) < 0);
+                assertTrue(comparator.compare(b, a) > 0);
             }
         }
     }
@@ -83,10 +89,11 @@
     }
 
     public void testReverseOrder() {
-        List<Item> itemsList = Arrays.asList(orderedItems);
+        // Make a copy that we can reverse. http://b/139015474
+        List<Item> itemsList = new ArrayList<>(orderedItems);
         Collections.reverse(itemsList);
         Comparator<Item> comparator = Comparator.reverseOrder();
-        checkComparison(comparator, (Item[]) itemsList.toArray());
+        checkComparison(comparator, itemsList);
     }
 
     public void testReverse() {
diff --git a/luni/src/test/java/libcore/java/util/DateTest.java b/luni/src/test/java/libcore/java/util/DateTest.java
index 1fd8193..9cd9868 100644
--- a/luni/src/test/java/libcore/java/util/DateTest.java
+++ b/luni/src/test/java/libcore/java/util/DateTest.java
@@ -51,18 +51,14 @@
         c.set(Calendar.YEAR, 21);
         assertEquals("Wed Jan 01 00:00:00 PST 21", c.getTime().toString());
         String actual21GmtString = c.getTime().toGMTString();
-        // zic <= 2014b data gives -08:00:00, later ones gives -07:52:58 instead. http://b/73719425
-        assertTrue("Actual: " + actual21GmtString,
-                "1 Jan 21 07:52:58 GMT".equals(actual21GmtString)
-                        || "1 Jan 21 08:00:00 GMT".equals(actual21GmtString));
+        // zic <= 2014b data produces -08:00:00, later ones produce -07:52:58 instead.
+        assertEquals("1 Jan 21 07:52:58 GMT", actual21GmtString);
 
         c.set(Calendar.YEAR, 321);
         assertEquals("Sun Jan 01 00:00:00 PST 321", c.getTime().toString());
         String actual321GmtString = c.getTime().toGMTString();
-        // zic <= 2014b data gives -08:00:00, later ones gives -07:52:58 instead. http://b/73719425
-        assertTrue("Actual: " + actual321GmtString,
-                "1 Jan 321 07:52:58 GMT".equals(actual321GmtString)
-                        || "1 Jan 321 08:00:00 GMT".equals(actual321GmtString));
+        // zic <= 2014b data produces -08:00:00, later ones produce -07:52:58 instead.
+        assertEquals("1 Jan 321 07:52:58 GMT", actual321GmtString);
     }
 
     public void test_toGMTString_nonUs() throws Exception {
@@ -74,18 +70,14 @@
         c.set(Calendar.YEAR, 21);
         assertEquals("Wed Jan 01 00:00:00 PST 21", c.getTime().toString());
         String actual21GmtString = c.getTime().toGMTString();
-        // zic <= 2014b data gives -08:00:00, later ones gives -07:52:58 instead. http://b/73719425
-        assertTrue("Actual: " + actual21GmtString,
-                "1 Jan 21 07:52:58 GMT".equals(actual21GmtString)
-                        || "1 Jan 21 08:00:00 GMT".equals(actual21GmtString));
+        // zic <= 2014b data produces -08:00:00, later ones produce -07:52:58 instead.
+        assertEquals("1 Jan 21 07:52:58 GMT", actual21GmtString);
 
         c.set(Calendar.YEAR, 321);
         assertEquals("Sun Jan 01 00:00:00 PST 321", c.getTime().toString());
         String actual321GmtString = c.getTime().toGMTString();
-        // zic <= 2014b data gives -08:00:00, later ones gives -07:52:58 instead. http://b/73719425
-        assertTrue("Actual: " + actual321GmtString,
-                "1 Jan 321 07:52:58 GMT".equals(actual321GmtString)
-                        || "1 Jan 321 08:00:00 GMT".equals(actual321GmtString));
+        // zic <= 2014b data produces -08:00:00, later ones produce -07:52:58 instead.
+        assertEquals("1 Jan 321 07:52:58 GMT", actual321GmtString);
     }
 
     public void test_parse_timezones() {
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/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java
index 33e427c..6cb9e17 100644
--- a/luni/src/test/java/libcore/java/util/LocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/LocaleTest.java
@@ -22,6 +22,7 @@
 import static java.util.Locale.FilteringMode.MAP_EXTENDED_RANGES;
 import static java.util.Locale.FilteringMode.REJECT_EXTENDED_RANGES;
 
+import android.icu.util.ULocale;
 import java.io.ObjectInputStream;
 import java.text.BreakIterator;
 import java.text.Collator;
@@ -30,13 +31,17 @@
 import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.IllformedLocaleException;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale.LanguageRange;
 import java.util.MissingResourceException;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 public class LocaleTest extends junit.framework.TestCase {
 
@@ -156,12 +161,10 @@
 
     public void test_getDisplayCountry_8870289() throws Exception {
         assertEquals("Hong Kong", new Locale("", "HK").getDisplayCountry(Locale.US));
-        assertEquals("Macau", new Locale("", "MO").getDisplayCountry(Locale.US));
         assertEquals("Palestine", new Locale("", "PS").getDisplayCountry(Locale.US));
 
         assertEquals("Cocos (Keeling) Islands", new Locale("", "CC").getDisplayCountry(Locale.US));
         assertEquals("Falkland Islands (Islas Malvinas)", new Locale("", "FK").getDisplayCountry(Locale.US));
-        assertEquals("Macedonia (FYROM)", new Locale("", "MK").getDisplayCountry(Locale.US));
         assertEquals("Myanmar (Burma)", new Locale("", "MM").getDisplayCountry(Locale.US));
         assertEquals("Taiwan", new Locale("", "TW").getDisplayCountry(Locale.US));
     }
@@ -234,6 +237,19 @@
         assertOnce(newLocale, Locale.getAvailableLocales());
     }
 
+    public void testGetAvailableLocales_icuConsistency() {
+        Locale[] javaLocales = Locale.getAvailableLocales();
+        ULocale[] icuLocales = ULocale.getAvailableLocales();
+        Set<Locale> javaSet = new HashSet<>(Arrays.asList(javaLocales));
+        Set<Locale> icuSet = Arrays.stream(icuLocales)
+            .map(uLocale -> uLocale.toLocale())
+            .collect(Collectors.toSet());
+        assertEquals(javaSet, icuSet);
+        // Assert no duplicated entries
+        assertEquals(javaLocales.length, javaSet.size());
+        assertEquals(icuLocales.length, icuSet.size());
+    }
+
     private static void assertOnce(Locale element, Locale[] array) {
         int count = 0;
         for (Locale l : array) {
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/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 6297080..da4a04f 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -59,7 +59,7 @@
 
     // http://code.google.com/p/android/issues/detail?id=14395
     public void testPreHistoricInDaylightTime() {
-        // A replacement for testPreHistoricInDaylightTime_old() using a zone that still lacks an
+        // A replacement for testPreHistoricInDaylightTime_old() using a zone that lacks an
         // explicit transition at Integer.MIN_VALUE with zic 2019a and 2019a data.
         TimeZone tz = TimeZone.getTimeZone("CET");
 
@@ -76,9 +76,7 @@
     public void testPreHistoricInDaylightTime_old() throws Exception {
         // Originally this test was intended to assert what happens when the first transition for a
         // time zone was a "to DST" transition. i.e. that the (implicit) offset / DST state before
-        // the first was treated as a non-DST state. Since zic version 2014c some zones have an
-        // explicit non-DST transition at time -2^31 seconds so it is no longer possible to test
-        // this with America/Los_Angeles.
+        // the first was treated as a non-DST state. With the latest data this is no longer true.
         // This regression test has been kept in case that changes again in future and to prove the
         // behavior has remained consistent.
 
@@ -92,7 +90,7 @@
         assertFalse(tz.inDaylightTime(date));
         assertEquals("Fri Oct 31 08:00:00 PST 1902", date.toString());
         assertEquals("31 Oct 1902 16:00:00 GMT", date.toGMTString());
-        // For zic versions <= 2014b, this would be before the first transition.
+        // For zic versions <= 2014b with 32-bit data, this would be before the first transition.
         date = sdf.parse("1902-06-01T00:00:00.000+0800");
         assertEquals(-28800000, tz.getOffset(date.getTime()));
         assertFalse(tz.inDaylightTime(date));
@@ -109,7 +107,7 @@
         // prehistoric offsets. http://b/118835133
         // "Africa/Bissau" has just a few known transitions:
         // Transition time             : Offset    : DST / non-DST
-        // <Integer.MIN_VALUE secs>[1] : -01:02:20 : non-DST
+        // <Before first transition>[1]: -01:02:20 : non-DST
         // 1912-01-01 01:00:00 GMT     : -01:00:00 : non-DST
         // 1975-01-01 01:00:00 GMT     :  00:00:00 : non-DST
         //
@@ -117,7 +115,8 @@
         // generate the data. When implicit, the first non-DST type defn should be used.
         TimeZone tz = TimeZone.getTimeZone("Africa/Bissau");
 
-        // Times before Integer.MIN_VALUE should assume we're using the first non-DST type.
+        // Integer.MIN_VALUE seconds should not be significant for TimeZone on Android since it
+        // switched to using 64-bit data but we try a time before to make sure that is true.
         assertNonDaylightOffset(-3740, parseIsoTime("1900-01-01T00:00:00.0+0000"), tz);
 
         // Time before 1912-01-01 01:00:00 but after Integer.MIN_VALUE.
@@ -351,11 +350,6 @@
      * calculations. A bug (http://b/18839557) was reported when someone noticed that Android's
      * TimeZone didn't produce the same answers as other libraries at times just outside the range
      * of Integer seconds. The reason was because of int overflow / underflow which has been fixed.
-     * At the time of writing, Android's java.util.TimeZone implementation only supports reading
-     * TZif version 1 data (32-bit times) and provides one additional "before first transition"
-     * type. This makes Android's time zone information outside of the Integer range unreliable and
-     * unlikely to match libraries that use 64-bit times for transitions and/or calculate times
-     * outside of the range using rules (e.g. like ICU4J does).
      */
     public void testOverflowing32BitUnixDates() {
         final TimeZone tz = TimeZone.getTimeZone("America/New_York");
@@ -370,14 +364,8 @@
         // This timezone didn't have any daylight savings prior to 1917 and this date is in 1900.
         assertFalse(tz.inDaylightTime(new Date(lowerTimeMillis)));
 
-        // http://b/118835133:
-        // zic <= 2014b produces data that suggests before -1633280400 seconds (Sun, 31 Mar 1918
-        // 07:00:00 GMT) the offset was -18000000.
-        // zic > 2014b produces data that suggests before Integer.MIN_VALUE seconds the offset was
-        // -17762000 and between Integer.MIN_VALUE and -1633280400 it was -18000000. Once Android
-        // moves to zic > 2014b the -18000000 can be removed. http://b/73719425
         int actualOffset = tz.getOffset(lowerTimeMillis);
-        assertTrue(-18000000 == actualOffset || -17762000 == actualOffset);
+        assertEquals(-18000000, actualOffset);
 
         // Nov 30th 2039, no daylight savings as per current rules.
         assertFalse(tz.inDaylightTime(new Date(upperTimeMillis)));
diff --git a/luni/src/test/java/libcore/java/util/logging/OldFileHandlerTest.java b/luni/src/test/java/libcore/java/util/logging/OldFileHandlerTest.java
index ead0b2e..c9f4d31 100644
--- a/luni/src/test/java/libcore/java/util/logging/OldFileHandlerTest.java
+++ b/luni/src/test/java/libcore/java/util/logging/OldFileHandlerTest.java
@@ -74,12 +74,12 @@
         File file = new File(TEMPPATH + SEP + "log");
         file.mkdir();
         manager.readConfiguration(propertiesToInputStream(props));
-        handler = new FileHandler();
         r = new LogRecord(Level.CONFIG, "msg");
     }
 
     protected void tearDown() throws Exception {
         if (null != handler) {
+            // Close handler created in setup to ensure that its lock is released.
             handler.close();
         }
         reset(TEMPPATH + SEP + "log", "");
@@ -93,6 +93,7 @@
     }
 
     public void testFileHandler() throws Exception {
+        handler = new FileHandler();
         assertEquals("character encoding is non equal to actual value",
                 "iso-8859-1", handler.getEncoding());
         assertNotNull("Filter is null", handler.getFilter());
@@ -115,7 +116,6 @@
     }
 
     public void testFileHandler_1params() throws Exception {
-
         handler = new FileHandler("%t/log/string");
         assertEquals("character encoding is non equal to actual value",
                 "iso-8859-1", handler.getEncoding());
@@ -466,11 +466,10 @@
     }
 
     public void testClose() throws Exception {
-        FileHandler h = new FileHandler("%t/log/stringPublish");
-        h.publish(r);
-        h.close();
-        assertFileContent(TEMPPATH + SEP + "log", "stringPublish", h
-                .getFormatter());
+        handler = new FileHandler("%t/log/stringPublish");
+        handler.publish(r);
+        handler.close();
+        assertFileContent(TEMPPATH + SEP + "log", "stringPublish", handler.getFormatter());
     }
 
     /*
diff --git a/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java b/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
index 99c7116..c2d56ae 100644
--- a/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
+++ b/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
@@ -718,6 +718,29 @@
             "0123zxx".replaceAll("(?<numbers>[0-9]+)", "a${other}");
             fail();
         } catch(IllegalArgumentException expected) {}
+
+        // group name is numeric
+        try {
+            "0123zxx".replaceAll("(?<numbers>[0-9]+)", "a${1}");
+            fail();
+        } catch(IllegalArgumentException expected) {}
+
+        // named group has the same prefix, i.e. numbers, but with additional number.
+        try {
+            "0123zxx".replaceAll("(?<numbers>[0-9]+)", "a${numbers1}");
+            fail();
+        } catch(IllegalArgumentException expected) {}
+
     }
 
+    public void testOptionalCapturingGroupReplace() {
+        Pattern pattern = Pattern.compile("(a)(b)?c");
+        assertEquals("_a_b_", pattern.matcher("abc").replaceAll("_$1_$2_"));
+        assertEquals("_a__", pattern.matcher("ac").replaceAll("_$1_$2_"));
+
+        // Test optopnal named-captureing group
+        pattern = Pattern.compile("(a)(?<name1>b)?c");
+        assertEquals("_a_b_", pattern.matcher("abc").replaceAll("_$1_${name1}_"));
+        assertEquals("_a__", pattern.matcher("ac").replaceAll("_$1_${name1}_"));
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/stream/StreamTest.java b/luni/src/test/java/libcore/java/util/stream/StreamTest.java
new file mode 100644
index 0000000..5f8f254
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/stream/StreamTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.stream;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import java.util.stream.Stream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Streams tests required for Mainline coverage.
+ *
+ * TODO(b/153297830): Use existing CtsLibcoreOjTestCases for coverage instead.
+ */
+
+@RunWith(JUnit4.class)
+public class StreamTest {
+  private static final int[] TEST_ARRAY_SIZES = { 0, 1, 2, 10, 100, 1000 };
+
+  /**
+   * Stream<T>.of() has two overloads, Stream.of(T t) and Stream.of(T... values)
+   *
+   * The first builds a Stream<T> whose functionality is tested in CtsLibcoreOjTestCases, so we
+   * just check the contents are as expected
+   *
+   * The second is a thin wrapper around Arrays.Stream(), which is tested in ArraysTest,
+   * so again we just check the contents are as expected.
+   *
+   */
+  @Test
+  public void streamOfSingleObject() {
+    String object = "string";
+    String[] array = Stream.of(object).toArray(String[]::new);
+    assertEquals(1, array.length);
+    assertSame(object, array[0]);
+  }
+
+  @Test
+  public void streamOfObjects() {
+    for (int size : TEST_ARRAY_SIZES) {
+      String[] sourceArray = stringTestArray(size);
+
+      // Stream.of(T[] t) is equivalent to Stream.of(T... t)
+      String[] destArray = Stream.of(sourceArray)
+          .toArray(String[]::new);
+      assertNotSame(sourceArray, destArray);
+      assertArrayEquals(sourceArray, destArray);
+    }
+  }
+
+  private String[] stringTestArray(int size) {
+    String[] array = new String[size];
+    for (int i = 0; i < size; i++) {
+      array[i] = String.valueOf(i);
+    }
+    return array;
+  }
+}
diff --git a/luni/src/test/java/libcore/java/util/zip/DeflateRegressionTest.java b/luni/src/test/java/libcore/java/util/zip/DeflateRegressionTest.java
deleted file mode 100644
index 1a505fa..0000000
--- a/luni/src/test/java/libcore/java/util/zip/DeflateRegressionTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package libcore.java.util.zip;
-
-import com.google.archivepatcher.shared.DefaultDeflateCompatibilityWindow;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertTrue;
-
-/**
- * A regression test for Deflate and the underlying native libraries. If any of these tests fail
- * it suggests that tools such as Google Play Store that rely on deterministic binary output from
- * Deflate; those tools may behave inefficiently if the output changes.
- */
-public class DeflateRegressionTest {
-
-    /*
-     * If this test fails then it implies a change that could regress Android user performance.
-     * Please check that the platform version of Deflate is still used by affected tools and notify
-     * them. See also http://b/27637914.
-     */
-    @Test
-    public void deterministicOutput() throws Exception {
-        assertTrue(new DefaultDeflateCompatibilityWindow().isCompatible());
-    }
-}
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipInputStreamTest.java b/luni/src/test/java/libcore/java/util/zip/ZipInputStreamTest.java
index 8485874..8a33f6f 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipInputStreamTest.java
@@ -143,6 +143,19 @@
         zis.close();
     }
 
+    private static final byte[] ZIP_WITH_DATA_DESCRIPTOR = new byte[] {
+(byte) 80, 75, 3, 4, 10, 0, 8, 0, 0, 0, -51, 90, -121, 80, -20, 62, -84, -103, 2, 0, 0, 0, 2, 0, 0, 0, 8, 0, 28, 0, 116, 101, 115, 116, 46, 116, 120, 116, 85, 84, 9, 0, 3, 97, 84, -116, 94, 102, 84, -116, 94, 117, 120, 11, 0, 1, 4, -119, 66, 0, 0, 4, 83, 95, 1, 0, 72, 10, 80, 75, 7, 8, -20, 62, -84, -103, 2, 0, 0, 0, 2, 0, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, -51, 90, -121, 80, -20, 62, -84, -103, 2, 0, 0, 0, 2, 0, 0, 0, 8, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, -92, -127, 0, 0, 0, 0, 116, 101, 115, 116, 46, 116, 120, 116, 85, 84, 5, 0, 3, 97, 84, -116, 94, 117, 120, 11, 0, 1, 4, -119, 66, 0, 0, 4, 83, 95, 1, 0, 80, 75, 5, 6, 0, 0, 0, 0, 1, 0, 1, 0, 78, 0, 0, 0, 84, 0, 0, 0, 0, 0 };
+
+    public void testDataDescriptorOnStoredEntry() throws Exception {
+        ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(
+                ZIP_WITH_DATA_DESCRIPTOR));
+
+        ZipEntry entry = zis.getNextEntry();
+        assertEquals("test.txt", entry.getName());
+
+        zis.close();
+    }
+
     private static byte[] zip(String[] names, byte[] bytes) throws IOException {
         ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
         ZipOutputStream zippedOut = new ZipOutputStream(bytesOut);
diff --git a/luni/src/test/java/libcore/javax/crypto/HardwareAesTest.java b/luni/src/test/java/libcore/javax/crypto/HardwareAesTest.java
new file mode 100644
index 0000000..f79bb81
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/crypto/HardwareAesTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.javax.crypto;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import libcore.java.security.CpuFeatures;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class HardwareAesTest {
+
+    @Test
+    public void hardwareAesAvailability() {
+        // Test is only applicable if we know for sure that the device should support
+        // hardware AES.  That covers the important cases (non-emulated ARM and x86_64),
+        // For everything else we assume BoringSSL does the right thing.
+        assumeTrue(CpuFeatures.isKnownToSupportHardwareAes());
+        assertTrue(CpuFeatures.isAesHardwareAccelerated());
+    }
+}
diff --git a/luni/src/test/java/libcore/javax/crypto/MacTest.java b/luni/src/test/java/libcore/javax/crypto/MacTest.java
index 3e49cd6..bd2ad39 100644
--- a/luni/src/test/java/libcore/javax/crypto/MacTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/MacTest.java
@@ -26,28 +26,18 @@
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
-import junit.framework.TestCase;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
-
-public class MacTest extends TestCase {
+public class MacTest extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     private static abstract class MockProvider extends Provider {
         public MockProvider(String name) {
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLParametersTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLParametersTest.java
index 620c022..3b3cfe4 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLParametersTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLParametersTest.java
@@ -16,13 +16,21 @@
 
 package libcore.javax.net.ssl;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.util.Arrays;
 import javax.net.ssl.SSLParameters;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
-public class SSLParametersTest extends TestCase {
+@RunWith(JUnit4.class)
+public class SSLParametersTest {
 
-  public void test_applicationProtocols() {
+  @Test
+  public void applicationProtocols() {
     SSLParameters params = new SSLParameters();
     try {
       params.setApplicationProtocols(null);
@@ -61,4 +69,14 @@
     assertTrue(Arrays.equals(new String[] {"h2"}, params.getApplicationProtocols()));
   }
 
+  @Test
+  public void getSetUseCipherSuitesOrder() {
+    SSLParameters params = new SSLParameters();
+    // Default should be false
+    assertFalse(params.getUseCipherSuitesOrder());
+    params.setUseCipherSuitesOrder(true);
+    assertTrue(params.getUseCipherSuitesOrder());
+    params.setUseCipherSuitesOrder(false);
+    assertFalse(params.getUseCipherSuitesOrder());
+  }
 }
diff --git a/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java b/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
index 1aa3550..226952f 100644
--- a/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
+++ b/luni/src/test/java/libcore/javax/security/auth/x500/X500PrincipalTest.java
@@ -21,30 +21,20 @@
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import javax.security.auth.x500.X500Principal;
-import junit.framework.TestCase;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
 import libcore.libcore.util.SerializationTester;
-
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
 
-public class X500PrincipalTest extends TestCase {
+public class X500PrincipalTest extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     public void testSerialization() {
         String expected = "aced0005737200266a617661782e73656375726974792e617574682e7"
diff --git a/luni/src/test/java/libcore/libcore/content/type/MimeMapTest.java b/luni/src/test/java/libcore/libcore/content/type/MimeMapTest.java
new file mode 100644
index 0000000..764bad2
--- /dev/null
+++ b/luni/src/test/java/libcore/libcore/content/type/MimeMapTest.java
@@ -0,0 +1,456 @@
+/*
+ * 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 libcore.libcore.content.type;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import libcore.content.type.MimeMap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link MimeMap} and {@link MimeMap.Builder}.
+ */
+public class MimeMapTest {
+
+    private MimeMap mimeMap;
+    private MimeMap emptyMap;
+
+    @Before public void setUp() {
+        mimeMap = MimeMap.getDefault();
+        emptyMap = MimeMap.builder().build();
+    }
+
+    @After public void tearDown() {
+        mimeMap = null;
+    }
+
+    @Test public void lookup_invalidExtension() {
+        assertNull(mimeMap.guessMimeTypeFromExtension(null));
+        assertNull(mimeMap.guessMimeTypeFromExtension(""));
+        assertFalse(mimeMap.hasExtension(null));
+        assertFalse(mimeMap.hasExtension(""));
+    }
+
+    @Test public void lookup_invalidMimeType() {
+        assertNull(mimeMap.guessExtensionFromMimeType(null));
+        assertNull(mimeMap.guessExtensionFromMimeType(""));
+        assertFalse(mimeMap.hasMimeType(null));
+        assertFalse(mimeMap.hasMimeType(""));
+    }
+
+    @Test public void caseNormalization_key() {
+        mimeMap = MimeMap.builder()
+                .put("application/msWord", Arrays.asList("Doc"))
+                .build();
+        assertEquals("application/msword", mimeMap.guessMimeTypeFromExtension("dOc"));
+        assertEquals("doc", mimeMap.guessExtensionFromMimeType("appliCATion/mSWOrd"));
+        assertTrue(mimeMap.hasMimeType("application/msword"));
+        assertTrue(mimeMap.hasMimeType("Application/mSWord"));
+
+        assertTrue(mimeMap.hasExtension("doc"));
+        assertTrue(mimeMap.hasExtension("DOC"));
+        assertTrue(mimeMap.hasExtension("dOc"));
+    }
+
+    @Test public void caseNormalization_value() {
+        // Default map
+        for (String extension : mimeMap.extensions()) {
+            assertLowerCase(mimeMap.guessMimeTypeFromExtension(extension));
+        }
+        for (String mimeType : mimeMap.mimeTypes()) {
+            assertLowerCase(mimeMap.guessExtensionFromMimeType(mimeType));
+        }
+
+        // Known keys for a custom map
+        mimeMap = MimeMap.builder()
+                .put("application/msWord", Arrays.asList("Doc"))
+                .build();
+        assertEquals("doc", mimeMap.guessExtensionFromMimeType("Application/mSWord"));
+        assertEquals("application/msword", mimeMap.guessMimeTypeFromExtension("DoC"));
+    }
+
+    private static void assertLowerCase(String s) {
+        assertEquals(s.toLowerCase(Locale.ROOT), s);
+    }
+
+    @Test public void unmapped() {
+        mimeMap = MimeMap.builder()
+                .put("mime/test", Arrays.asList("test", "tst"))
+                .build();
+        assertNull(mimeMap.guessExtensionFromMimeType("mime/unknown"));
+        assertFalse(mimeMap.hasMimeType("mime/unknown"));
+
+        assertNull(mimeMap.guessMimeTypeFromExtension("absent"));
+        assertFalse(mimeMap.hasExtension("absent"));
+    }
+
+    @Test public void getDefault_returnsSameInstance() {
+        assertSame(MimeMap.getDefault(), MimeMap.getDefault());
+    }
+
+    @Test public void getDefault_afterSetDefaultSupplier() {
+        MimeMap originalDefault = MimeMap.getDefault();
+        try {
+            // Constructs a new instance every time it is called
+            MimeMap.setDefaultSupplier(() -> MimeMap.builder().put("mime/sup", "sup").build());
+            // Same instance is returned both times
+            assertSame(MimeMap.getDefault(), MimeMap.getDefault());
+            // Check that the supplier is in effect
+            assertTrue(originalDefault != MimeMap.getDefault());
+            assertEquals("mime/sup", MimeMap.getDefault().guessMimeTypeFromExtension("sup"));
+        } finally {
+            MimeMap.setDefaultSupplier(() -> originalDefault);
+        }
+        assertSame(originalDefault, MimeMap.getDefault());
+    }
+
+    @Test public void setDefaultSupplier_returningNull() {
+        MimeMap originalDefault = MimeMap.getDefault();
+        try {
+            // A Supplier that returns null is invalid, but we only notice during getDefault().
+            MimeMap.setDefaultSupplier(() -> null);
+            try {
+                MimeMap.getDefault();
+                fail();
+            } catch (NullPointerException expected) {
+            }
+        } finally {
+            MimeMap.setDefaultSupplier(() -> originalDefault);
+        }
+    }
+
+    @Test public void buildUpon() {
+        mimeMap = MimeMap.builder()
+                .build();
+        assertMap(
+                makeMap(),
+                makeMap(),
+                mimeMap);
+
+        mimeMap = mimeMap.buildUpon()
+                .build();
+        assertMap(
+                makeMap(),
+                makeMap(),
+                mimeMap);
+
+        mimeMap = mimeMap.buildUpon()
+                .put("text/plain", "txt")
+                .build();
+        assertMap(
+                makeMap("text/plain", "txt"),
+                makeMap("txt", "text/plain"),
+                mimeMap);
+
+        mimeMap = mimeMap.buildUpon()
+                .put("audio/mpeg", Arrays.asList("mp2", "mp3"))
+                .build();
+        assertMap(
+                makeMap("audio/mpeg", "mp2",
+                        "text/plain", "txt"),
+                makeMap("mp2", "audio/mpeg",
+                        "mp3", "audio/mpeg",
+                        "txt", "text/plain"),
+                mimeMap);
+
+        mimeMap = mimeMap.buildUpon()
+                .put("text/plain", "text")
+                .build();
+        assertMap(
+                makeMap("audio/mpeg", "mp2",
+                        "text/plain", "text"),
+                makeMap("mp2", "audio/mpeg",
+                        "mp3", "audio/mpeg",
+                        "text", "text/plain",
+                        "txt", "text/plain"),
+                mimeMap);
+    }
+
+    @Test public void put() {
+        MimeMap a = MimeMap.builder()
+                .put("text/plain", Arrays.asList("txt", "text"))
+                .put("application/msword", "doc")
+                .build();
+        MimeMap b = MimeMap.builder()
+                .put("text/plain", Arrays.asList("txt", "text"))
+                .put("application/msword", "doc")
+                .build();
+        assertEqualsButNotSame(a, b);
+        assertEqualsButNotSame(a, a.buildUpon().build());
+        assertMap(
+                makeMap(
+                        "text/plain", "txt",
+                        "application/msword", "doc"),
+                makeMap("txt", "text/plain",
+                        "text", "text/plain",
+                        "doc", "application/msword"),
+                a);
+    }
+
+    @Test public void put_noExtensions() {
+        checkPut_noExtensions(emptyMap);
+        checkPut_noExtensions(MimeMap.builder().put("text/plain", "txt").build());
+        checkPut_noExtensions(mimeMap);
+    }
+
+    /**
+     * Checks that put(String, emptyList()) doesn't change or add any mappings.
+     */
+    private static void checkPut_noExtensions(MimeMap baseMap) {
+        MimeMap mimeMap = baseMap.buildUpon()
+                .put("mime/type", Collections.emptyList())
+                .build();
+        assertEquals(baseMap, mimeMap);
+    }
+
+    @Test public void put_String_List_nullOrEmpty() {
+        // We still check mimeType for validity even if no extensions are specified
+        assertPutThrowsNpe(null);
+        assertPutThrowsIae("");
+
+        // null or "" are not allowed for either MIME type or extension
+        assertPutThrowsNpe(null, "ext");
+        assertPutThrowsIae("", "ext");
+        assertPutThrowsNpe("mime/type", (String) null);
+        assertPutThrowsIae("mime/type", "");
+
+        assertPutThrowsNpe("mime/type", "ext", null);
+        assertPutThrowsIae("mime/type", "ext", "");
+    }
+
+    @Test public void put_String_String_nullOrEmpty() {
+        assertThrowsNpe(() -> MimeMap.builder().put(null, "ext"));
+        assertThrowsIae(() -> MimeMap.builder().put("", "ext"));
+
+        assertThrowsNpe(() -> MimeMap.builder().put("mime/type", (String) null));
+        assertThrowsIae(() -> MimeMap.builder().put("mime/type", ""));
+    }
+
+    /**
+     * Tests put() arguments that have a prefix {@code "?"} which leads to putIfAbsent semantics.
+     */
+    @Test public void putIfAbsent() {
+        // Starting from an empty mapping, add a bunch more, some with and some without '?'.
+        mimeMap = MimeMap.builder()
+                .put("?text/plain", "?txt")
+                .put("audio/mpeg", Arrays.asList("mpga", "mpega", "?mp2", "mp3"))
+                .build();
+        assertEquals("txt", mimeMap.guessExtensionFromMimeType("text/plain"));
+        assertEquals("text/plain", mimeMap.guessMimeTypeFromExtension("txt"));
+        assertEquals("mpga", mimeMap.guessExtensionFromMimeType("audio/mpeg"));
+        assertEquals("audio/mpeg", mimeMap.guessMimeTypeFromExtension("mp2"));
+        assertEquals("audio/mpeg", mimeMap.guessMimeTypeFromExtension("mp3"));
+
+        // Override a ext -> MIME mapping without overriding the MIME -> ext mapping.
+        mimeMap = mimeMap.buildUpon()
+                .put("?audio/mpeg", "m4a")
+                .build();
+        assertEquals("mpga", mimeMap.guessExtensionFromMimeType("audio/mpeg"));
+        assertEquals("audio/mpeg", mimeMap.guessMimeTypeFromExtension("m4a"));
+
+        // Override a MIME -> ext mapping without overriding the ext -> MIME mapping.
+        mimeMap = mimeMap.buildUpon()
+                .put("audio/mpeg", "?txt")
+                .build();
+        assertEquals("txt", mimeMap.guessExtensionFromMimeType("audio/mpeg"));
+        assertEquals("text/plain", mimeMap.guessMimeTypeFromExtension("txt"));
+
+
+        // Check final state
+        assertMap(
+                makeMap(
+                        "text/plain", "txt",
+                        "audio/mpeg", "txt"
+                        ),
+                makeMap(
+                        "txt", "text/plain",
+                        "m4a", "audio/mpeg",
+                        "mp2", "audio/mpeg",
+                        "mp3", "audio/mpeg",
+                        "mpega", "audio/mpeg",
+                        "mpga", "audio/mpeg"
+                ),
+                mimeMap
+        );
+    }
+
+    @Test public void extensions() {
+        assertEquals(Collections.emptySet(), emptyMap.extensions());
+        mimeMap = MimeMap.builder()
+                .put("text/plain", Arrays.asList("txt", "text"))
+                .put("audi/mpeg", "m4a")
+                .put("application/msword", "doc")
+                .put("text/plain", "tx")
+                .build();
+        Set<String> extensions = new HashSet<>(Arrays.asList(
+                "txt", "text", "m4a", "doc", "tx"));
+        assertEquals(extensions, mimeMap.extensions());
+        // Check that the extensions() view is unmodifiable
+        try {
+            mimeMap.extensions().add("ext");
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    @Test public void mimeTypes() {
+        assertEquals(Collections.emptySet(), emptyMap.mimeTypes());
+        mimeMap = MimeMap.builder()
+                .put("text/plain", Arrays.asList("txt", "text"))
+                .put("audio/mpeg", "m4a")
+                .put("application/msword", "doc")
+                .put("text/plain", "tx")
+                .build();
+        Set<String> mimeTypes = new HashSet<>(Arrays.asList(
+                "text/plain",
+                "audio/mpeg",
+                "application/msword"));
+        assertEquals(mimeTypes, mimeMap.mimeTypes());
+        // Check that the mimeTypes() view is unmodifiable
+        try {
+            mimeMap.mimeTypes().add("foo/bar");
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    /**
+     * Tests invalid put() invocations that have '?' in additional/invalid places.
+     */
+    @Test public void put_invalid_additionalQuestionMarks() {
+        // Potentially we could tolerate additional ? as a prefix in future, but right now we don't.
+        assertPutThrowsIae("??text/plain", "txt");
+        assertPutThrowsIae("text/p?lain", "txt");
+        assertPutThrowsIae("text/plain", "txt", "t?ext");
+        assertPutThrowsIae("text/plain", "??txt");
+        assertPutThrowsIae("text/plain", "t?xt");
+    }
+
+    /** Checks that MIME types must have a '/', while extensions must not. */
+    @Test public void put_invalid_slash() {
+        assertPutThrowsIae("mime/type", "invalid/ext");
+        assertPutThrowsIae("invalidmime", "ext");
+
+        // During lookups, wrong arguments return null rather than throwing.
+        mimeMap = MimeMap.builder().put("mime/type", "ext").build();
+        assertNull(mimeMap.guessExtensionFromMimeType("ext")); // ext is no mime type
+        assertNull(mimeMap.guessMimeTypeFromExtension("mime/type")); // mime/type is no extension
+    }
+
+    private static void assertPutThrowsNpe(String mime, String... exts) {
+        assertThrowsNpe(() -> MimeMap.builder().put(mime, Arrays.asList(exts)));
+    }
+
+    private static void assertPutThrowsIae(final String mime, final String... exts) {
+        assertThrowsIae(() -> MimeMap.builder().put(mime, Arrays.asList(exts)));
+    }
+
+    private static void assertThrowsNpe(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (NullPointerException expected) {
+        }
+    }
+
+    private static void assertThrowsIae(Runnable runnable) {
+        try {
+            runnable.run();
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test public void hashCodeValue() {
+        assertEquals(0, emptyMap.hashCode());
+        MimeMap a = MimeMap.builder().put("mime/test", "test").build();
+        MimeMap b = a.buildUpon().put("foo/bar", "baz").build();
+        assertTrue(0 != a.hashCode());
+        assertTrue((a.hashCode() != b.hashCode()));
+    }
+
+    @Test public void empty_copies() {
+        assertEqualsButNotSame(emptyMap, MimeMap.builder().build());
+        assertEqualsButNotSame(emptyMap, emptyMap.buildUpon().build());
+    }
+
+    /** Creates a map from alternating key/value arguments, useful for test assertions. */
+    private static Map<String, String> makeMap(String... keysAndValues) {
+        if (keysAndValues.length % 2 != 0) {
+            throw new IllegalArgumentException(
+                    "Invalid length " + keysAndValues.length + ": " + keysAndValues);
+        }
+        Map<String, String> result = new HashMap<>();
+        for (int i = 0; i < keysAndValues.length; i += 2) {
+            String key = keysAndValues[i];
+            String value = keysAndValues[i + 1];
+            result.put(key, value);
+        }
+        return result;
+
+    }
+
+    /**
+     * Asserts that the given {@code MimeMap} has exactly the given mime -> ext and ext -> mime
+     * mappings, but no others.
+     */
+    private static<T> void assertMap(
+            Map<String, String> expectedMimeToExt,
+            Map<String, String> expectedExtToMime,
+            MimeMap mimeMap)
+    {
+        MimeMap.Builder expectedBuilder = MimeMap.builder();
+        for (Map.Entry<String, String> entry : expectedExtToMime.entrySet()) {
+            String ext = entry.getKey();
+            String mime = entry.getValue();
+            assertEquals(ext + ": " + mimeMap, mime, mimeMap.guessMimeTypeFromExtension(ext));
+            expectedBuilder.put("?" + mime, ext);
+        }
+        for (Map.Entry<String, String> entry : expectedMimeToExt.entrySet()) {
+            String mime = entry.getKey();
+            String ext = entry.getValue();
+            assertEquals(mime + ": "  + mimeMap, ext, mimeMap.guessExtensionFromMimeType(mime));
+            expectedBuilder.put(mime, "?" + ext);
+        }
+        // Check that there are no unexpected additional mappings.
+        assertEqualsButNotSame(expectedBuilder.build(), mimeMap);
+    }
+
+    private static<T> void assertEqualsButNotSame(T a, T b) {
+        assertEquals(a, b);
+        assertEquals(b, a);
+        assertNotSame(a, b);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+}
diff --git a/luni/src/test/java/libcore/libcore/icu/ICUTest.java b/luni/src/test/java/libcore/libcore/icu/ICUTest.java
index e67e9a1..30e3081 100644
--- a/luni/src/test/java/libcore/libcore/icu/ICUTest.java
+++ b/luni/src/test/java/libcore/libcore/icu/ICUTest.java
@@ -220,38 +220,25 @@
     assertTrue(c.compare("AF", "af") < 0);
   }
 
-  // Test for the behavior of currency symbol lookup when an unrecognized locale has been set as the
-  // default.
-  public void testIcuDefaultAffectsCurrencySymbol() {
-    // A locale that is not going to be recognized by ICU and should fallback to "root" for the
-    // currency symbol.
-    final Locale unrecognizedLocale = new Locale("xy", "KR");
+  public void testSetDefault() {
+      String current = ICU.getDefaultLocale();
 
-    // A known locale with a relatively stable representation for its currency symbol.
-    final Locale enUsLocale = new Locale("en", "US");
-    final String usDollar = "USD";
-
-    String initialDefaultLocale = ICU.getDefaultLocale();
-    try {
-      // Confirm the "$" symbol for USD in en-US.
-      assertEquals("$", ICU.getCurrencySymbol(enUsLocale, usDollar));
-
-      // Set the default so this will be used as fallback for the unrecognized locale symbol lookup.
-      ICU.setDefaultLocale(enUsLocale.toLanguageTag());
-
-      // Demonstrate the USD symbol is reported as "$" for the unrecognized locale (which is using
-      // the default).
-      assertEquals("$", ICU.getCurrencySymbol(unrecognizedLocale, usDollar));
-
-      // Change the default.
-      ICU.setDefaultLocale(unrecognizedLocale.toLanguageTag());
-
-      String currencySymbolAfterDefaultChange = ICU.getCurrencySymbol(unrecognizedLocale, usDollar);
-      // "$US" is the value from root. With an unrecognized locale argument, and an unrecognized
-      // locale as the default, ICU has returns the value in root.
-      assertEquals("US$", currencySymbolAfterDefaultChange);
-    } finally {
-      ICU.setDefaultLocale(initialDefaultLocale);
-    }
+      try {
+        assertGetDefault("", "");
+        assertGetDefault("und", "");
+        assertGetDefault("en-US", "en_US");
+        assertGetDefault("uz-CYRL-UZ", "uz_Cyrl_UZ");
+        assertGetDefault("ca-ES-PREEURO", "ca_ES_PREEURO");
+        assertGetDefault("es-ES-PREEURO-u-ca-japanese", "es_ES_PREEURO@calendar=japanese");
+        assertGetDefault("es-ES-PREEURO-u-ca-Japanese", "es_ES_PREEURO@calendar=japanese");
+      } finally {
+          ICU.setDefaultLocale(current);
+      }
   }
+
+  private static void assertGetDefault(String inputLangaugeTag, String expectedLanguageTag) {
+    ICU.setDefaultLocale(inputLangaugeTag);
+    assertEquals(expectedLanguageTag, ICU.getDefaultLocale());
+  }
+
 }
diff --git a/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java b/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
index 607397d..eace233 100644
--- a/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
+++ b/luni/src/test/java/libcore/libcore/icu/LocaleDataTest.java
@@ -16,10 +16,37 @@
 
 package libcore.libcore.icu;
 
-import java.util.Locale;
-import libcore.icu.LocaleData;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-public class LocaleDataTest extends junit.framework.TestCase {
+import android.icu.text.DateTimePatternGenerator;
+
+import java.text.DateFormatSymbols;
+import java.text.DecimalFormatSymbols;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import libcore.icu.LocaleData;
+import libcore.junit.util.SwitchTargetSdkVersionRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class LocaleDataTest {
+  
+  @Rule
+  public TestRule switchTargetSdkVersionRule = SwitchTargetSdkVersionRule.getInstance();
+
+  @Test
   public void testAll() throws Exception {
     // Test that we can get the locale data for all known locales.
     for (Locale l : Locale.getAvailableLocales()) {
@@ -29,6 +56,7 @@
     }
   }
 
+  @Test
   public void test_en_US() throws Exception {
     LocaleData l = LocaleData.get(Locale.US);
     assertEquals("AM", l.amPm[0]);
@@ -57,6 +85,7 @@
     assertEquals("Tomorrow", l.tomorrow);
   }
 
+  @Test
   public void test_de_DE() throws Exception {
     LocaleData l = LocaleData.get(new Locale("de", "DE"));
 
@@ -65,6 +94,7 @@
     assertEquals("Morgen", l.tomorrow);
   }
 
+  @Test
   public void test_cs_CZ() throws Exception {
     LocaleData l = LocaleData.get(new Locale("cs", "CZ"));
 
@@ -77,6 +107,7 @@
     assertEquals("1", l.tinyStandAloneMonthNames[0]);
   }
 
+  @Test
   public void test_ko_KR() throws Exception {
     LocaleData l = LocaleData.get(new Locale("ko", "KR"));
 
@@ -86,6 +117,7 @@
     assertEquals("내일", l.tomorrow);
   }
 
+  @Test
   public void test_ru_RU() throws Exception {
     LocaleData l = LocaleData.get(new Locale("ru", "RU"));
 
@@ -100,6 +132,7 @@
   }
 
   // http://code.google.com/p/android/issues/detail?id=38844
+  @Test
   public void testDecimalFormatSymbols_es() throws Exception {
     LocaleData es = LocaleData.get(new Locale("es"));
     assertEquals(',', es.decimalSeparator);
@@ -123,6 +156,7 @@
   }
 
   // http://b/7924970
+  @Test
   public void testTimeFormat12And24() throws Exception {
     LocaleData en_US = LocaleData.get(Locale.US);
     assertEquals("h:mm a", en_US.timeFormat_hm);
@@ -134,6 +168,7 @@
   }
 
   // http://b/26397197
+  @Test
   public void testPatternWithOverride() throws Exception {
     LocaleData haw = LocaleData.get(new Locale("haw"));
     assertFalse(haw.shortDateFormat.isEmpty());
@@ -143,7 +178,111 @@
    * Check that LocaleData.get() does not throw when the input locale is invalid.
    * http://b/129070579
    */
+  @Test
   public void testInvalidLocale() {
     LocaleData.get(new Locale("invalidLocale"));
   }
+
+  // Test for b/159514442 when targetSdkVersion == current
+  @Test
+  public void test_rootLocale_icu4jConsistency() {
+    assertRootDataEqualsToTargetLocaleData(Locale.ROOT);
+  }
+
+  // Test for b/159514442
+  @Test
+  @SwitchTargetSdkVersionRule.TargetSdkVersion(30)
+  public void test_rootLocale_useRealRootLocaleData() {
+    assertRootDataEqualsToTargetLocaleData(Locale.ROOT);
+
+    // Regression test as in b/159514442.
+    SimpleDateFormat df = new SimpleDateFormat("MMM", Locale.ROOT);
+    df.setTimeZone(TimeZone.getTimeZone("GMT"));
+    assertEquals("M07", df.format(new Date(1594255915217L)));
+  }
+
+  // Test for b/159514442
+  @Test
+  @SwitchTargetSdkVersionRule.TargetSdkVersion(29)
+  public void test_rootLocale_notUseRealRootLocaleData() {
+    Locale LOCALE_EN_US_POSIX = new Locale("en", "US", "POSIX");
+    assertRootDataEqualsToTargetLocaleData(LOCALE_EN_US_POSIX);
+
+    // Regression test as in b/159514442.
+    SimpleDateFormat df = new SimpleDateFormat("MMM", Locale.ROOT);
+    df.setTimeZone(TimeZone.getTimeZone("GMT"));
+    assertEquals("Jul", df.format(new Date(1594255915217L)));
+  }
+
+  private static void assertRootDataEqualsToTargetLocaleData(Locale targetLocale) {
+    LocaleData localeData = LocaleData.get(Locale.ROOT);
+    Calendar calendar = Calendar.getInstance(Locale.ROOT);
+    android.icu.util.Calendar icuCalendar = android.icu.util.Calendar.getInstance(targetLocale);
+    DateFormatSymbols dateFormatSymbols = DateFormatSymbols.getInstance(Locale.ROOT);
+    android.icu.text.DateFormatSymbols icuDateFormatSymbols =
+        android.icu.text.DateFormatSymbols.getInstance(targetLocale);
+    DecimalFormatSymbols decimalFormatSymbols = DecimalFormatSymbols.getInstance(Locale.ROOT);
+    android.icu.text.DecimalFormatSymbols icuDecimalFormatSymbols =
+        android.icu.text.DecimalFormatSymbols.getInstance(targetLocale);
+    DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance(Locale.ROOT);
+
+    assertEquals(localeData.firstDayOfWeek, (Integer) icuCalendar.getFirstDayOfWeek());
+    assertEquals(localeData.minimalDaysInFirstWeek,
+        (Integer) icuCalendar.getMinimalDaysInFirstWeek());
+
+    assertArrayEquals(localeData.amPm, icuDateFormatSymbols.getAmPmStrings());
+    assertArrayEquals(localeData.eras, icuDateFormatSymbols.getEras());
+    assertArrayEquals(localeData.longMonthNames, icuDateFormatSymbols.getMonths(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.WIDE));
+    assertArrayEquals(localeData.tinyMonthNames, icuDateFormatSymbols.getMonths(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.NARROW));
+    assertArrayEquals(localeData.shortMonthNames, icuDateFormatSymbols.getMonths(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.ABBREVIATED));
+    assertArrayEquals(localeData.longStandAloneMonthNames, icuDateFormatSymbols.getMonths(
+        android.icu.text.DateFormatSymbols.STANDALONE, android.icu.text.DateFormatSymbols.WIDE));
+    assertArrayEquals(localeData.tinyStandAloneMonthNames, icuDateFormatSymbols.getMonths(
+        android.icu.text.DateFormatSymbols.STANDALONE, android.icu.text.DateFormatSymbols.NARROW));
+    assertArrayEquals(localeData.shortStandAloneMonthNames, icuDateFormatSymbols.getMonths(
+        android.icu.text.DateFormatSymbols.STANDALONE,
+        android.icu.text.DateFormatSymbols.ABBREVIATED));
+    assertArrayEquals(localeData.longWeekdayNames, icuDateFormatSymbols.getWeekdays(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.WIDE));
+    assertArrayEquals(localeData.tinyWeekdayNames, icuDateFormatSymbols.getWeekdays(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.NARROW));
+    assertArrayEquals(localeData.shortWeekdayNames, icuDateFormatSymbols.getWeekdays(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.ABBREVIATED));
+    assertArrayEquals(localeData.longStandAloneWeekdayNames, icuDateFormatSymbols.getWeekdays(
+        android.icu.text.DateFormatSymbols.STANDALONE, android.icu.text.DateFormatSymbols.WIDE));
+    assertArrayEquals(localeData.tinyStandAloneWeekdayNames, icuDateFormatSymbols.getWeekdays(
+        android.icu.text.DateFormatSymbols.STANDALONE, android.icu.text.DateFormatSymbols.NARROW));
+    assertArrayEquals(localeData.shortStandAloneWeekdayNames, icuDateFormatSymbols.getWeekdays(
+        android.icu.text.DateFormatSymbols.STANDALONE,
+        android.icu.text.DateFormatSymbols.ABBREVIATED));
+
+    // ICU DecimalFormatSymbols has data slightly different from LocaleData, but infinity is known
+    // to be the same, but caused the bug b/68318492 in old Android version.
+    assertEquals(localeData.infinity, icuDecimalFormatSymbols.getInfinity());
+    assertEquals(decimalFormatSymbols.getInfinity(), icuDecimalFormatSymbols.getInfinity());
+
+    assertEquals(localeData.timeFormat_Hm, dtpg.getBestPattern("Hm"));
+    assertEquals(localeData.timeFormat_hm, dtpg.getBestPattern("hm"));
+    assertEquals(localeData.timeFormat_Hms, dtpg.getBestPattern("Hms"));
+    assertEquals(localeData.timeFormat_hms, dtpg.getBestPattern("hms"));
+
+    // Explicitly test Calendar and DateFormatSymbols here because they are known to
+    // cache some part of LocaleData.
+    assertEquals(calendar.getFirstDayOfWeek(), icuCalendar.getFirstDayOfWeek());
+    assertEquals(calendar.getMinimalDaysInFirstWeek(), icuCalendar.getMinimalDaysInFirstWeek());
+    assertArrayEquals(dateFormatSymbols.getAmPmStrings(), icuDateFormatSymbols.getAmPmStrings());
+    assertArrayEquals(dateFormatSymbols.getEras(), icuDateFormatSymbols.getEras());
+
+    assertArrayEquals(dateFormatSymbols.getMonths(), icuDateFormatSymbols.getMonths(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.WIDE));
+    assertArrayEquals(dateFormatSymbols.getShortMonths(), icuDateFormatSymbols.getMonths(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.ABBREVIATED));
+    assertArrayEquals(dateFormatSymbols.getWeekdays(), icuDateFormatSymbols.getWeekdays(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.WIDE));
+    assertArrayEquals(dateFormatSymbols.getShortWeekdays(), icuDateFormatSymbols.getWeekdays(
+        android.icu.text.DateFormatSymbols.FORMAT, android.icu.text.DateFormatSymbols.ABBREVIATED));
+  }
 }
diff --git a/luni/src/test/java/libcore/libcore/icu/TimeZoneIntegrationTest.java b/luni/src/test/java/libcore/libcore/icu/TimeZoneIntegrationTest.java
index 32dbb1c..f24d8b1 100644
--- a/luni/src/test/java/libcore/libcore/icu/TimeZoneIntegrationTest.java
+++ b/luni/src/test/java/libcore/libcore/icu/TimeZoneIntegrationTest.java
@@ -22,6 +22,8 @@
 import android.icu.util.VersionInfo;
 import android.system.Os;
 
+import com.android.icu.util.Icu4cMetadata;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -37,11 +39,10 @@
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-import libcore.icu.ICU;
 import libcore.timezone.TimeZoneDataFiles;
 import libcore.timezone.TimeZoneFinder;
 import libcore.timezone.TzDataSetVersion;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
 import libcore.util.CoreLibraryDebug;
 import libcore.util.DebugInfo;
 
@@ -182,9 +183,9 @@
      */
     @Test
     public void testTimeZoneDataVersion() {
-        String icu4cTzVersion = ICU.getTZDataVersion();
+        String icu4cTzVersion = Icu4cMetadata.getTzdbVersion();
 
-        String zoneInfoTzVersion = ZoneInfoDB.getInstance().getVersion();
+        String zoneInfoTzVersion = ZoneInfoDb.getInstance().getVersion();
         assertEquals(icu4cTzVersion, zoneInfoTzVersion);
 
         String icu4jTzVersion = android.icu.util.TimeZone.getTZDataVersion();
@@ -226,39 +227,29 @@
      */
     @Test
     public void testTzDataSetVersions() throws Exception {
-        String moduleTzVersionFile = "tz/" + TzDataSetVersion.DEFAULT_FILE_NAME;
-
+        // The time zone data module is required.
         String timeZoneModuleVersionFile =
-                TimeZoneDataFiles.getTimeZoneModuleFile(moduleTzVersionFile);
-        // We currently treat the time zone APEX as optional in code. Its is also not present on ART
-        // host environments.
-        if (fileExists(timeZoneModuleVersionFile)) {
-            assertTzDataSetVersionIsCompatible(timeZoneModuleVersionFile);
-        }
+                TimeZoneDataFiles.getTimeZoneModuleTzFile(TzDataSetVersion.DEFAULT_FILE_NAME);
+        assertTzDataSetVersionIsCompatible(timeZoneModuleVersionFile);
 
-        String runtimeModuleVersionFile =
-                TimeZoneDataFiles.getRuntimeModuleFile(moduleTzVersionFile);
-        assertTzDataSetVersionIsCompatible(runtimeModuleVersionFile);
-
-        // Check getRuntimeModuleTzVersionFile() is doing the right thing.
-        // getRuntimeModuleTzVersionFile() should go away when its one user, RulesManagerService,
+        // Check getTimeZoneModuleTzVersionFile() is doing the right thing.
+        // getTimeZoneModuleTzVersionFile() should go away when its one user, RulesManagerService,
         // is removed from the platform code. http://b/123398797
-        assertEquals(TimeZoneDataFiles.getRuntimeModuleTzVersionFile(), runtimeModuleVersionFile);
+        assertEquals(TimeZoneDataFiles.getTimeZoneModuleTzVersionFile(), timeZoneModuleVersionFile);
 
         // TODO: Remove this once the /system copy of time zone files have gone away. See also
         // testTimeZoneDebugInfo().
         assertTzDataSetVersionIsCompatible(
-                TimeZoneDataFiles.getSystemTimeZoneFile(TzDataSetVersion.DEFAULT_FILE_NAME));
+                TimeZoneDataFiles.getSystemTzFile(TzDataSetVersion.DEFAULT_FILE_NAME));
     }
 
     private static void assertTzDataSetVersionIsCompatible(String versionFile) throws Exception {
-        TzDataSetVersion actualVersion =
-                TzDataSetVersion.readFromFile(new File(versionFile));
+        TzDataSetVersion actualVersion = TzDataSetVersion.readFromFile(new File(versionFile));
         assertEquals(
                 TzDataSetVersion.currentFormatMajorVersion(),
-                actualVersion.formatMajorVersion);
+                actualVersion.getFormatMajorVersion());
         int minDeviceMinorVersion = TzDataSetVersion.currentFormatMinorVersion();
-        assertTrue(actualVersion.formatMinorVersion >= minDeviceMinorVersion);
+        assertTrue(actualVersion.getFormatMinorVersion() >= minDeviceMinorVersion);
     }
 
     /**
@@ -278,8 +269,8 @@
                 "core_library.timezone.source.tzdata_module_status");
         String apexRootDir = TimeZoneDataFiles.getTimeZoneModuleFile("");
         List<String> dataModuleFiles =
-                createModuleTzFileNames(TimeZoneDataFiles::getTimeZoneModuleFile);
-        String icuOverlayFile = TimeZoneDataFiles.getTimeZoneModuleFile("icu/icu_tzdata.dat");
+                createModuleTzFiles(TimeZoneDataFiles::getTimeZoneModuleTzFile);
+        String icuOverlayFile = TimeZoneDataFiles.getTimeZoneModuleIcuFile("icu_tzdata.dat");
         if (fileExists(apexRootDir)) {
             assertEquals("OK", tzModuleStatus);
             dataModuleFiles.forEach(TimeZoneIntegrationTest::assertFileExists);
@@ -290,46 +281,36 @@
             assertFileDoesNotExist(icuOverlayFile);
         }
 
-        // Every device should have a runtime module copy of time zone data since we expect every
-        // device to have a runtime module. This is the base copy of time zone data that can be
-        // updated when we update the runtime module. Host ART should match device.
-        assertEquals("OK", getDebugStringValue(debugInfo,
-                "core_library.timezone.source.runtime_module_status"));
-        assertFileExists(TimeZoneDataFiles.getRuntimeModuleFile(""));
-        List<String> runtimeModuleFiles =
-                createModuleTzFileNames(TimeZoneDataFiles::getRuntimeModuleFile);
-        runtimeModuleFiles.forEach(TimeZoneIntegrationTest::assertFileExists);
-
         String icuDatFileName = "icudt" + VersionInfo.ICU_VERSION.getMajor() + "l.dat";
-        String runtimeModuleIcuData =
-                TimeZoneDataFiles.getRuntimeModuleFile("icu/" + icuDatFileName);
-        assertFileExists(runtimeModuleIcuData);
+        String i18nModuleIcuData = TimeZoneDataFiles.getI18nModuleIcuFile(icuDatFileName);
+        assertFileExists(i18nModuleIcuData);
 
         // Devices currently have a subset of the time zone files in /system. These are going away
         // but we test them while they exist. Host ART should match device.
         assertEquals("OK", getDebugStringValue(debugInfo,
                 "core_library.timezone.source.system_status"));
         assertFileExists(
-                TimeZoneDataFiles.getSystemTimeZoneFile(TzDataSetVersion.DEFAULT_FILE_NAME));
-        assertFileExists(TimeZoneDataFiles.getSystemTimeZoneFile("tzdata"));
+                TimeZoneDataFiles.getSystemTzFile(TzDataSetVersion.DEFAULT_FILE_NAME));
+        assertFileExists(TimeZoneDataFiles.getSystemTzFile(ZoneInfoDb.TZDATA_FILE_NAME));
         // The following files once existed in /system but have been removed as part of APEX work.
-        assertFileDoesNotExist(TimeZoneDataFiles.getSystemTimeZoneFile("tzlookup.xml"));
+        assertFileDoesNotExist(
+                TimeZoneDataFiles.getSystemTzFile(TimeZoneFinder.TZLOOKUP_FILE_NAME));
 
         // It's hard to assert much about this file as there is a symlink in /system on device for
         // app compatibility (b/122985829) but it doesn't exist in host environments. If the file
         // exists we can say it should resolve (realpath) to the same file as the runtime module.
         String systemIcuData = TimeZoneDataFiles.getSystemIcuFile(icuDatFileName);
         if (new File(systemIcuData).exists()) {
-            assertEquals(Os.realpath(runtimeModuleIcuData), Os.realpath(systemIcuData));
+            assertEquals(Os.realpath(i18nModuleIcuData), Os.realpath(systemIcuData));
         }
     }
 
-    private static List<String> createModuleTzFileNames(
+    private static List<String> createModuleTzFiles(
             Function<String, String> pathCreationFunction) {
         List<String> relativePaths = Arrays.asList(
-                "tz/" + TzDataSetVersion.DEFAULT_FILE_NAME,
-                "tz/tzdata",
-                "tz/tzlookup.xml");
+                TzDataSetVersion.DEFAULT_FILE_NAME,
+                ZoneInfoDb.TZDATA_FILE_NAME,
+                TimeZoneFinder.TZLOOKUP_FILE_NAME);
         return relativePaths.stream().map(pathCreationFunction).collect(Collectors.toList());
     }
 
@@ -355,7 +336,7 @@
      */
     @Test
     public void testTimeZoneIdLookup() {
-        String[] zoneInfoDbAvailableIds = ZoneInfoDB.getInstance().getAvailableIDs();
+        String[] zoneInfoDbAvailableIds = ZoneInfoDb.getInstance().getAvailableIDs();
 
         // ICU has a known set of IDs. We want ANY because we don't want to filter to ICU's
         // canonical IDs only.
diff --git a/luni/src/test/java/libcore/libcore/io/BlockGuardOsTest.java b/luni/src/test/java/libcore/libcore/io/BlockGuardOsTest.java
index 0e2c6b5..218678e 100644
--- a/luni/src/test/java/libcore/libcore/io/BlockGuardOsTest.java
+++ b/luni/src/test/java/libcore/libcore/io/BlockGuardOsTest.java
@@ -189,7 +189,6 @@
                 "dup(java.io.FileDescriptor)",
                 "dup2(java.io.FileDescriptor,int)",
                 "environ()",
-                "fcntlFlock(java.io.FileDescriptor,int,android.system.StructFlock)",
                 "fcntlInt(java.io.FileDescriptor,int,int)",
                 "fcntlVoid(java.io.FileDescriptor,int)",
                 "gai_strerror(int)",
@@ -227,6 +226,7 @@
                 "kill(int,int)",
                 "listen(java.io.FileDescriptor,int)",
                 "listxattr(java.lang.String)",
+                "memfd_create(java.lang.String,int)",
                 "mincore(long,long,byte[])",
                 "mlock(long,long)",
                 "mmap(long,long,int,int,java.io.FileDescriptor,long)",
diff --git a/luni/src/test/java/libcore/libcore/net/MimeUtilsTest.java b/luni/src/test/java/libcore/libcore/net/MimeUtilsTest.java
deleted file mode 100644
index 7d7617b..0000000
--- a/luni/src/test/java/libcore/libcore/net/MimeUtilsTest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2014 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.libcore.net;
-
-import libcore.net.MimeUtils;
-
-import junit.framework.TestCase;
-
-import java.util.Locale;
-import java.util.Objects;
-
-public class MimeUtilsTest extends TestCase {
-    public void test_15715370() {
-        assertEquals("audio/flac", MimeUtils.guessMimeTypeFromExtension("flac"));
-        assertEquals("flac", MimeUtils.guessExtensionFromMimeType("audio/flac"));
-        assertEquals("flac", MimeUtils.guessExtensionFromMimeType("application/x-flac"));
-    }
-
-    // https://code.google.com/p/android/issues/detail?id=78909
-    public void test_78909() {
-        assertEquals("mka", MimeUtils.guessExtensionFromMimeType("audio/x-matroska"));
-        assertEquals("mkv", MimeUtils.guessExtensionFromMimeType("video/x-matroska"));
-    }
-
-    public void test_16978217() {
-        assertEquals("image/x-ms-bmp", MimeUtils.guessMimeTypeFromExtension("bmp"));
-        assertEquals("image/x-icon", MimeUtils.guessMimeTypeFromExtension("ico"));
-        assertEquals("video/mp2ts", MimeUtils.guessMimeTypeFromExtension("ts"));
-    }
-
-    public void testCommon() {
-        assertEquals("audio/mpeg", MimeUtils.guessMimeTypeFromExtension("mp3"));
-        assertEquals("image/png", MimeUtils.guessMimeTypeFromExtension("png"));
-        assertEquals("application/zip", MimeUtils.guessMimeTypeFromExtension("zip"));
-
-        assertEquals("mp3", MimeUtils.guessExtensionFromMimeType("audio/mpeg"));
-        assertEquals("png", MimeUtils.guessExtensionFromMimeType("image/png"));
-        assertEquals("zip", MimeUtils.guessExtensionFromMimeType("application/zip"));
-    }
-
-    public void test_18390752() {
-        assertEquals("jpg", MimeUtils.guessExtensionFromMimeType("image/jpeg"));
-    }
-
-    public void test_30207891() {
-        assertTrue(MimeUtils.hasMimeType("IMAGE/PNG"));
-        assertTrue(MimeUtils.hasMimeType("IMAGE/png"));
-        assertFalse(MimeUtils.hasMimeType(""));
-        assertEquals("png", MimeUtils.guessExtensionFromMimeType("IMAGE/PNG"));
-        assertEquals("png", MimeUtils.guessExtensionFromMimeType("IMAGE/png"));
-        assertNull(MimeUtils.guessMimeTypeFromExtension(""));
-        assertNull(MimeUtils.guessMimeTypeFromExtension("doesnotexist"));
-        assertTrue(MimeUtils.hasExtension("PNG"));
-        assertTrue(MimeUtils.hasExtension("PnG"));
-        assertFalse(MimeUtils.hasExtension(""));
-        assertFalse(MimeUtils.hasExtension(".png"));
-        assertEquals("image/png", MimeUtils.guessMimeTypeFromExtension("PNG"));
-        assertEquals("image/png", MimeUtils.guessMimeTypeFromExtension("PnG"));
-        assertNull(MimeUtils.guessMimeTypeFromExtension(".png"));
-        assertNull(MimeUtils.guessMimeTypeFromExtension(""));
-        assertNull(MimeUtils.guessExtensionFromMimeType("doesnotexist"));
-    }
-
-    public void test_30793548() {
-        assertEquals("video/3gpp", MimeUtils.guessMimeTypeFromExtension("3gpp"));
-        assertEquals("video/3gpp", MimeUtils.guessMimeTypeFromExtension("3gp"));
-        assertEquals("video/3gpp2", MimeUtils.guessMimeTypeFromExtension("3gpp2"));
-        assertEquals("video/3gpp2", MimeUtils.guessMimeTypeFromExtension("3g2"));
-    }
-
-    public void test_37167977() {
-        // https://tools.ietf.org/html/rfc5334#section-10.1
-        assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("ogg"));
-        assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("oga"));
-        assertEquals("audio/ogg", MimeUtils.guessMimeTypeFromExtension("spx"));
-        assertEquals("video/ogg", MimeUtils.guessMimeTypeFromExtension("ogv"));
-    }
-
-    public void test_70851634_mimeTypeFromExtension() {
-        assertEquals("video/vnd.youtube.yt", MimeUtils.guessMimeTypeFromExtension("yt"));
-    }
-
-    public void test_70851634_extensionFromMimeType() {
-        assertEquals("yt", MimeUtils.guessExtensionFromMimeType("video/vnd.youtube.yt"));
-        assertEquals("yt", MimeUtils.guessExtensionFromMimeType("application/vnd.youtube.yt"));
-    }
-
-    public void test_112162449_audio() {
-        // According to https://en.wikipedia.org/wiki/M3U#Internet_media_types
-        // this is a giant mess, so we pick "audio/x-mpegurl" because a similar
-        // playlist format uses "audio/x-scpls".
-        assertMimeTypeFromExtension("audio/x-mpegurl", "m3u");
-        assertMimeTypeFromExtension("audio/x-mpegurl", "m3u8");
-        assertExtensionFromMimeType("m3u", "audio/x-mpegurl");
-
-        assertExtensionFromMimeType("m4a", "audio/mp4");
-        assertMimeTypeFromExtension("audio/mpeg", "m4a");
-
-        assertBidirectional("audio/aac", "aac");
-    }
-
-    public void test_112162449_video() {
-        assertBidirectional("video/x-flv", "flv");
-        assertBidirectional("video/quicktime", "mov");
-        assertBidirectional("video/mpeg", "mpeg");
-    }
-
-    public void test_112162449_image() {
-        assertBidirectional("image/heif", "heif");
-        assertBidirectional("image/heif-sequence", "heifs");
-        assertBidirectional("image/heic", "heic");
-        assertBidirectional("image/heic-sequence", "heics");
-        assertMimeTypeFromExtension("image/heif", "hif");
-
-        assertBidirectional("image/x-adobe-dng", "dng");
-        assertBidirectional("image/x-photoshop", "psd");
-
-        assertBidirectional("image/jp2", "jp2");
-        assertMimeTypeFromExtension("image/jp2", "jpg2");
-    }
-
-    public void test_120135571_audio() {
-        assertMimeTypeFromExtension("audio/mpeg", "m4r");
-    }
-
-    public void testWifiConfig_xml() {
-        assertExtensionFromMimeType("xml", "application/x-wifi-config");
-        assertMimeTypeFromExtension("text/xml", "xml");
-    }
-
-    // http://b/122734564
-    public void testNonLowercaseMimeType() {
-        // A mixed-case mimeType that appears in mime.types; we expect guessMimeTypeFromExtension()
-        // to return it in lowercase because MimeUtils considers lowercase to be the canonical form.
-        String mimeType = "application/vnd.ms-word.document.macroEnabled.12".toLowerCase(Locale.US);
-        assertBidirectional(mimeType, "docm");
-    }
-
-    // Check that the keys given for lookups in either direction are not case sensitive
-    public void testCaseInsensitiveKeys() {
-        String mimeType = MimeUtils.guessMimeTypeFromExtension("apk");
-        assertNotNull(mimeType);
-
-        assertEquals(mimeType, MimeUtils.guessMimeTypeFromExtension("APK"));
-        assertEquals(mimeType, MimeUtils.guessMimeTypeFromExtension("aPk"));
-
-        assertEquals("apk", MimeUtils.guessExtensionFromMimeType(mimeType));
-        assertEquals("apk", MimeUtils.guessExtensionFromMimeType(mimeType.toUpperCase(Locale.US)));
-        assertEquals("apk", MimeUtils.guessExtensionFromMimeType(mimeType.toLowerCase(Locale.US)));
-    }
-
-    public void test_invalid_empty() {
-        checkInvalidExtension("");
-        checkInvalidMimeType("");
-    }
-
-    public void test_invalid_null() {
-        checkInvalidExtension(null);
-        checkInvalidMimeType(null);
-    }
-
-    public void test_invalid() {
-        checkInvalidMimeType("invalid mime type");
-        checkInvalidExtension("invalid extension");
-    }
-
-    private static void checkInvalidExtension(String s) {
-        assertFalse(MimeUtils.hasExtension(s));
-        assertNull(MimeUtils.guessMimeTypeFromExtension(s));
-    }
-
-    private static void checkInvalidMimeType(String s) {
-        assertFalse(MimeUtils.hasMimeType(s));
-        assertNull(MimeUtils.guessExtensionFromMimeType(s));
-    }
-
-    private static void assertMimeTypeFromExtension(String mimeType, String extension) {
-        final String actual = MimeUtils.guessMimeTypeFromExtension(extension);
-        if (!Objects.equals(mimeType, actual)) {
-            fail("Expected " + mimeType + " but was " + actual + " for extension " + extension);
-        }
-    }
-
-    private static void assertExtensionFromMimeType(String extension, String mimeType) {
-        final String actual = MimeUtils.guessExtensionFromMimeType(mimeType);
-        if (!Objects.equals(extension, actual)) {
-            fail("Expected " + extension + " but was " + actual + " for type " + mimeType);
-        }
-    }
-
-    private static void assertBidirectional(String mimeType, String extension) {
-        assertMimeTypeFromExtension(mimeType, extension);
-        assertExtensionFromMimeType(extension, mimeType);
-    }
-}
diff --git a/luni/src/test/java/libcore/libcore/net/http/ResponseUtilsTest.java b/luni/src/test/java/libcore/libcore/net/http/ResponseUtilsTest.java
deleted file mode 100644
index fed9e9b..0000000
--- a/luni/src/test/java/libcore/libcore/net/http/ResponseUtilsTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2014 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.libcore.net.http;
-
-import java.nio.charset.StandardCharsets;
-import java.nio.charset.UnsupportedCharsetException;
-import junit.framework.TestCase;
-import static libcore.net.http.ResponseUtils.responseCharset;
-
-public class ResponseUtilsTest extends TestCase {
-  public void test_responseCharset_missing() {
-    assertEquals(StandardCharsets.UTF_8, responseCharset(null));
-    assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain"));
-    assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain;foo=bar;baz=bal"));
-    assertEquals(StandardCharsets.UTF_8, responseCharset("text/plain;charset="));
-  }
-
-  public void test_responseCharset_valid() {
-    assertEquals(StandardCharsets.ISO_8859_1,
-            responseCharset("text/plain;charset=ISO-8859-1"));
-    assertEquals(StandardCharsets.ISO_8859_1,
-            responseCharset("text/plain;CHARSET=ISO-8859-1"));
-    assertEquals(StandardCharsets.ISO_8859_1,
-            responseCharset("text/plain;   charset  =   ISO-8859-1"));
-    assertEquals(StandardCharsets.ISO_8859_1,
-            responseCharset("text/plain; foo=bar;baz=bag;charset=ISO-8859-1"));
-    assertEquals(StandardCharsets.ISO_8859_1,
-            responseCharset("text/plain;charset=ISO-8859-1;;==,=="));
-  }
-
-  public void test_responseCharset_invalid() {
-    try {
-      responseCharset("text/plain;charset=unsupportedCharset");
-      fail();
-    } catch (UnsupportedCharsetException expected) {
-    }
-  }
-}
diff --git a/luni/src/test/java/libcore/libcore/reflect/ParameterizedTypeRegressionTest.java b/luni/src/test/java/libcore/libcore/reflect/ParameterizedTypeRegressionTest.java
new file mode 100644
index 0000000..7da1161
--- /dev/null
+++ b/luni/src/test/java/libcore/libcore/reflect/ParameterizedTypeRegressionTest.java
@@ -0,0 +1,277 @@
+/*
+ * 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 libcore.libcore.reflect;
+
+import com.google.common.base.Joiner;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+
+/**
+ * Regression tests for http://b/124315589
+ */
+public class ParameterizedTypeRegressionTest {
+
+    // A set of nested classes used by some of the tests in this class.
+    class A<X> {
+        class B<Y> {
+            class C1<Z> {
+                // Leaf not generic.
+                class D1 {
+                }
+            }
+            // Non-leaf not generic.
+            class C2 {
+                class D2<Z> {
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testNoGeneric() {
+        Type actual = new ParameterizedClass<List>() {
+            // Anonymous class declaration.
+        }.getArgumentType();
+        Class<List> expected = List.class;
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals("interface java.util.List", actual.toString());
+    }
+
+    @Test
+    public void testGeneric() {
+        Type actual = new ParameterizedClass<List<Integer>>() {
+            // Anonymous class declaration.
+        }.getArgumentType();
+        ParameterizedTypeImpl expected = new ParameterizedTypeImpl(
+                null,
+                List.class,
+                Integer.class
+        );
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals("java.util.List<java.lang.Integer>", actual.toString());
+    }
+
+    @Test
+    public void testGenericOfGeneric() {
+        Type actual = new ParameterizedClass<List<Map<String, Float>>>() {
+            // Anonymous class declaration.
+        }.getArgumentType();
+        ParameterizedTypeImpl expected = new ParameterizedTypeImpl(
+                null,
+                List.class,
+                new ParameterizedTypeImpl(
+                        null,
+                        Map.class,
+                        String.class,
+                        Float.class)
+        );
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals(
+                "java.util.List<java.util.Map<java.lang.String, java.lang.Float>>",
+                actual.toString());
+    }
+
+    @Test
+    public void testNested1() {
+        Type actual = new ParameterizedClass<A<Integer>>() {
+            // Anonymous class declaration.
+        }.getArgumentType();
+        ParameterizedTypeImpl expected = new ParameterizedTypeImpl(
+                ParameterizedTypeRegressionTest.class,
+                A.class,
+                Integer.class
+        );
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals(
+                "libcore.libcore.reflect.ParameterizedTypeRegressionTest$A<java.lang.Integer>",
+                actual.toString());
+    }
+
+    @Test
+    public void testNested2() {
+        Type actual = new ParameterizedClass<A<Integer>.B<Float>>() {
+            // Anonymous class declaration.
+        }.getArgumentType();
+        ParameterizedTypeImpl expected = new ParameterizedTypeImpl(
+                new ParameterizedTypeImpl(
+                        ParameterizedTypeRegressionTest.class,
+                        A.class,
+                        Integer.class),
+                A.B.class,
+                Float.class
+        );
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals(
+                "libcore.libcore.reflect.ParameterizedTypeRegressionTest$A<java.lang.Integer>"
+                        + "$B<java.lang.Float>",
+                actual.toString());
+    }
+
+    @Test
+    public void testNested3() {
+        Type actual = new ParameterizedClass<A<Integer>.B<Float>.C1<String>>() {
+            // Anonymous class declaration.
+        }.getArgumentType();
+        ParameterizedTypeImpl expected = new ParameterizedTypeImpl(
+                new ParameterizedTypeImpl(
+                        new ParameterizedTypeImpl(
+                                ParameterizedTypeRegressionTest.class,
+                                A.class,
+                                Integer.class),
+                        A.B.class,
+                        Float.class),
+                A.B.C1.class,
+                String.class);
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals(
+                "libcore.libcore.reflect.ParameterizedTypeRegressionTest$A<java.lang.Integer>"
+                        + "$B<java.lang.Float>"
+                        + "$C1<java.lang.String>",
+                actual.toString());
+    }
+
+    @Test
+    public void testNested4_nonGenericLeaf() {
+        // This anonymous class has a non-generic leaf class (D).
+        Type actual = new ParameterizedClass<A<Integer>.B<Float>.C1<String>.D1>() {
+            // Anonymous class declaration.
+        }.getArgumentType();
+        ParameterizedTypeImpl expected = new ParameterizedTypeImpl(
+                new ParameterizedTypeImpl(
+                        new ParameterizedTypeImpl(
+                                new ParameterizedTypeImpl(
+                                        ParameterizedTypeRegressionTest.class,
+                                        A.class,
+                                        Integer.class),
+                                A.B.class,
+                                Float.class),
+                        A.B.C1.class,
+                        String.class),
+                A.B.C1.D1.class
+        );
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals(
+                "libcore.libcore.reflect.ParameterizedTypeRegressionTest$A<java.lang.Integer>"
+                        + "$B<java.lang.Float>$C1<java.lang.String>$D1",
+                actual.toString());
+    }
+
+    @Test
+    public void testNested4_nonGenericNonLeaf() {
+        // This anonymous class has a non-generic class (C2).
+        Type actual = new ParameterizedClass<A<Integer>.B<Float>.C2.D2<String>>() {
+            // Anonymous class declaration.
+        }.getArgumentType();
+        ParameterizedTypeImpl expected = new ParameterizedTypeImpl(
+                new ParameterizedTypeImpl(
+                        new ParameterizedTypeImpl(
+                                new ParameterizedTypeImpl(
+                                        ParameterizedTypeRegressionTest.class,
+                                        A.class,
+                                        Integer.class),
+                                A.B.class,
+                                Float.class),
+                        A.B.C2.class),
+                A.B.C2.D2.class,
+                String.class
+        );
+        Assert.assertEquals(expected, actual);
+        Assert.assertEquals(
+                "libcore.libcore.reflect.ParameterizedTypeRegressionTest$A<java.lang.Integer>"
+                        + "$B<java.lang.Float>$C2$D2<java.lang.String>",
+                actual.toString());
+    }
+
+    private static class ParameterizedClass<T> {
+        public Type getArgumentType() {
+            Class<?> parameterizedClass = getClass();
+            return ((ParameterizedType) parameterizedClass.getGenericSuperclass())
+                    .getActualTypeArguments()[0];
+        }
+    }
+
+    /**
+     * A straightforward implementation of ParameterizedType that implements equals() and can be
+     * used when comparing against the platform behavior.
+     */
+    private static class ParameterizedTypeImpl implements ParameterizedType {
+        private final Type ownerType;
+        private final Class<?> rawType;
+        private final Type[] typeArguments;
+
+        ParameterizedTypeImpl(Type ownerType, Class<?> rawType, Type... typeArguments) {
+            this.ownerType = ownerType;
+            this.rawType = rawType;
+            this.typeArguments = typeArguments;
+        }
+
+        @Override
+        public Class getRawType() {
+            return rawType;
+        }
+
+        @Override
+        public Type[] getActualTypeArguments() {
+            return typeArguments;
+        }
+
+        @Override
+        public Type getOwnerType() {
+            return ownerType;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder stringBuilder = new StringBuilder();
+            if (ownerType != null) {
+                stringBuilder.append(ownerType.getTypeName());
+                stringBuilder.append('$');
+                stringBuilder.append(rawType.getSimpleName());
+            } else {
+                stringBuilder.append(rawType.getName());
+            }
+            stringBuilder.append('<');
+            List<String> typeArgumentNames = Arrays.stream(typeArguments)
+                    .map(Type::getTypeName)
+                    .collect(Collectors.toList());
+            stringBuilder.append(Joiner.on(", ").join(typeArgumentNames));
+            stringBuilder.append('>');
+            return stringBuilder.toString();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof ParameterizedType)) {
+                return false;
+            }
+            ParameterizedType other = (ParameterizedType) obj;
+            return getRawType().equals(other.getRawType()) &&
+                    Arrays.equals(getActualTypeArguments(), other.getActualTypeArguments()) &&
+                    Objects.equals(getOwnerType(), other.getOwnerType());
+        }
+    }
+}
diff --git a/luni/src/test/java/libcore/libcore/timezone/CountryTimeZonesTest.java b/luni/src/test/java/libcore/libcore/timezone/CountryTimeZonesTest.java
index 2a5f6e2..cf32896 100644
--- a/luni/src/test/java/libcore/libcore/timezone/CountryTimeZonesTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/CountryTimeZonesTest.java
@@ -20,8 +20,11 @@
 
 import android.icu.util.TimeZone;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import libcore.timezone.CountryTimeZones;
 import libcore.timezone.CountryTimeZones.OffsetResult;
@@ -39,13 +42,13 @@
 
     private static final String INVALID_TZ_ID = "Moon/Tranquility_Base";
 
-    // Zones used in the tests. NEW_YORK_TZ and LONDON_TZ chosen because they never overlap but both
-    // have DST.
-    private static final TimeZone NEW_YORK_TZ = TimeZone.getTimeZone("America/New_York");
-    private static final TimeZone LONDON_TZ = TimeZone.getTimeZone("Europe/London");
-    // A zone that matches LONDON_TZ for WHEN_NO_DST. It does not have DST so differs for WHEN_DST.
-    private static final TimeZone REYKJAVIK_TZ = TimeZone.getTimeZone("Atlantic/Reykjavik");
-    // Another zone that matches LONDON_TZ for WHEN_NO_DST. It does not have DST so differs for
+    // Zones used in the tests. NY_TZ and LON_TZ chosen because they never overlap but both have
+    // DST.
+    private static final TimeZone NY_TZ = TimeZone.getTimeZone("America/New_York");
+    private static final TimeZone LON_TZ = TimeZone.getTimeZone("Europe/London");
+    // A zone that matches LON_TZ for WHEN_NO_DST. It does not have DST so differs for WHEN_DST.
+    private static final TimeZone REYK_TZ = TimeZone.getTimeZone("Atlantic/Reykjavik");
+    // Another zone that matches LON_TZ for WHEN_NO_DST. It does not have DST so differs for
     // WHEN_DST.
     private static final TimeZone UTC_TZ = TimeZone.getTimeZone("Etc/UTC");
 
@@ -58,57 +61,63 @@
     // The offset applied to most zones during DST.
     private static final int NORMAL_DST_ADJUSTMENT = HOUR_MILLIS;
 
-    private static final int LONDON_NO_DST_OFFSET_MILLIS = 0;
-    private static final int LONDON_DST_OFFSET_MILLIS = LONDON_NO_DST_OFFSET_MILLIS
+    private static final int LON_NO_DST_TOTAL_OFFSET = 0;
+    private static final int LON_DST_TOTAL_OFFSET = LON_NO_DST_TOTAL_OFFSET
             + NORMAL_DST_ADJUSTMENT;
 
-    private static final int NEW_YORK_NO_DST_OFFSET_MILLIS = -5 * HOUR_MILLIS;
-    private static final int NEW_YORK_DST_OFFSET_MILLIS = NEW_YORK_NO_DST_OFFSET_MILLIS
+    private static final int NY_NO_DST_TOTAL_OFFSET = -5 * HOUR_MILLIS;
+    private static final int NY_DST_TOTAL_OFFSET = NY_NO_DST_TOTAL_OFFSET
             + NORMAL_DST_ADJUSTMENT;
 
     @Test
     public void createValidated() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */,
+                true /* everUsesUtc */, timeZoneMappings("Europe/London"), "test");
         assertTrue(countryTimeZones.isForCountryCode("gb"));
         assertEquals("Europe/London", countryTimeZones.getDefaultTimeZoneId());
         assertZoneEquals(zone("Europe/London"), countryTimeZones.getDefaultTimeZone());
         assertEquals(timeZoneMappings("Europe/London"), countryTimeZones.getTimeZoneMappings());
-        assertZonesEqual(zones("Europe/London"), countryTimeZones.getIcuTimeZones());
+        assertEquals(timeZoneMappings("Europe/London"),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(0 /* whenMillis */));
     }
 
     @Test
     public void createValidated_nullDefault() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "gb", null, true /* everUsesUtc */, timeZoneMappings("Europe/London"), "test");
+                "gb", null, false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
         assertNull(countryTimeZones.getDefaultTimeZoneId());
+        assertNull(countryTimeZones.getDefaultTimeZone());
     }
 
     @Test
     public void createValidated_invalidDefault() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "gb", INVALID_TZ_ID, true /* everUsesUtc */,
+                "gb", INVALID_TZ_ID, false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
                 timeZoneMappings("Europe/London", INVALID_TZ_ID), "test");
         assertNull(countryTimeZones.getDefaultTimeZoneId());
+        assertNull(countryTimeZones.getDefaultTimeZone());
         assertEquals(timeZoneMappings("Europe/London"), countryTimeZones.getTimeZoneMappings());
-        assertZonesEqual(zones("Europe/London"), countryTimeZones.getIcuTimeZones());
+        assertEquals(timeZoneMappings("Europe/London"),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(0 /* whenMillis */));
     }
 
     @Test
     public void createValidated_unknownTimeZoneIdIgnored() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */,
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
                 timeZoneMappings("Unknown_Id", "Europe/London"), "test");
         assertEquals(timeZoneMappings("Europe/London"), countryTimeZones.getTimeZoneMappings());
-        assertZonesEqual(zones("Europe/London"), countryTimeZones.getIcuTimeZones());
+        assertEquals(timeZoneMappings("Europe/London"),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(0 /* whenMillis */));
     }
 
     @Test
     public void isForCountryCode() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
         assertTrue(countryTimeZones.isForCountryCode("GB"));
         assertTrue(countryTimeZones.isForCountryCode("Gb"));
         assertTrue(countryTimeZones.isForCountryCode("gB"));
@@ -117,375 +126,134 @@
     @Test
     public void structuresAreImmutable() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
 
         assertImmutableTimeZone(countryTimeZones.getDefaultTimeZone());
 
-        List<TimeZone> tzList = countryTimeZones.getIcuTimeZones();
-        assertEquals(1, tzList.size());
-        assertImmutableList(tzList);
-        assertImmutableTimeZone(tzList.get(0));
-
         List<TimeZoneMapping> timeZoneMappings = countryTimeZones.getTimeZoneMappings();
         assertEquals(1, timeZoneMappings.size());
         assertImmutableList(timeZoneMappings);
-    }
 
-    @Test
-    public void lookupByOffsetWithBiasDeprecated_oneCandidate() throws Exception {
-        CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"), "test");
-
-        OffsetResult expectedResult = new OffsetResult(LONDON_TZ, true /* oneMatch */);
-
-        // The three parameters match the configured zone: offset, isDst and time.
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, null /* bias */));
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_NO_DST_OFFSET_MILLIS,
-                        false /* isDst */, WHEN_NO_DST, null /* bias */));
-
-        // Some lookup failure cases where the offset, isDst and time do not match the configured
-        // zone.
-        OffsetResult noDstMatch1 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
-
-        OffsetResult noDstMatch2 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch2);
-
-        OffsetResult noDstMatch3 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch3);
-
-        OffsetResult noDstMatch4 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch4);
-
-        OffsetResult noDstMatch5 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch5);
-
-        OffsetResult noDstMatch6 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch6);
-
-        // Some bias cases below.
-
-        // The bias is irrelevant here: it matches what would be returned anyway.
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, LONDON_TZ /* bias */));
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_NO_DST_OFFSET_MILLIS,
-                        false /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-        // A sample of a non-matching case with bias.
-        assertNull(countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                true /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-
-        // The bias should be ignored: it doesn't match any of the country's zones.
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, NEW_YORK_TZ /* bias */));
-
-        // The bias should still be ignored even though it matches the offset information given:
-        // it doesn't match any of the country's configured zones.
-        assertNull(countryTimeZones.lookupByOffsetWithBias(NEW_YORK_DST_OFFSET_MILLIS,
-                true /* isDst */, WHEN_DST, NEW_YORK_TZ /* bias */));
-    }
-
-    @Test
-    public void lookupByOffsetWithBiasDeprecated_multipleNonOverlappingCandidates()
-            throws Exception {
-        CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* everUsesUtc */,
-                timeZoneMappings("America/New_York", "Europe/London"), "test");
-
-        OffsetResult expectedLondonResult = new OffsetResult(LONDON_TZ, true /* oneMatch */);
-        OffsetResult expectedNewYorkResult = new OffsetResult(NEW_YORK_TZ, true /* oneMatch */);
-
-        // The three parameters match the configured zone: offset, isDst and time.
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */));
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, null /* bias */));
-        assertOffsetResultEquals(expectedNewYorkResult, countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */));
-        assertOffsetResultEquals(expectedNewYorkResult, countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, null /* bias */));
-
-        // Some lookup failure cases where the offset, isDst and time do not match the configured
-        // zone. This is a sample, not complete.
-        OffsetResult noDstMatch1 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
-
-        OffsetResult noDstMatch2 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch2);
-
-        OffsetResult noDstMatch3 = countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_NO_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch3);
-
-        OffsetResult noDstMatch4 = countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_NO_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch4);
-
-        OffsetResult noDstMatch5 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch5);
-
-        OffsetResult noDstMatch6 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch6);
-
-        // Some bias cases below.
-
-        // The bias is irrelevant here: it matches what would be returned anyway.
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, LONDON_TZ /* bias */));
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-        // A sample of a non-matching case with bias.
-        assertNull(countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-
-        // The bias should be ignored: it matches a configured zone, but the offset is wrong so
-        // should not be considered a match.
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, NEW_YORK_TZ /* bias */));
-    }
-
-    // This is an artificial case very similar to America/Denver and America/Phoenix in the US: both
-    // have the same offset for 6 months of the year but diverge. Australia/Lord_Howe too.
-    @Test
-    public void lookupByOffsetWithBiasDeprecated_multipleOverlappingCandidates() throws Exception {
-        // Three zones that have the same offset for some of the year. Europe/London changes
-        // offset WHEN_DST, the others do not.
-        CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* everUsesUtc */,
-                timeZoneMappings("Atlantic/Reykjavik", "Europe/London", "Etc/UTC"), "test");
-
-        // This is the no-DST offset for LONDON_TZ, REYKJAVIK_TZ. UTC_TZ.
-        final int noDstOffset = LONDON_NO_DST_OFFSET_MILLIS;
-        // This is the DST offset for LONDON_TZ.
-        final int dstOffset = LONDON_DST_OFFSET_MILLIS;
-
-        OffsetResult expectedLondonOnlyMatch = new OffsetResult(LONDON_TZ, true /* oneMatch */);
-        OffsetResult expectedReykjavikBestMatch =
-                new OffsetResult(REYKJAVIK_TZ, false /* oneMatch */);
-
-        // The three parameters match the configured zone: offset, isDst and when.
-        assertOffsetResultEquals(expectedLondonOnlyMatch,
-                countryTimeZones.lookupByOffsetWithBias(dstOffset, true /* isDst */, WHEN_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, false /* isDst */, WHEN_NO_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedLondonOnlyMatch,
-                countryTimeZones.lookupByOffsetWithBias(dstOffset, true /* isDst */, WHEN_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, false /* isDst */, WHEN_NO_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, false /* isDst */, WHEN_DST,
-                        null /* bias */));
-
-        // Some lookup failure cases where the offset, isDst and time do not match the configured
-        // zones.
-        OffsetResult noDstMatch1 = countryTimeZones.lookupByOffsetWithBias(dstOffset,
-                true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
-
-        OffsetResult noDstMatch2 = countryTimeZones.lookupByOffsetWithBias(noDstOffset,
-                true /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch2);
-
-        OffsetResult noDstMatch3 = countryTimeZones.lookupByOffsetWithBias(noDstOffset,
-                true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch3);
-
-        OffsetResult noDstMatch4 = countryTimeZones.lookupByOffsetWithBias(dstOffset,
-                false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch4);
-
-
-        // Some bias cases below.
-
-        // Multiple zones match but Reykjavik is the bias.
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, false /* isDst */, WHEN_NO_DST,
-                        REYKJAVIK_TZ /* bias */));
-
-        // Multiple zones match but London is the bias.
-        OffsetResult expectedLondonBestMatch = new OffsetResult(LONDON_TZ, false /* oneMatch */);
-        assertOffsetResultEquals(expectedLondonBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, false /* isDst */, WHEN_NO_DST,
-                        LONDON_TZ /* bias */));
-
-        // Multiple zones match but UTC is the bias.
-        OffsetResult expectedUtcResult = new OffsetResult(UTC_TZ, false /* oneMatch */);
-        assertOffsetResultEquals(expectedUtcResult,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, false /* isDst */, WHEN_NO_DST,
-                        UTC_TZ /* bias */));
-
-        // The bias should be ignored: it matches a configured zone, but the offset is wrong so
-        // should not be considered a match.
-        assertOffsetResultEquals(expectedLondonOnlyMatch,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS, true /* isDst */,
-                        WHEN_DST, REYKJAVIK_TZ /* bias */));
+        List<TimeZoneMapping> effectiveTimeZoneMappings =
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(0 /* whenMillis */);
+        assertEquals(1, effectiveTimeZoneMappings.size());
+        assertImmutableList(effectiveTimeZoneMappings);
     }
 
     @Test
     public void lookupByOffsetWithBias_oneCandidate() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* uses UTC */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
 
-        OffsetResult expectedResult = new OffsetResult(LONDON_TZ, true /* oneMatch */);
+        OffsetResult lonMatch = new OffsetResult(LON_TZ, true /* oneMatch */);
 
-        // The three parameters match the configured zone: offset, isDst and time.
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                        NORMAL_DST_ADJUSTMENT, WHEN_DST, null /* bias */));
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_NO_DST_OFFSET_MILLIS,
-                        0 /* no DST */, WHEN_NO_DST, null /* bias */));
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                        null /* unknown DST */, WHEN_DST, null /* bias */));
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_NO_DST_OFFSET_MILLIS,
-                        null /* unknown DST */, WHEN_NO_DST, null /* bias */));
+        // Placeholder constants to improve test case readability.
+        final Boolean isDst = true;
+        final Boolean notDst = false;
+        final Boolean unkIsDst = null;
+        final TimeZone noBias = null;
+        final OffsetResult noMatch = null;
 
-        // Some lookup failure cases where the offset, DST offset and time do not match the
-        // configured zone.
-        OffsetResult noDstMatch1 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
+        Object[][] testCases = new Object[][] {
+                // totalOffsetMillis, isDst, whenMillis, bias, expectedMatch
 
-        OffsetResult noDstMatch2 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch2);
+                // The parameters match the zone: total offset and time.
+                { LON_DST_TOTAL_OFFSET, unkIsDst, WHEN_DST, noBias, lonMatch },
+                { LON_NO_DST_TOTAL_OFFSET, unkIsDst, WHEN_NO_DST, noBias, lonMatch },
 
-        OffsetResult noDstMatch3 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch3);
+                // The parameters match the zone: total offset, isDst and time.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_DST, noBias, lonMatch },
+                { LON_NO_DST_TOTAL_OFFSET, notDst, WHEN_NO_DST, noBias, lonMatch },
 
-        OffsetResult noDstMatch4 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch4);
+                // Some lookup failure cases where the total offset, isDst and time do not match the
+                // zone.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_NO_DST, noBias, noMatch },
+                { LON_DST_TOTAL_OFFSET, notDst, WHEN_NO_DST, noBias, noMatch },
+                { LON_NO_DST_TOTAL_OFFSET, isDst, WHEN_DST, noBias, noMatch },
+                { LON_NO_DST_TOTAL_OFFSET, isDst, WHEN_NO_DST, noBias, noMatch },
+                { LON_DST_TOTAL_OFFSET, notDst, WHEN_DST, noBias, noMatch },
+                { LON_NO_DST_TOTAL_OFFSET, notDst, WHEN_DST, noBias, noMatch },
 
-        OffsetResult noDstMatch5 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch5);
+                // Some bias cases below.
 
-        OffsetResult noDstMatch6 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch6);
+                // The bias is irrelevant here: it matches what would be returned anyway.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_DST, LON_TZ, lonMatch },
+                { LON_NO_DST_TOTAL_OFFSET, notDst, WHEN_NO_DST, LON_TZ, lonMatch },
 
-        // Some bias cases below.
+                // A sample of a non-matching case with bias.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_NO_DST, LON_TZ, noMatch },
 
-        // The bias is irrelevant here: it matches what would be returned anyway.
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                        NORMAL_DST_ADJUSTMENT, WHEN_DST, LONDON_TZ /* bias */));
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_NO_DST_OFFSET_MILLIS,
-                        0 /* no DST */, WHEN_NO_DST, LONDON_TZ /* bias */));
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_NO_DST_OFFSET_MILLIS,
-                        null /* unknown DST */, WHEN_NO_DST, LONDON_TZ /* bias */));
-        // A sample of a non-matching case with bias.
-        assertNull(countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                NORMAL_DST_ADJUSTMENT, WHEN_NO_DST, LONDON_TZ /* bias */));
+                // The bias should be ignored: it doesn't match any of the country's zones.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_DST, NY_TZ, lonMatch },
 
-        // The bias should be ignored: it doesn't match any of the country's zones.
-        assertOffsetResultEquals(expectedResult,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                        NORMAL_DST_ADJUSTMENT, WHEN_DST, NEW_YORK_TZ /* bias */));
-
-        // The bias should still be ignored even though it matches the offset information given:
-        // it doesn't match any of the country's configured zones.
-        assertNull(countryTimeZones.lookupByOffsetWithBias(NEW_YORK_DST_OFFSET_MILLIS,
-                NORMAL_DST_ADJUSTMENT, WHEN_DST, NEW_YORK_TZ /* bias */));
+                // The bias should still be ignored even though it matches the offset information
+                // given it doesn't match any of the country's zones.
+                { NY_DST_TOTAL_OFFSET, isDst, WHEN_DST, NY_TZ, noMatch },
+        };
+        executeLookupByOffsetWithBiasTestCases(countryTimeZones, testCases);
     }
 
     @Test
-    public void lookupByOffsetWithBias_multipleNonOverlappingCandidates()
-            throws Exception {
+    public void lookupByOffsetWithBias_multipleNonOverlappingCandidates() throws Exception {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* uses UTC */,
+                "xx", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
                 timeZoneMappings("America/New_York", "Europe/London"), "test");
 
-        OffsetResult expectedLondonResult = new OffsetResult(LONDON_TZ, true /* oneMatch */);
-        OffsetResult expectedNewYorkResult = new OffsetResult(NEW_YORK_TZ, true /* oneMatch */);
+        OffsetResult lonMatch = new OffsetResult(LON_TZ, true /* oneMatch */);
+        OffsetResult nyMatch = new OffsetResult(NY_TZ, true /* oneMatch */);
 
-        // The three parameters match the configured zone: offset, DST offset and time.
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_DST, null /* bias */));
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_NO_DST, null /* bias */));
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, null /* unknown DST */, WHEN_NO_DST, null /* bias */));
-        assertOffsetResultEquals(expectedNewYorkResult, countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_DST, null /* bias */));
-        assertOffsetResultEquals(expectedNewYorkResult, countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_NO_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_NO_DST, null /* bias */));
-        assertOffsetResultEquals(expectedNewYorkResult, countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_NO_DST_OFFSET_MILLIS, null /* unknown DST */, WHEN_NO_DST,
-                null /* bias */));
+        // Placeholder constants to improve test case readability.
+        final Boolean isDst = true;
+        final Boolean notDst = false;
+        final Boolean unkIsDst = null;
+        final TimeZone noBias = null;
+        final OffsetResult noMatch = null;
 
-        // Some lookup failure cases where the offset, DST offset and time do not match the
-        // configured zone. This is a sample, not complete.
-        OffsetResult noDstMatch1 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
+        Object[][] testCases = new Object[][] {
+                // totalOffsetMillis, isDst, dstOffsetMillis, whenMillis, bias, expectedMatch
 
-        OffsetResult noDstMatch2 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch2);
+                // The parameters match the zone: total offset and time.
+                { LON_DST_TOTAL_OFFSET, unkIsDst, WHEN_DST, noBias, lonMatch },
+                { LON_NO_DST_TOTAL_OFFSET, unkIsDst, WHEN_NO_DST, noBias, lonMatch },
+                { NY_NO_DST_TOTAL_OFFSET, unkIsDst, WHEN_NO_DST, noBias, nyMatch },
+                { NY_DST_TOTAL_OFFSET, unkIsDst, WHEN_DST, noBias, nyMatch },
 
-        OffsetResult noDstMatch3 = countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_NO_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch3);
+                // The parameters match the zone: total offset, isDst and time.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_DST, noBias, lonMatch },
+                { LON_NO_DST_TOTAL_OFFSET, notDst, WHEN_NO_DST, noBias, lonMatch },
+                { NY_DST_TOTAL_OFFSET, isDst, WHEN_DST, noBias, nyMatch },
+                { NY_NO_DST_TOTAL_OFFSET, notDst, WHEN_NO_DST, noBias, nyMatch },
 
-        OffsetResult noDstMatch4 = countryTimeZones.lookupByOffsetWithBias(
-                NEW_YORK_NO_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch4);
+                // Some lookup failure cases where the total offset, isDst and time do not match the
+                // zone. This is a sample, not complete.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_NO_DST, noBias, noMatch },
+                { LON_DST_TOTAL_OFFSET, unkIsDst, WHEN_NO_DST, noBias, noMatch },
+                { LON_DST_TOTAL_OFFSET, notDst, WHEN_DST, noBias, noMatch },
+                { LON_NO_DST_TOTAL_OFFSET, isDst, WHEN_DST, noBias, noMatch },
+                { LON_NO_DST_TOTAL_OFFSET, isDst, WHEN_NO_DST, noBias, noMatch },
+                { LON_NO_DST_TOTAL_OFFSET, unkIsDst, WHEN_DST, noBias, noMatch },
+                { LON_NO_DST_TOTAL_OFFSET, notDst, WHEN_DST, noBias, noMatch },
 
-        OffsetResult noDstMatch5 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch5);
+                // Some bias cases below.
 
-        OffsetResult noDstMatch6 = countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch6);
+                // The bias is irrelevant here: it matches what would be returned anyway.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_DST, LON_TZ, lonMatch },
+                { LON_DST_TOTAL_OFFSET, unkIsDst, WHEN_DST, LON_TZ, lonMatch },
+                { LON_NO_DST_TOTAL_OFFSET, unkIsDst, WHEN_NO_DST, LON_TZ, lonMatch },
 
-        // Some bias cases below.
+                // A sample of non-matching cases with bias.
+                { LON_NO_DST_TOTAL_OFFSET, isDst, WHEN_NO_DST, LON_TZ, noMatch },
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_NO_DST, LON_TZ, noMatch },
+                { LON_DST_TOTAL_OFFSET, unkIsDst, WHEN_NO_DST, LON_TZ, noMatch },
 
-        // The bias is irrelevant here: it matches what would be returned anyway.
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_DST, LONDON_TZ /* bias */));
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, 0 /* no DST */, WHEN_NO_DST, LONDON_TZ /* bias */));
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_NO_DST_OFFSET_MILLIS, null /* unknown DST */, WHEN_NO_DST,
-                LONDON_TZ /* bias */));
-
-        // A sample of a non-matching case with bias.
-        assertNull(countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_NO_DST, LONDON_TZ /* bias */));
-
-        // The bias should be ignored: it matches a configured zone, but the offset is wrong so
-        // should not be considered a match.
-        assertOffsetResultEquals(expectedLondonResult, countryTimeZones.lookupByOffsetWithBias(
-                LONDON_DST_OFFSET_MILLIS, NORMAL_DST_ADJUSTMENT, WHEN_DST, NEW_YORK_TZ /* bias */));
+                // The bias should be ignored: it matches a zone, but the offset is wrong so
+                // should not be considered a match.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_DST, NY_TZ, lonMatch },
+                { LON_DST_TOTAL_OFFSET, unkIsDst, WHEN_DST, NY_TZ, lonMatch },
+        };
+        executeLookupByOffsetWithBiasTestCases(countryTimeZones, testCases);
     }
 
     // This is an artificial case very similar to America/Denver and America/Phoenix in the US: both
@@ -495,146 +263,171 @@
         // Three zones that have the same offset for some of the year. Europe/London changes
         // offset WHEN_DST, the others do not.
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* uses UTC */,
+                "xx", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
                 timeZoneMappings("Atlantic/Reykjavik", "Europe/London", "Etc/UTC"), "test");
 
-        // This is the no-DST offset for LONDON_TZ, REYKJAVIK_TZ. UTC_TZ.
-        final int noDstOffset = LONDON_NO_DST_OFFSET_MILLIS;
-        // This is the DST offset for LONDON_TZ.
-        final int dstOffset = LONDON_DST_OFFSET_MILLIS;
+        // Placeholder constants to improve test case readability.
+        final Boolean isDst = true;
+        final Boolean notDst = false;
+        final Boolean unkIsDst = null;
+        final TimeZone noBias = null;
+        final OffsetResult noMatch = null;
 
-        OffsetResult expectedLondonOnlyMatch = new OffsetResult(LONDON_TZ, true /* oneMatch */);
-        OffsetResult expectedReykjavikBestMatch =
-                new OffsetResult(REYKJAVIK_TZ, false /* oneMatch */);
+        // This is the no-DST offset for LON_TZ, REYK_TZ. UTC_TZ.
+        final int noDstTotalOffset = LON_NO_DST_TOTAL_OFFSET;
+        // This is the DST offset for LON_TZ.
+        final int dstTotalOffset = LON_DST_TOTAL_OFFSET;
 
-        // The three parameters match the configured zone: offset, DST offset and time.
-        assertOffsetResultEquals(expectedLondonOnlyMatch,
-                countryTimeZones.lookupByOffsetWithBias(dstOffset, NORMAL_DST_ADJUSTMENT, WHEN_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, 0 /* no DST */, WHEN_NO_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedLondonOnlyMatch,
-                countryTimeZones.lookupByOffsetWithBias(dstOffset, NORMAL_DST_ADJUSTMENT, WHEN_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, 0 /* no DST */, WHEN_NO_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, 0 /* no DST */, WHEN_DST,
-                        null /* bias */));
+        OffsetResult lonOnlyMatch = new OffsetResult(LON_TZ, true /* oneMatch */);
+        OffsetResult lonBestMatch = new OffsetResult(LON_TZ, false /* oneMatch */);
+        OffsetResult reykBestMatch = new OffsetResult(REYK_TZ, false /* oneMatch */);
+        OffsetResult utcBestMatch = new OffsetResult(UTC_TZ, false /* oneMatch */);
 
-        // Unknown DST cases
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, null, WHEN_NO_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, null, WHEN_DST,
-                        null /* bias */));
-        assertNull(countryTimeZones.lookupByOffsetWithBias(dstOffset, null, WHEN_NO_DST,
-                        null /* bias */));
-        assertOffsetResultEquals(expectedLondonOnlyMatch,
-                countryTimeZones.lookupByOffsetWithBias(dstOffset, null, WHEN_DST,
-                        null /* bias */));
+        Object[][] testCases = new Object[][] {
+                // totalOffsetMillis, isDst, dstOffsetMillis, whenMillis, bias, expectedMatch
 
-        // Some lookup failure cases where the offset, DST offset and time do not match the
-        // configured zones.
-        OffsetResult noDstMatch1 = countryTimeZones.lookupByOffsetWithBias(dstOffset,
-                NORMAL_DST_ADJUSTMENT, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
+                // The parameters match one zone: total offset and time.
+                { dstTotalOffset, unkIsDst, WHEN_DST, noBias, lonOnlyMatch },
+                { dstTotalOffset, unkIsDst, WHEN_DST, noBias, lonOnlyMatch },
 
-        OffsetResult noDstMatch2 = countryTimeZones.lookupByOffsetWithBias(noDstOffset,
-                NORMAL_DST_ADJUSTMENT, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch2);
+                // The parameters match several zones: total offset and time.
+                { noDstTotalOffset, unkIsDst, WHEN_NO_DST, noBias, reykBestMatch },
+                { noDstTotalOffset, unkIsDst, WHEN_DST, noBias, reykBestMatch },
 
-        OffsetResult noDstMatch3 = countryTimeZones.lookupByOffsetWithBias(noDstOffset,
-                NORMAL_DST_ADJUSTMENT, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch3);
+                // The parameters match one zone: total offset, isDst and time.
+                { dstTotalOffset, isDst, WHEN_DST, noBias, lonOnlyMatch },
+                { dstTotalOffset, isDst, WHEN_DST, noBias, lonOnlyMatch },
 
-        OffsetResult noDstMatch4 = countryTimeZones.lookupByOffsetWithBias(dstOffset,
-                0 /* no DST */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch4);
+                { noDstTotalOffset, notDst, WHEN_NO_DST, noBias, reykBestMatch },
+                { noDstTotalOffset, notDst, WHEN_DST, noBias, reykBestMatch },
 
+                // Some lookup failure cases where the total offset, isDst and time do not match any
+                // zone.
+                { dstTotalOffset, isDst, WHEN_NO_DST, noBias, noMatch },
+                { dstTotalOffset, unkIsDst, WHEN_NO_DST, noBias, noMatch },
+                { noDstTotalOffset, isDst, WHEN_NO_DST, noBias, noMatch },
+                { noDstTotalOffset, isDst, WHEN_DST, noBias, noMatch },
 
-        // Some bias cases below.
+                // Some bias cases below.
 
-        // Multiple zones match but Reykjavik is the bias.
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, 0 /* no DST */, WHEN_NO_DST,
-                        REYKJAVIK_TZ /* bias */));
-        assertOffsetResultEquals(expectedReykjavikBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, null /* unknown DST */,
-                        WHEN_NO_DST, REYKJAVIK_TZ /* bias */));
+                // Multiple zones match but Reykjavik is the bias.
+                { noDstTotalOffset, notDst, WHEN_NO_DST, REYK_TZ, reykBestMatch },
 
-        // Multiple zones match but London is the bias.
-        OffsetResult expectedLondonBestMatch = new OffsetResult(LONDON_TZ, false /* oneMatch */);
-        assertOffsetResultEquals(expectedLondonBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, 0 /* no DST */, WHEN_NO_DST,
-                        LONDON_TZ /* bias */));
-        assertOffsetResultEquals(expectedLondonBestMatch,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, null /* unknown DST */,
-                        WHEN_NO_DST, LONDON_TZ /* bias */));
+                // Multiple zones match but London is the bias.
+                { noDstTotalOffset, notDst, WHEN_NO_DST, LON_TZ, lonBestMatch },
 
-        // Multiple zones match but UTC is the bias.
-        OffsetResult expectedUtcResult = new OffsetResult(UTC_TZ, false /* oneMatch */);
-        assertOffsetResultEquals(expectedUtcResult,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, 0 /* no DST */, WHEN_NO_DST,
-                        UTC_TZ /* bias */));
-        assertOffsetResultEquals(expectedUtcResult,
-                countryTimeZones.lookupByOffsetWithBias(noDstOffset, null /* unknown DST */,
-                        WHEN_NO_DST, UTC_TZ /* bias */));
+                // Multiple zones match but UTC is the bias.
+                { noDstTotalOffset, notDst, WHEN_NO_DST, UTC_TZ, utcBestMatch },
 
-        // The bias should be ignored: it matches a configured zone, but the offset is wrong so
-        // should not be considered a match.
-        assertOffsetResultEquals(expectedLondonOnlyMatch,
-                countryTimeZones.lookupByOffsetWithBias(LONDON_DST_OFFSET_MILLIS,
-                        NORMAL_DST_ADJUSTMENT, WHEN_DST, REYKJAVIK_TZ /* bias */));
+                // The bias should be ignored: it matches a zone, but the offset is wrong so
+                // should not be considered a match.
+                { LON_DST_TOTAL_OFFSET, isDst, WHEN_DST, REYK_TZ, lonOnlyMatch },
+                { LON_DST_TOTAL_OFFSET, unkIsDst, WHEN_DST, REYK_TZ, lonOnlyMatch },
+        };
+        executeLookupByOffsetWithBiasTestCases(countryTimeZones, testCases);
+    }
+
+    private static void executeLookupByOffsetWithBiasTestCases(
+            CountryTimeZones countryTimeZones, Object[][] testCases) {
+
+        List<String> failures = new ArrayList<>();
+        for (int i = 0; i < testCases.length; i++) {
+            Object[] testCase = testCases[i];
+            int totalOffsetMillis = (int) testCase[0];
+            Boolean isDst = (Boolean) testCase[1];
+            long whenMillis = (Long) testCase[2];
+            TimeZone bias = (TimeZone) testCase[3];
+            OffsetResult expectedMatch = (OffsetResult) testCase[4];
+
+            OffsetResult actualMatch;
+            if (isDst == null) {
+                actualMatch = countryTimeZones.lookupByOffsetWithBias(
+                        whenMillis, bias, totalOffsetMillis);
+            } else {
+                actualMatch = countryTimeZones.lookupByOffsetWithBias(
+                        whenMillis, bias, totalOffsetMillis, isDst);
+            }
+
+            if (!offsetResultEquals(expectedMatch, actualMatch)) {
+                Function<TimeZone, String> timeZoneFormatter =
+                        x -> x == null ? "null" : x.getID();
+                Function<OffsetResult, String> offsetResultFormatter =
+                        x -> x == null ? "null"
+                                : "{" + x.getTimeZone().getID() + ", " + x.isOnlyMatch() + "}";
+                failures.add("Fail: case=" + i
+                        + ", totalOffsetMillis=" + totalOffsetMillis
+                        + ", isDst=" + isDst
+                        + ", whenMillis=" + whenMillis
+                        + ", bias=" + timeZoneFormatter.apply(bias)
+                        + ", expectedMatch=" + offsetResultFormatter.apply(expectedMatch)
+                        + ", actualMatch=" + offsetResultFormatter.apply(actualMatch)
+                        + "\n");
+            }
+        }
+        if (!failures.isEmpty()) {
+            fail("Failed:\n" + failures);
+        }
     }
 
     @Test
-    public void isDefaultOkForCountryTimeZoneDetection_noZones() {
+    public void getEffectiveTimeZonesAt_noZones() {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* everUsesUtc */, timeZoneMappings(), "test");
-        assertFalse(countryTimeZones.isDefaultOkForCountryTimeZoneDetection(WHEN_DST));
-        assertFalse(countryTimeZones.isDefaultOkForCountryTimeZoneDetection(WHEN_NO_DST));
+                "xx", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings(), "test");
+        assertEquals(timeZoneMappings(),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(0 /* whenMillis */));
+        assertEquals(timeZoneMappings(),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(Long.MIN_VALUE));
+        assertEquals(timeZoneMappings(),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(Long.MAX_VALUE));
     }
 
     @Test
-    public void isDefaultOkForCountryTimeZoneDetection_oneZone() {
+    public void getEffectiveTimeZonesAt_oneZone() {
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
-        assertTrue(countryTimeZones.isDefaultOkForCountryTimeZoneDetection(WHEN_DST));
-        assertTrue(countryTimeZones.isDefaultOkForCountryTimeZoneDetection(WHEN_NO_DST));
+                "xx", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
+        assertEquals(timeZoneMappings("Europe/London"),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(0));
+        assertEquals(timeZoneMappings("Europe/London"),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(Long.MIN_VALUE));
+        assertEquals(timeZoneMappings("Europe/London"),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(Long.MAX_VALUE));
     }
 
     @Test
-    public void isDefaultOkForCountryTimeZoneDetection_twoZones_overlap() {
-        CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* everUsesUtc */,
-                timeZoneMappings("Europe/London", "Etc/UTC"), "test");
-        // Europe/London is the same as UTC in the Winter, so all the zones have the same offset
-        // in Winter, but not in Summer.
-        assertFalse(countryTimeZones.isDefaultOkForCountryTimeZoneDetection(WHEN_DST));
-        assertTrue(countryTimeZones.isDefaultOkForCountryTimeZoneDetection(WHEN_NO_DST));
-    }
+    public void getEffectiveTimeZonesAt_filtering() {
+        TimeZoneMapping alwaysUsed = timeZoneMapping("Europe/London", null /* notUsedAfter */);
 
-    @Test
-    public void isDefaultOkForCountryTimeZoneDetection_twoZones_noOverlap() {
+        long mappingNotUsedAfterMillis = 0L;
+        TimeZoneMapping notAlwaysUsed = timeZoneMapping("Europe/Paris",
+                mappingNotUsedAfterMillis /* notUsedAfter */);
+
+        List<TimeZoneMapping> timeZoneMappings = list(alwaysUsed, notAlwaysUsed);
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* everUsesUtc */,
-                timeZoneMappings("Europe/London", "America/New_York"), "test");
-        // The zones have different offsets all year, so it would never be ok to use the default
-        // zone for the country of "xx".
-        assertFalse(countryTimeZones.isDefaultOkForCountryTimeZoneDetection(WHEN_DST));
-        assertFalse(countryTimeZones.isDefaultOkForCountryTimeZoneDetection(WHEN_NO_DST));
+                "xx", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings, "test");
+
+        // Before and at mappingNotUsedAfterMillis, both mappings are "effective".
+        assertEquals(list(alwaysUsed, notAlwaysUsed),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(Long.MIN_VALUE));
+        assertEquals(list(alwaysUsed, notAlwaysUsed),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(mappingNotUsedAfterMillis));
+
+        // The following should filter the second mapping because it's not "effective" after
+        // mappingNotUsedAfterMillis.
+        assertEquals(list(alwaysUsed),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(mappingNotUsedAfterMillis + 1));
+        assertEquals(list(alwaysUsed),
+                countryTimeZones.getEffectiveTimeZoneMappingsAt(Long.MAX_VALUE));
     }
 
     @Test
     public void hasUtcZone_everUseUtcHintOverridesZoneInformation() {
         // The country has a single zone. Europe/London uses UTC in Winter.
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Etc/UTC", false /* everUsesUtc */, timeZoneMappings("Etc/UTC"), "test");
+                "xx", "Etc/UTC", false /* defaultTimeZoneBoost */, false /* everUsesUtc */,
+                timeZoneMappings("Etc/UTC"), "test");
         assertFalse(countryTimeZones.hasUtcZone(WHEN_DST));
         assertFalse(countryTimeZones.hasUtcZone(WHEN_NO_DST));
     }
@@ -643,8 +436,8 @@
     public void hasUtcZone_singleZone() {
         // The country has a single zone. Europe/London uses UTC in Winter.
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "xx", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
         assertFalse(countryTimeZones.hasUtcZone(WHEN_DST));
         assertTrue(countryTimeZones.hasUtcZone(WHEN_NO_DST));
     }
@@ -653,7 +446,8 @@
     public void hasUtcZone_multipleZonesWithUtc() {
         // The country has multiple zones. Europe/London uses UTC in Winter.
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "America/Los_Angeles", true /* everUsesUtc */,
+                "xx", "America/Los_Angeles", false /* defaultTimeZoneBoost */,
+                true /* everUsesUtc */,
                 timeZoneMappings("America/Los_Angeles", "America/New_York", "Europe/London"),
                 "test");
         assertFalse(countryTimeZones.hasUtcZone(WHEN_DST));
@@ -664,7 +458,7 @@
     public void hasUtcZone_multipleZonesWithoutUtc() {
         // The country has multiple zones, none of which use UTC.
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", "Europe/Paris", false /* everUsesUtc */,
+                "xx", "Europe/Paris", false /* defaultTimeZoneBoost */, false /* everUsesUtc */,
                 timeZoneMappings("America/Los_Angeles", "America/New_York", "Europe/Paris"),
                 "test");
         assertFalse(countryTimeZones.hasUtcZone(WHEN_DST));
@@ -675,13 +469,33 @@
     public void hasUtcZone_emptyZones() {
         // The country has no valid zones.
         CountryTimeZones countryTimeZones = CountryTimeZones.createValidated(
-                "xx", INVALID_TZ_ID, false /* everUsesUtc */, timeZoneMappings(INVALID_TZ_ID),
-                "test");
+                "xx", INVALID_TZ_ID, false /* defaultTimeZoneBoost */, false /* everUsesUtc */,
+                timeZoneMappings(INVALID_TZ_ID), "test");
         assertTrue(countryTimeZones.getTimeZoneMappings().isEmpty());
         assertFalse(countryTimeZones.hasUtcZone(WHEN_DST));
         assertFalse(countryTimeZones.hasUtcZone(WHEN_NO_DST));
     }
 
+    @Test
+    public void timeZoneMapping_getTimeZone_badZoneId() {
+        TimeZoneMapping timeZoneMapping =
+                TimeZoneMapping.createForTests("DOES_NOT_EXIST", true, 1234L);
+        try {
+            timeZoneMapping.getTimeZone();
+            fail();
+        } catch (RuntimeException expected) {
+        }
+    }
+
+    @Test
+    public void timeZoneMapping_getTimeZone_validZoneId() {
+        TimeZoneMapping timeZoneMapping =
+                TimeZoneMapping.createForTests("Europe/London", true, 1234L);
+        TimeZone timeZone = timeZoneMapping.getTimeZone();
+        assertTrue(timeZone.isFrozen());
+        assertEquals("Europe/London", timeZone.getID());
+    }
+
     private void assertImmutableTimeZone(TimeZone timeZone) {
         try {
             timeZone.setRawOffset(1000);
@@ -703,18 +517,19 @@
         assertEquals(expected, actual);
     }
 
-    private static void assertOffsetResultEquals(OffsetResult expected, OffsetResult actual) {
-        assertEquals(expected.mTimeZone.getID(), actual.mTimeZone.getID());
-        assertEquals(expected.mOneMatch, actual.mOneMatch);
+    private static boolean offsetResultEquals(OffsetResult expected, OffsetResult actual) {
+        return expected == actual
+                || (expected != null && actual != null
+                && Objects.equals(expected.getTimeZone().getID(), actual.getTimeZone().getID())
+                && expected.isOnlyMatch() == actual.isOnlyMatch());
     }
 
-    private static void assertZonesEqual(List<TimeZone> expected, List<TimeZone> actual) {
-        // TimeZone.equals() only checks the ID, but that's ok for these tests.
-        assertEquals(expected, actual);
-    }
-
-    private static TimeZone zone(String id) {
-        return TimeZone.getTimeZone(id);
+    /**
+     * Creates a list of default {@link TimeZoneMapping} objects with the specified time zone IDs.
+     */
+    private static TimeZoneMapping timeZoneMapping(String timeZoneId, Long notUsedAfterMillis) {
+        return TimeZoneMapping.createForTests(
+                        timeZoneId, true /* picker */, notUsedAfterMillis);
     }
 
     /**
@@ -727,7 +542,11 @@
                 .collect(Collectors.toList());
     }
 
-    private static List<TimeZone> zones(String... ids) {
-        return Arrays.stream(ids).map(TimeZone::getTimeZone).collect(Collectors.toList());
+    private static TimeZone zone(String id) {
+        return TimeZone.getFrozenTimeZone(id);
+    }
+
+    private static <X> List<X> list(X... xes) {
+        return Arrays.asList(xes);
     }
 }
diff --git a/luni/src/test/java/libcore/libcore/timezone/CountryZonesFinderTest.java b/luni/src/test/java/libcore/libcore/timezone/CountryZonesFinderTest.java
index 7fc2abf..ecd5201 100644
--- a/luni/src/test/java/libcore/libcore/timezone/CountryZonesFinderTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/CountryZonesFinderTest.java
@@ -33,16 +33,19 @@
 public class CountryZonesFinderTest {
 
     private static final CountryTimeZones GB_ZONES = CountryTimeZones.createValidated(
-            "gb", "Europe/London", true, timeZoneMappings("Europe/London"), "test");
+            "gb", "Europe/London", false /* defaultTimeZoneBoost */, true,
+            timeZoneMappings("Europe/London"), "test");
 
     private static final CountryTimeZones IM_ZONES = CountryTimeZones.createValidated(
-            "im", "Europe/London", true, timeZoneMappings("Europe/London"), "test");
+            "im", "Europe/London", false /* defaultTimeZoneBoost */, true,
+            timeZoneMappings("Europe/London"), "test");
 
     private static final CountryTimeZones FR_ZONES = CountryTimeZones.createValidated(
-            "fr", "Europe/Paris", true, timeZoneMappings("Europe/Paris"), "test");
+            "fr", "Europe/Paris", false /* defaultTimeZoneBoost */, true,
+            timeZoneMappings("Europe/Paris"), "test");
 
     private static final CountryTimeZones US_ZONES = CountryTimeZones.createValidated(
-            "us", "America/New_York", true,
+            "us", "America/New_York", false /* defaultTimeZoneBoost */, true,
             timeZoneMappings("America/New_York", "America/Los_Angeles"), "test");
 
     @Test
diff --git a/luni/src/test/java/libcore/libcore/timezone/TelephonyLookupTest.java b/luni/src/test/java/libcore/libcore/timezone/TelephonyLookupTest.java
new file mode 100644
index 0000000..8b4d867
--- /dev/null
+++ b/luni/src/test/java/libcore/libcore/timezone/TelephonyLookupTest.java
@@ -0,0 +1,367 @@
+/*
+ * 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 libcore.libcore.timezone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import libcore.timezone.TelephonyLookup;
+import libcore.timezone.TelephonyNetwork;
+import libcore.timezone.TelephonyNetworkFinder;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+public class TelephonyLookupTest {
+
+    private Path testDir;
+
+    @Before
+    public void setUp() throws Exception {
+        testDir = Files.createTempDirectory("TelephonyLookupTest");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // Delete the testDir and all contents.
+        Files.walkFileTree(testDir, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                    throws IOException {
+                Files.delete(file);
+                return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                    throws IOException {
+                Files.delete(dir);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    @Test
+    public void createInstanceWithFallback() throws Exception {
+        String validXml1 = "<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n";
+        TelephonyNetwork expectedTelephonyNetwork1 =
+                TelephonyNetwork.create("123", "456", "gb");
+
+        String validXml2 = "<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"234\" mnc=\"567\" country=\"fr\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n";
+        TelephonyNetwork expectedTelephonyNetwork2 =
+                TelephonyNetwork.create("234", "567", "fr");
+
+        String invalidXml = "<foo></foo>\n";
+        checkValidateThrowsParserException(invalidXml);
+
+        String validFile1 = createFile(validXml1);
+        String validFile2 = createFile(validXml2);
+        String invalidFile = createFile(invalidXml);
+        String missingFile = createMissingFile();
+
+        TelephonyLookup file1ThenFile2 =
+                TelephonyLookup.createInstanceWithFallback(validFile1, validFile2);
+        assertEquals(list(expectedTelephonyNetwork1),
+                file1ThenFile2.getTelephonyNetworkFinder().getAll());
+
+        TelephonyLookup missingFileThenFile1 =
+                TelephonyLookup.createInstanceWithFallback(missingFile, validFile1);
+        assertEquals(list(expectedTelephonyNetwork1),
+                missingFileThenFile1.getTelephonyNetworkFinder().getAll());
+
+        TelephonyLookup file2ThenFile1 =
+                TelephonyLookup.createInstanceWithFallback(validFile2, validFile1);
+        assertEquals(list(expectedTelephonyNetwork2),
+                file2ThenFile1.getTelephonyNetworkFinder().getAll());
+
+        // We assume the file has been validated so an invalid file is not checked ahead of time.
+        // We will find out when we look something up.
+        TelephonyLookup invalidThenValid =
+                TelephonyLookup.createInstanceWithFallback(invalidFile, validFile1);
+        assertNull(invalidThenValid.getTelephonyNetworkFinder());
+
+        // This is not a normal case: It would imply a device shipped without a file anywhere!
+        TelephonyLookup missingFiles =
+                TelephonyLookup.createInstanceWithFallback(missingFile, missingFile);
+        assertEmpty(missingFiles.getTelephonyNetworkFinder().getAll());
+    }
+
+    @Test
+    public void xmlParsing_emptyFile() throws Exception {
+        checkValidateThrowsParserException("");
+    }
+
+    @Test
+    public void xmlParsing_unexpectedRootElement() throws Exception {
+        checkValidateThrowsParserException("<foo></foo>\n");
+    }
+
+    @Test
+    public void xmlParsing_missingNetworks() throws Exception {
+        checkValidateThrowsParserException("<telephony_lookup></telephony_lookup>\n");
+    }
+
+    @Test
+    public void xmlParsing_emptyNetworksOk() throws Exception {
+        {
+            TelephonyLookup telephonyLookup =
+                    validate("<telephony_lookup>\n"
+                            + "  <networks>\n"
+                            + "  </networks>\n"
+                            + "</telephony_lookup>\n");
+            TelephonyNetworkFinder telephonyNetworkFinder = telephonyLookup
+                    .getTelephonyNetworkFinder();
+            assertEquals(list(), telephonyNetworkFinder.getAll());
+        }
+        {
+            TelephonyLookup telephonyLookup =
+                    validate("<telephony_lookup>\n"
+                            + "  <networks/>\n"
+                            + "</telephony_lookup>\n");
+            TelephonyNetworkFinder telephonyNetworkFinder = telephonyLookup
+                    .getTelephonyNetworkFinder();
+            assertEquals(list(), telephonyNetworkFinder.getAll());
+        }
+    }
+
+    @Test
+    public void xmlParsing_unexpectedComments() throws Exception {
+        TelephonyNetwork expectedTelephonyNetwork =
+                TelephonyNetwork.create("123", "456", "gb");
+
+        TelephonyLookup telephonyLookup = validate("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <!-- This is a comment -->"
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+        assertEquals(list(expectedTelephonyNetwork), telephonyLookup.getTelephonyNetworkFinder().getAll());
+    }
+
+    @Test
+    public void xmlParsing_unexpectedElementsIgnored() throws Exception {
+        TelephonyNetwork expectedTelephonyNetwork =
+                TelephonyNetwork.create("123", "456", "gb");
+        List<TelephonyNetwork> expectedNetworks = list(expectedTelephonyNetwork);
+
+        String unexpectedElement = "<unexpected-element>\n<a /></unexpected-element>\n";
+
+        // These tests are important because they ensure we can extend the format in future with
+        // more information but could continue using the same file on older devices.
+        TelephonyLookup telephonyLookup = validate("<telephony_lookup>\n"
+                + " " + unexpectedElement
+                + "  <networks>\n"
+                + "    " + unexpectedElement
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
+                + "    " + unexpectedElement
+                + "  </networks>\n"
+                + "  " + unexpectedElement
+                + "</telephony_lookup>\n");
+        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+
+        telephonyLookup = validate("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\">\n"
+                + "    " + unexpectedElement
+                + "    </network>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+
+        expectedNetworks = list(expectedTelephonyNetwork,
+                TelephonyNetwork.create("234", "567", "fr"));
+        telephonyLookup = validate("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
+                + "    " + unexpectedElement
+                + "    <network mcc=\"234\" mnc=\"567\" country=\"fr\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+    }
+
+    @Test
+    public void xmlParsing_unexpectedTextIgnored() throws Exception {
+        TelephonyNetwork expectedTelephonyNetwork =
+                TelephonyNetwork.create("123", "456", "gb");
+        List<TelephonyNetwork> expectedNetworks = list(expectedTelephonyNetwork);
+
+        String unexpectedText = "unexpected-text";
+        TelephonyLookup telephonyLookup = validate("<telephony_lookup>\n"
+                + "  " + unexpectedText
+                + "  <networks>\n"
+                + "  " + unexpectedText
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
+                + "    " + unexpectedText
+                + "  </networks>\n"
+                + "  " + unexpectedText
+                + "</telephony_lookup>\n");
+        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+
+        telephonyLookup = validate("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\">\n"
+                + "      " + unexpectedText
+                + "    </network>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+        assertEquals(expectedNetworks, telephonyLookup.getTelephonyNetworkFinder().getAll());
+    }
+
+    @Test
+    public void xmlParsing_truncatedInput() throws Exception {
+        checkValidateThrowsParserException("<telephony_lookup>\n");
+
+        checkValidateThrowsParserException("<telephony_lookup>\n"
+                + "  <networks>\n");
+
+        checkValidateThrowsParserException("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n");
+
+        checkValidateThrowsParserException("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
+                + "  </networks>\n");
+    }
+
+    @Test
+    public void validateDuplicateMccMnc() {
+        checkValidateThrowsParserException("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" countryCode=\"gb\"/>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" countryCode=\"fr\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+    }
+
+    @Test
+    public void validateCountryCodeLowerCase() {
+        checkValidateThrowsParserException("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" countryCode=\"GB\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+    }
+
+
+    @Test
+    public void getTelephonyNetworkFinder() throws Exception {
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceForTests(
+                "<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\" country=\"gb\"/>\n"
+                + "    <network mcc=\"234\" mnc=\"567\" country=\"fr\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+
+        TelephonyNetworkFinder telephonyNetworkFinder = telephonyLookup.getTelephonyNetworkFinder();
+        TelephonyNetwork expectedNetwork1 = TelephonyNetwork.create("123", "456", "gb");
+        TelephonyNetwork expectedNetwork2 = TelephonyNetwork.create("234", "567", "fr");
+        assertEquals(list(expectedNetwork1, expectedNetwork2), telephonyNetworkFinder.getAll());
+        assertEquals(expectedNetwork1, telephonyNetworkFinder.findNetworkByMccMnc("123", "456"));
+        assertEquals(expectedNetwork2, telephonyNetworkFinder.findNetworkByMccMnc("234", "567"));
+        assertNull(telephonyNetworkFinder.findNetworkByMccMnc("999", "999"));
+    }
+
+    @Test
+    public void xmlParsing_missingMccAttribute() throws Exception {
+        checkValidateThrowsParserException("<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mnc=\"456\" country=\"gb\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+    }
+
+    @Test
+    public void xmlParsing_missingMncAttribute() throws Exception {
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceForTests(
+                "<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" country=\"gb\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+        assertNull(telephonyLookup.getTelephonyNetworkFinder());
+    }
+
+    @Test
+    public void xmlParsing_missingCountryCodeAttribute() throws Exception {
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceForTests(
+                "<telephony_lookup>\n"
+                + "  <networks>\n"
+                + "    <network mcc=\"123\" mnc=\"456\"/>\n"
+                + "  </networks>\n"
+                + "</telephony_lookup>\n");
+        assertNull(telephonyLookup.getTelephonyNetworkFinder());
+    }
+
+    private static void checkValidateThrowsParserException(String xml) {
+        try {
+            validate(xml);
+            fail();
+        } catch (IOException expected) {
+        }
+    }
+
+    private static TelephonyLookup validate(String xml) throws IOException {
+        TelephonyLookup telephonyLookup = TelephonyLookup.createInstanceForTests(xml);
+        telephonyLookup.validate();
+        return telephonyLookup;
+    }
+
+    private static void assertEmpty(Collection<?> collection) {
+        assertTrue("Expected empty:" + collection, collection.isEmpty());
+    }
+
+    private static <X> List<X> list(X... values) {
+        return Arrays.asList(values);
+    }
+
+    private String createFile(String fileContent) throws IOException {
+        Path filePath = Files.createTempFile(testDir, null, null);
+        Files.write(filePath, fileContent.getBytes(StandardCharsets.UTF_8));
+        return filePath.toString();
+    }
+
+    private String createMissingFile() throws IOException {
+        Path filePath = Files.createTempFile(testDir, null, null);
+        Files.delete(filePath);
+        return filePath.toString();
+    }
+}
diff --git a/luni/src/test/java/libcore/libcore/timezone/TelephonyNetworkFinderTest.java b/luni/src/test/java/libcore/libcore/timezone/TelephonyNetworkFinderTest.java
new file mode 100644
index 0000000..44dfc81
--- /dev/null
+++ b/luni/src/test/java/libcore/libcore/timezone/TelephonyNetworkFinderTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 libcore.libcore.timezone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import libcore.timezone.TelephonyNetwork;
+import libcore.timezone.TelephonyNetworkFinder;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class TelephonyNetworkFinderTest {
+
+    @Test
+    public void testCreateAndLookups() {
+        TelephonyNetwork network = TelephonyNetwork.create("123", "456", "gb");
+        List<TelephonyNetwork> networkList = list(network);
+        TelephonyNetworkFinder finder = TelephonyNetworkFinder.create(networkList);
+        assertEquals(network, finder.findNetworkByMccMnc("123", "456"));
+        assertNull(finder.findNetworkByMccMnc("XXX", "XXX"));
+        assertNull(finder.findNetworkByMccMnc("123", "XXX"));
+        assertNull(finder.findNetworkByMccMnc("456", "123"));
+        assertNull(finder.findNetworkByMccMnc("111", "222"));
+        assertEquals(networkList, finder.getAll());
+    }
+
+    private static <X> List<X> list(X... values) {
+        return 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 e94b96e..a74ba30 100644
--- a/luni/src/test/java/libcore/libcore/timezone/TimeZoneDataFilesTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/TimeZoneDataFilesTest.java
@@ -27,31 +27,28 @@
 public class TimeZoneDataFilesTest {
 
     private static final String ANDROID_TZDATA_ROOT_ENV = "ANDROID_TZDATA_ROOT";
-    private static final String ANDROID_RUNTIME_ROOT_ENV = "ANDROID_RUNTIME_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_RUNTIME_ROOT_ENV));
+        assertNotNull(System.getenv(ANDROID_I18N_ROOT_ENV));
     }
 
     @Test
     public void getTimeZoneFilePaths() {
         String[] paths = TimeZoneDataFiles.getTimeZoneFilePaths("foo");
-        assertEquals(4, paths.length);
+        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"));
 
         assertTrue(paths[1].startsWith(System.getenv(ANDROID_TZDATA_ROOT_ENV)));
         assertTrue(paths[1].endsWith("/foo"));
-
-        assertTrue(paths[2].startsWith(System.getenv(ANDROID_RUNTIME_ROOT_ENV)));
-        assertTrue(paths[2].endsWith("/foo"));
-
-        assertTrue(paths[3].contains("/usr/share/zoneinfo/"));
-        assertTrue(paths[3].endsWith("/foo"));
     }
 
     // http://b/34867424
@@ -64,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];
@@ -72,7 +70,7 @@
 
         String runtimeModulePath = paths[2];
         assertTrue(runtimeModulePath + " invalid",
-                runtimeModulePath.startsWith(System.getenv(ANDROID_RUNTIME_ROOT_ENV)));
+                runtimeModulePath.startsWith(System.getenv(ANDROID_I18N_ROOT_ENV)));
         assertTrue(runtimeModulePath + " invalid", runtimeModulePath.contains("/etc/icu"));
     }
 }
diff --git a/luni/src/test/java/libcore/libcore/timezone/TimeZoneFinderTest.java b/luni/src/test/java/libcore/libcore/timezone/TimeZoneFinderTest.java
index 8bfacd8..ef07371 100644
--- a/luni/src/test/java/libcore/libcore/timezone/TimeZoneFinderTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/TimeZoneFinderTest.java
@@ -20,8 +20,6 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import android.icu.util.TimeZone;
-
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.FileVisitResult;
@@ -30,7 +28,6 @@
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 import java.util.stream.Collectors;
 import libcore.timezone.CountryTimeZones;
@@ -39,35 +36,13 @@
 import libcore.timezone.TimeZoneFinder;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 public class TimeZoneFinderTest {
 
-    private static final int HOUR_MILLIS = 60 * 60 * 1000;
-
-    // Zones used in the tests. NEW_YORK_TZ and LONDON_TZ chosen because they never overlap but both
-    // have DST.
-    private static final TimeZone NEW_YORK_TZ = TimeZone.getTimeZone("America/New_York");
-    private static final TimeZone LONDON_TZ = TimeZone.getTimeZone("Europe/London");
-    // A zone that matches LONDON_TZ for WHEN_NO_DST. It does not have DST so differs for WHEN_DST.
-    private static final TimeZone REYKJAVIK_TZ = TimeZone.getTimeZone("Atlantic/Reykjavik");
-    // Another zone that matches LONDON_TZ for WHEN_NO_DST. It does not have DST so differs for
-    // WHEN_DST.
-    private static final TimeZone UTC_TZ = TimeZone.getTimeZone("Etc/UTC");
-
-    // 22nd July 2017, 13:14:15 UTC (DST time in all the timezones used in these tests that observe
-    // DST).
-    private static final long WHEN_DST = 1500729255000L;
-    // 22nd January 2018, 13:14:15 UTC (non-DST time in all timezones used in these tests).
-    private static final long WHEN_NO_DST = 1516626855000L;
-
-    private static final int LONDON_DST_OFFSET_MILLIS = HOUR_MILLIS;
-    private static final int LONDON_NO_DST_OFFSET_MILLIS = 0;
-
-    private static final int NEW_YORK_DST_OFFSET_MILLIS = -4 * HOUR_MILLIS;
-    private static final int NEW_YORK_NO_DST_OFFSET_MILLIS = -5 * HOUR_MILLIS;
-
     private Path testDir;
 
     @Before
@@ -105,8 +80,8 @@
                 + "  </countryzones>\n"
                 + "</timezones>\n";
         CountryTimeZones expectedCountryTimeZones1 = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
 
         String validXml2 = "<timezones ianaversion=\"2017b\">\n"
                 + "  <countryzones>\n"
@@ -116,8 +91,8 @@
                 + "  </countryzones>\n"
                 + "</timezones>\n";
         CountryTimeZones expectedCountryTimeZones2 = CountryTimeZones.createValidated(
-                "gb", "Europe/Paris", false /* everUsesUtc */, timeZoneMappings("Europe/Paris"),
-                "test");
+                "gb", "Europe/Paris", false /* defaultTimeZoneBoost */, false /* everUsesUtc */,
+                timeZoneMappings("Europe/Paris"), "test");
 
         String invalidXml = "<foo></foo>\n";
         checkValidateThrowsParserException(invalidXml);
@@ -149,7 +124,7 @@
         assertNull(invalidThenValid.getIanaVersion());
         assertNull(invalidThenValid.lookupCountryTimeZones("gb"));
 
-        // This is not a normal case: It would imply a define shipped without a file in /system!
+        // This is not a normal case: It would imply a device shipped without a file anywhere!
         TimeZoneFinder missingFiles =
                 TimeZoneFinder.createInstanceWithFallback(missingFile, missingFile);
         assertNull(missingFiles.getIanaVersion());
@@ -182,8 +157,8 @@
     @Test
     public void xmlParsing_unexpectedComments() throws Exception {
         CountryTimeZones expectedCountryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
 
         TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
                 + "  <countryzones>\n"
@@ -210,8 +185,8 @@
     @Test
     public void xmlParsing_unexpectedElementsIgnored() throws Exception {
         CountryTimeZones expectedCountryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
 
         String unexpectedElement = "<unexpected-element>\n<a /></unexpected-element>\n";
         TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
@@ -267,7 +242,7 @@
         assertEquals(expectedCountryTimeZones, finder.lookupCountryTimeZones("gb"));
 
         expectedCountryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */,
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
                 timeZoneMappings("Europe/London", "Europe/Paris"), "test");
         finder = validate("<timezones ianaversion=\"2017b\">\n"
                 + "  <countryzones>\n"
@@ -284,8 +259,8 @@
     @Test
     public void xmlParsing_unexpectedTextIgnored() throws Exception {
         CountryTimeZones expectedCountryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
 
         String unexpectedText = "unexpected-text";
         TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
@@ -319,7 +294,7 @@
         assertEquals(expectedCountryTimeZones, finder.lookupCountryTimeZones("gb"));
 
         expectedCountryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */,
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
                 timeZoneMappings("Europe/London", "Europe/Paris"), "test");
         finder = validate("<timezones ianaversion=\"2017b\">\n"
                 + "  <countryzones>\n"
@@ -377,8 +352,8 @@
     @Test
     public void xmlParsing_unknownTimeZoneIdIgnored() throws Exception {
         CountryTimeZones expectedCountryTimeZones = CountryTimeZones.createValidated(
-                "gb", "Europe/London", true /* everUsesUtc */, timeZoneMappings("Europe/London"),
-                "test");
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
         TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
                 + "  <countryzones>\n"
                 + "    <country code=\"gb\" default=\"Europe/London\" everutc=\"y\">\n"
@@ -435,6 +410,32 @@
     }
 
     @Test
+    public void xmlParsing_badCountryDefaultBoost() throws Exception {
+        checkValidateThrowsParserException("<timezones ianaversion=\"2017b\">\n"
+                + "  <countryzones>\n"
+                + "    <country code=\"gb\" default=\"Europe/London\" defaultBoost=\"nope\""
+                + "everutc=\"y\">\n"
+                + "      <id>Europe/London</id>\n"
+                + "    </country>\n"
+                + "  </countryzones>\n"
+                + "</timezones>\n");
+    }
+
+    @Test
+    public void xmlParsing_countryDefaultBoost() throws Exception {
+        TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
+                + "  <countryzones>\n"
+                + "    <country code=\"gb\" default=\"Europe/London\" defaultBoost=\"y\""
+                + "everutc=\"y\">\n"
+                + "      <id>Europe/London</id>\n"
+                + "    </country>\n"
+                + "  </countryzones>\n"
+                + "</timezones>\n");
+        CountryTimeZones countryTimeZones = finder.lookupCountryTimeZones("gb");
+        assertTrue(countryTimeZones.isDefaultTimeZoneBoosted());
+    }
+
+    @Test
     public void xmlParsing_badTimeZoneMappingPicker() throws Exception {
         checkValidateThrowsParserException("<timezones ianaversion=\"2017b\">\n"
                 + "  <countryzones>\n"
@@ -509,16 +510,6 @@
     }
 
     @Test
-    public void xmlParsing_unknownCountryReturnsNull() throws Exception {
-        TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
-                + "  <countryzones>\n"
-                + "  </countryzones>\n"
-                + "</timezones>\n");
-        assertNull(finder.lookupTimeZoneIdsByCountry("gb"));
-        assertNull(finder.lookupTimeZonesByCountry("gb"));
-    }
-
-    @Test
     public void getCountryZonesFinder() throws Exception {
         TimeZoneFinder timeZoneFinder = TimeZoneFinder.createInstanceForTests(
                 "<timezones ianaversion=\"2017b\">\n"
@@ -531,10 +522,10 @@
                 + "    </country>\n"
                 + "  </countryzones>\n"
                 + "</timezones>\n");
-        CountryTimeZones expectedGb = CountryTimeZones.createValidated("gb", "Europe/London", true,
-                timeZoneMappings("Europe/London"), "test");
-        CountryTimeZones expectedFr = CountryTimeZones.createValidated("fr", "Europe/Paris", true,
-                timeZoneMappings("Europe/Paris"), "test");
+        CountryTimeZones expectedGb = CountryTimeZones.createValidated("gb", "Europe/London",
+                false /* defaultTimeZoneBoost */, true, timeZoneMappings("Europe/London"), "test");
+        CountryTimeZones expectedFr = CountryTimeZones.createValidated("fr", "Europe/Paris",
+                false /* defaultTimeZoneBoost */, true, timeZoneMappings("Europe/Paris"), "test");
         CountryZonesFinder countryZonesFinder = timeZoneFinder.getCountryZonesFinder();
         assertEquals(list("gb", "fr"), countryZonesFinder.lookupAllCountryIsoCodes());
         assertEquals(expectedGb, countryZonesFinder.lookupCountryTimeZones("gb"));
@@ -571,7 +562,7 @@
     }
 
     @Test
-    public void lookupTimeZonesByCountry_structuresAreImmutable() throws Exception {
+    public void lookupCountryTimeZones_caseInsensitive() throws Exception {
         TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
                 + "  <countryzones>\n"
                 + "    <country code=\"gb\" default=\"Europe/London\" everutc=\"y\">\n"
@@ -579,323 +570,22 @@
                 + "    </country>\n"
                 + "  </countryzones>\n"
                 + "</timezones>\n");
+        CountryTimeZones expectedCountryTimeZones = CountryTimeZones.createValidated(
+                "gb", "Europe/London", false /* defaultTimeZoneBoost */, true /* everUsesUtc */,
+                timeZoneMappings("Europe/London"), "test");
 
-        List<TimeZone> gbList = finder.lookupTimeZonesByCountry("gb");
-        assertEquals(1, gbList.size());
-        assertImmutableList(gbList);
-        assertImmutableTimeZone(gbList.get(0));
-
-        // Check country code normalization works too.
-        assertEquals(1, finder.lookupTimeZonesByCountry("GB").size());
-
-        assertNull(finder.lookupTimeZonesByCountry("unknown"));
+        assertEquals(expectedCountryTimeZones, finder.lookupCountryTimeZones("gb"));
+        assertEquals(expectedCountryTimeZones, finder.lookupCountryTimeZones("GB"));
+        assertEquals(expectedCountryTimeZones, finder.lookupCountryTimeZones("Gb"));
     }
 
     @Test
-    public void lookupTimeZoneIdsByCountry_structuresAreImmutable() throws Exception {
+    public void lookupCountryTimeZones_unknownCountryReturnsNull() throws Exception {
         TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
                 + "  <countryzones>\n"
-                + "    <country code=\"gb\" default=\"Europe/London\" everutc=\"y\">\n"
-                + "      <id>Europe/London</id>\n"
-                + "    </country>\n"
                 + "  </countryzones>\n"
                 + "</timezones>\n");
-
-        List<String> gbList = finder.lookupTimeZoneIdsByCountry("gb");
-        assertEquals(1, gbList.size());
-        assertImmutableList(gbList);
-
-        // Check country code normalization works too.
-        assertEquals(1, finder.lookupTimeZoneIdsByCountry("GB").size());
-
-        assertNull(finder.lookupTimeZoneIdsByCountry("unknown"));
-    }
-
-    @Test
-    public void lookupDefaultTimeZoneIdByCountry() throws Exception {
-        TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
-                + "  <countryzones>\n"
-                + "    <country code=\"gb\" default=\"Europe/London\" everutc=\"y\">\n"
-                + "      <id>Europe/London</id>\n"
-                + "    </country>\n"
-                + "  </countryzones>\n"
-                + "</timezones>\n");
-
-        assertEquals("Europe/London", finder.lookupDefaultTimeZoneIdByCountry("gb"));
-
-        // Check country code normalization works too.
-        assertEquals("Europe/London", finder.lookupDefaultTimeZoneIdByCountry("GB"));
-    }
-
-    /**
-     * At runtime we don't validate too much since there's nothing we can do if the data is
-     * incorrect.
-     */
-    @Test
-    public void lookupDefaultTimeZoneIdByCountry_notCountryTimeZoneButValid() throws Exception {
-        String xml = "<timezones ianaversion=\"2017b\">\n"
-                + "  <countryzones>\n"
-                + "    <country code=\"gb\" default=\"America/New_York\" everutc=\"y\">\n"
-                + "      <id>Europe/London</id>\n"
-                + "    </country>\n"
-                + "  </countryzones>\n"
-                + "</timezones>\n";
-        // validate() should fail because America/New_York is not one of the "gb" zones listed.
-        checkValidateThrowsParserException(xml);
-
-        // But it should still work at runtime.
-        TimeZoneFinder finder = TimeZoneFinder.createInstanceForTests(xml);
-        assertEquals("America/New_York", finder.lookupDefaultTimeZoneIdByCountry("gb"));
-    }
-
-    @Test
-    public void lookupDefaultTimeZoneIdByCountry_invalidDefault() throws Exception {
-        String xml = "<timezones ianaversion=\"2017b\">\n"
-                + "  <countryzones>\n"
-                + "    <country code=\"gb\" default=\"Moon/Tranquility_Base\" everutc=\"y\">\n"
-                + "      <id>Europe/London</id>\n"
-                + "      <id>Moon/Tranquility_Base</id>\n"
-                + "    </country>\n"
-                + "  </countryzones>\n"
-                + "</timezones>\n";
-        // validate() should pass because the IDs all match.
-        TimeZoneFinder finder = validate(xml);
-
-        // But "Moon/Tranquility_Base" is not a valid time zone ID so should not be used.
-        assertNull(finder.lookupDefaultTimeZoneIdByCountry("gb"));
-    }
-
-    @Test
-    public void lookupTimeZoneByCountryAndOffset_unknownCountry() throws Exception {
-        TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
-                + "  <countryzones>\n"
-                + "    <country code=\"xx\" default=\"Europe/London\" everutc=\"y\">\n"
-                + "      <id>Europe/London</id>\n"
-                + "    </country>\n"
-                + "  </countryzones>\n"
-                + "</timezones>\n");
-
-        // Demonstrate the arguments work for a known country.
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, null /* bias */));
-
-        // Check country code normalization works too.
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("XX", LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, null /* bias */));
-
-        // Test with an unknown country.
-        String unknownCountryCode = "yy";
-        assertNull(finder.lookupTimeZoneByCountryAndOffset(unknownCountryCode,
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */));
-
-        assertNull(finder.lookupTimeZoneByCountryAndOffset(unknownCountryCode,
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, LONDON_TZ /* bias */));
-    }
-
-    @Test
-    public void lookupTimeZoneByCountryAndOffset_oneCandidate() throws Exception {
-        TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
-                + "  <countryzones>\n"
-                + "    <country code=\"xx\" default=\"Europe/London\" everutc=\"y\">\n"
-                + "      <id>Europe/London</id>\n"
-                + "    </country>\n"
-                + "  </countryzones>\n"
-                + "</timezones>\n");
-
-        // The three parameters match the configured zone: offset, isDst and when.
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, null /* bias */));
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_NO_DST_OFFSET_MILLIS,
-                        false /* isDst */, WHEN_NO_DST, null /* bias */));
-
-        // Some lookup failure cases where the offset, isDst and when do not match the configured
-        // zone.
-        TimeZone noDstMatch1 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
-
-        TimeZone noDstMatch2 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch2);
-
-        TimeZone noDstMatch3 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_NO_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch3);
-
-        TimeZone noDstMatch4 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_NO_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch4);
-
-        TimeZone noDstMatch5 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_DST_OFFSET_MILLIS, false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch5);
-
-        TimeZone noDstMatch6 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch6);
-
-        // Some bias cases below.
-
-        // The bias is irrelevant here: it matches what would be returned anyway.
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, LONDON_TZ /* bias */));
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_NO_DST_OFFSET_MILLIS,
-                        false /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-        // A sample of a non-matching case with bias.
-        assertNull(finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_DST_OFFSET_MILLIS,
-                true /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-
-        // The bias should be ignored: it doesn't match any of the country's zones.
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, NEW_YORK_TZ /* bias */));
-
-        // The bias should still be ignored even though it matches the offset information given:
-        // it doesn't match any of the country's configured zones.
-        assertNull(finder.lookupTimeZoneByCountryAndOffset("xx", NEW_YORK_DST_OFFSET_MILLIS,
-                true /* isDst */, WHEN_DST, NEW_YORK_TZ /* bias */));
-    }
-
-    @Test
-    public void lookupTimeZoneByCountryAndOffset_multipleNonOverlappingCandidates()
-            throws Exception {
-        TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
-                + "  <countryzones>\n"
-                + "    <country code=\"xx\" default=\"Europe/London\" everutc=\"y\">\n"
-                + "      <id>America/New_York</id>\n"
-                + "      <id>Europe/London</id>\n"
-                + "    </country>\n"
-                + "  </countryzones>\n"
-                + "</timezones>\n");
-
-        // The three parameters match the configured zone: offset, isDst and when.
-        assertZoneEquals(LONDON_TZ, finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */));
-        assertZoneEquals(LONDON_TZ, finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, null /* bias */));
-        assertZoneEquals(NEW_YORK_TZ, finder.lookupTimeZoneByCountryAndOffset("xx",
-                NEW_YORK_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */));
-        assertZoneEquals(NEW_YORK_TZ, finder.lookupTimeZoneByCountryAndOffset("xx",
-                NEW_YORK_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, null /* bias */));
-
-        // Some lookup failure cases where the offset, isDst and when do not match the configured
-        // zone. This is a sample, not complete.
-        TimeZone noDstMatch1 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
-
-        TimeZone noDstMatch2 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_DST_OFFSET_MILLIS, false /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch2);
-
-        TimeZone noDstMatch3 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                NEW_YORK_NO_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch3);
-
-        TimeZone noDstMatch4 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                NEW_YORK_NO_DST_OFFSET_MILLIS, true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch4);
-
-        TimeZone noDstMatch5 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_DST_OFFSET_MILLIS, false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch5);
-
-        TimeZone noDstMatch6 = finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_NO_DST_OFFSET_MILLIS, false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch6);
-
-        // Some bias cases below.
-
-        // The bias is irrelevant here: it matches what would be returned anyway.
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, LONDON_TZ /* bias */));
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_NO_DST_OFFSET_MILLIS,
-                        false /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-        // A sample of a non-matching case with bias.
-        assertNull(finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_DST_OFFSET_MILLIS,
-                true /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-
-        // The bias should be ignored: it matches a configured zone, but the offset is wrong so
-        // should not be considered a match.
-        assertZoneEquals(LONDON_TZ,
-                finder.lookupTimeZoneByCountryAndOffset("xx", LONDON_DST_OFFSET_MILLIS,
-                        true /* isDst */, WHEN_DST, NEW_YORK_TZ /* bias */));
-    }
-
-    // This is an artificial case very similar to America/Denver and America/Phoenix in the US: both
-    // have the same offset for 6 months of the year but diverge. Australia/Lord_Howe too.
-    @Test
-    public void lookupTimeZoneByCountryAndOffset_multipleOverlappingCandidates() throws Exception {
-        // Three zones that have the same offset for some of the year. Europe/London changes
-        // offset WHEN_DST, the others do not.
-        TimeZoneFinder finder = validate("<timezones ianaversion=\"2017b\">\n"
-                + "  <countryzones>\n"
-                + "    <country code=\"xx\" default=\"Europe/London\" everutc=\"y\">\n"
-                + "      <id>Atlantic/Reykjavik</id>\n"
-                + "      <id>Europe/London</id>\n"
-                + "      <id>Etc/UTC</id>\n"
-                + "    </country>\n"
-                + "  </countryzones>\n"
-                + "</timezones>\n");
-
-        // This is the no-DST offset for LONDON_TZ, REYKJAVIK_TZ. UTC_TZ.
-        final int noDstOffset = LONDON_NO_DST_OFFSET_MILLIS;
-        // This is the DST offset for LONDON_TZ.
-        final int dstOffset = LONDON_DST_OFFSET_MILLIS;
-
-        // The three parameters match the configured zone: offset, isDst and when.
-        assertZoneEquals(LONDON_TZ, finder.lookupTimeZoneByCountryAndOffset("xx", dstOffset,
-                true /* isDst */, WHEN_DST, null /* bias */));
-        assertZoneEquals(REYKJAVIK_TZ, finder.lookupTimeZoneByCountryAndOffset("xx", noDstOffset,
-                false /* isDst */, WHEN_NO_DST, null /* bias */));
-        assertZoneEquals(LONDON_TZ, finder.lookupTimeZoneByCountryAndOffset("xx", dstOffset,
-                true /* isDst */, WHEN_DST, null /* bias */));
-        assertZoneEquals(REYKJAVIK_TZ, finder.lookupTimeZoneByCountryAndOffset("xx", noDstOffset,
-                false /* isDst */, WHEN_NO_DST, null /* bias */));
-        assertZoneEquals(REYKJAVIK_TZ, finder.lookupTimeZoneByCountryAndOffset("xx", noDstOffset,
-                false /* isDst */, WHEN_DST, null /* bias */));
-
-        // Some lookup failure cases where the offset, isDst and when do not match the configured
-        // zones.
-        TimeZone noDstMatch1 = finder.lookupTimeZoneByCountryAndOffset("xx", dstOffset,
-                true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch1);
-
-        TimeZone noDstMatch2 = finder.lookupTimeZoneByCountryAndOffset("xx", noDstOffset,
-                true /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch2);
-
-        TimeZone noDstMatch3 = finder.lookupTimeZoneByCountryAndOffset("xx", noDstOffset,
-                true /* isDst */, WHEN_NO_DST, null /* bias */);
-        assertNull(noDstMatch3);
-
-        TimeZone noDstMatch4 = finder.lookupTimeZoneByCountryAndOffset("xx", dstOffset,
-                false /* isDst */, WHEN_DST, null /* bias */);
-        assertNull(noDstMatch4);
-
-
-        // Some bias cases below.
-
-        // The bias is relevant here: it overrides what would be returned naturally.
-        assertZoneEquals(REYKJAVIK_TZ, finder.lookupTimeZoneByCountryAndOffset("xx", noDstOffset,
-                false /* isDst */, WHEN_NO_DST, null /* bias */));
-        assertZoneEquals(LONDON_TZ, finder.lookupTimeZoneByCountryAndOffset("xx", noDstOffset,
-                false /* isDst */, WHEN_NO_DST, LONDON_TZ /* bias */));
-        assertZoneEquals(UTC_TZ, finder.lookupTimeZoneByCountryAndOffset("xx", noDstOffset,
-                false /* isDst */, WHEN_NO_DST, UTC_TZ /* bias */));
-
-        // The bias should be ignored: it matches a configured zone, but the offset is wrong so
-        // should not be considered a match.
-        assertZoneEquals(LONDON_TZ, finder.lookupTimeZoneByCountryAndOffset("xx",
-                LONDON_DST_OFFSET_MILLIS, true /* isDst */, WHEN_DST, REYKJAVIK_TZ /* bias */));
+        assertNull(finder.lookupCountryTimeZones("gb"));
     }
 
     @Test
@@ -909,9 +599,9 @@
                 + "    </country>\n"
                 + "  </countryzones>\n"
                 + "</timezones>\n");
-        assertEquals(list("Europe/London"), finder.lookupTimeZoneIdsByCountry("gb"));
-
         assertNull(finder.getIanaVersion());
+
+        assertNotNull(finder.lookupCountryTimeZones("gb"));
     }
 
     @Test
@@ -925,27 +615,6 @@
         assertEquals(expectedIanaVersion, finder.getIanaVersion());
     }
 
-    private static void assertImmutableTimeZone(TimeZone timeZone) {
-        try {
-            timeZone.setRawOffset(1000);
-            fail();
-        } catch (UnsupportedOperationException expected) {
-        }
-    }
-
-    private static <X> void assertImmutableList(List<X> list) {
-        try {
-            list.add(null);
-            fail();
-        } catch (UnsupportedOperationException expected) {
-        }
-    }
-
-    private static void assertZoneEquals(TimeZone expected, TimeZone actual) {
-        // TimeZone.equals() only checks the ID, but that's ok for these tests.
-        assertEquals(expected, actual);
-    }
-
     private static void checkValidateThrowsParserException(String xml) {
         try {
             validate(xml);
@@ -974,11 +643,6 @@
         return Arrays.asList(values);
     }
 
-    private static <X> List<X> sort(Collection<X> value) {
-        return value.stream().sorted()
-                .collect(Collectors.toList());
-    }
-
     private String createFile(String fileContent) throws IOException {
         Path filePath = Files.createTempFile(testDir, null, null);
         Files.write(filePath, fileContent.getBytes(StandardCharsets.UTF_8));
diff --git a/luni/src/test/java/libcore/libcore/timezone/TzDataSetVersionTest.java b/luni/src/test/java/libcore/libcore/timezone/TzDataSetVersionTest.java
index 75e079b..a653301 100644
--- a/luni/src/test/java/libcore/libcore/timezone/TzDataSetVersionTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/TzDataSetVersionTest.java
@@ -55,10 +55,10 @@
 
     public void testConstructor() throws Exception {
         TzDataSetVersion distroVersion = new TzDataSetVersion(1, 2, VALID_RULES_VERSION, 3);
-        assertEquals(1, distroVersion.formatMajorVersion);
-        assertEquals(2, distroVersion.formatMinorVersion);
-        assertEquals(VALID_RULES_VERSION, distroVersion.rulesVersion);
-        assertEquals(3, distroVersion.revision);
+        assertEquals(1, distroVersion.getFormatMajorVersion());
+        assertEquals(2, distroVersion.getFormatMinorVersion());
+        assertEquals(VALID_RULES_VERSION, distroVersion.getRulesVersion());
+        assertEquals(3, distroVersion.getRevision());
     }
 
     public void testToFromBytesRoundTrip() throws Exception {
diff --git a/luni/src/test/java/libcore/libcore/timezone/ZoneInfoDBTest.java b/luni/src/test/java/libcore/libcore/timezone/ZoneInfoDbTest.java
similarity index 83%
rename from luni/src/test/java/libcore/libcore/timezone/ZoneInfoDBTest.java
rename to luni/src/test/java/libcore/libcore/timezone/ZoneInfoDbTest.java
index 3f4791c..48eb286 100644
--- a/luni/src/test/java/libcore/libcore/timezone/ZoneInfoDBTest.java
+++ b/luni/src/test/java/libcore/libcore/timezone/ZoneInfoDbTest.java
@@ -18,28 +18,27 @@
 
 import java.io.File;
 import java.io.FileOutputStream;
-import java.io.IOException;
 import java.io.RandomAccessFile;
 
 import libcore.timezone.TimeZoneDataFiles;
 import libcore.timezone.testing.ZoneInfoTestHelper;
 import libcore.util.ZoneInfo;
-import libcore.timezone.ZoneInfoDB;
+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 {
+public class ZoneInfoDbTest extends junit.framework.TestCase {
 
   // The base tzdata file, always present on a device.
-  private static final String SYSTEM_TZDATA_FILE =
-      TimeZoneDataFiles.getSystemTimeZoneFile(ZoneInfoDB.TZDATA_FILE);
+  private static final String TZDATA_FILE =
+          TimeZoneDataFiles.getTimeZoneModuleTzFile(ZoneInfoDb.TZDATA_FILE_NAME);
 
   // 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(SYSTEM_TZDATA_FILE);
-         ZoneInfoDB.TzData dataWithEmptyOverride =
-                 ZoneInfoDB.TzData.loadTzDataWithFallback(emptyFilePath, SYSTEM_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);
     }
@@ -48,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(SYSTEM_TZDATA_FILE);
-         ZoneInfoDB.TzData dataWithCorruptOverride =
-                 ZoneInfoDB.TzData.loadTzDataWithFallback(corruptFilePath, SYSTEM_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);
     }
@@ -59,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]);
@@ -68,7 +67,7 @@
 
   // Given a valid override file, we should find ourselves using that.
   public void testLoadTzDataWithFallback_goodOverrideFile() throws Exception {
-    RandomAccessFile in = new RandomAccessFile(SYSTEM_TZDATA_FILE, "r");
+    RandomAccessFile in = new RandomAccessFile(TZDATA_FILE, "r");
     byte[] content = new byte[(int) in.length()];
     in.readFully(content);
     in.close();
@@ -81,9 +80,9 @@
     content[10] = 'z';
 
     File goodFile = makeTemporaryFile(content);
-    try (ZoneInfoDB.TzData dataWithOverride =
-              ZoneInfoDB.TzData.loadTzDataWithFallback(goodFile.getPath(), SYSTEM_TZDATA_FILE);
-         ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(SYSTEM_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);
@@ -93,7 +92,7 @@
   }
 
   public void testLoadTzData_badHeader() throws Exception {
-    RandomAccessFile in = new RandomAccessFile(SYSTEM_TZDATA_FILE, "r");
+    RandomAccessFile in = new RandomAccessFile(TZDATA_FILE, "r");
     byte[] content = new byte[(int) in.length()];
     in.readFully(content);
     in.close();
@@ -107,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();
     }
@@ -150,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);
 
@@ -208,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();
     }
@@ -216,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(SYSTEM_TZDATA_FILE)) {
+    try (ZoneInfoDb data = ZoneInfoDb.loadTzData(TZDATA_FILE)) {
       String tzId = "Europe/London";
       ZoneInfo first = data.makeTimeZone(tzId);
       ZoneInfo second = data.makeTimeZone(tzId);
@@ -234,14 +233,14 @@
   }
 
   public void testMakeTimeZone_notFound() throws Exception {
-    try (ZoneInfoDB.TzData data = ZoneInfoDB.TzData.loadTzData(SYSTEM_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(SYSTEM_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/FP16Test.java b/luni/src/test/java/libcore/libcore/util/FP16Test.java
new file mode 100644
index 0000000..916df92
--- /dev/null
+++ b/luni/src/test/java/libcore/libcore/util/FP16Test.java
@@ -0,0 +1,400 @@
+/*
+ * 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 libcore.libcore.util;
+
+import static libcore.util.FP16.*;
+import libcore.util.FP16;
+
+import junit.framework.TestCase;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class FP16Test extends TestCase {
+
+    public void testSingleToHalf() {
+        // Zeroes, NaN and infinities
+        assertEquals(POSITIVE_ZERO, toHalf(0.0f));
+        assertEquals(NEGATIVE_ZERO, toHalf(-0.0f));
+        assertEquals(NaN, toHalf(Float.NaN));
+        assertEquals(POSITIVE_INFINITY, toHalf(Float.POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, toHalf(Float.NEGATIVE_INFINITY));
+        // Known values
+        assertEquals((short) 0x3c01, toHalf(1.0009765625f));
+        assertEquals((short) 0xc000, toHalf(-2.0f));
+        assertEquals((short) 0x0400, toHalf(6.10352e-5f));
+        assertEquals((short) 0x7bff, toHalf(65504.0f));
+        assertEquals((short) 0x3555, toHalf(1.0f / 3.0f));
+        // Subnormals
+        assertEquals((short) 0x03ff, toHalf(6.09756e-5f));
+        assertEquals(MIN_VALUE, toHalf(5.96046e-8f));
+        assertEquals((short) 0x83ff, toHalf(-6.09756e-5f));
+        assertEquals((short) 0x8001, toHalf(-5.96046e-8f));
+        // Subnormals (flushed to +/-0)
+        assertEquals(POSITIVE_ZERO, toHalf(5.96046e-9f));
+        assertEquals(NEGATIVE_ZERO, toHalf(-5.96046e-9f));
+        // Test for values that overflow the mantissa bits into exp bits
+        assertEquals((short) 0x1000, toHalf(Float.intBitsToFloat(0x39fff000)));
+        assertEquals((short) 0x0400, toHalf(Float.intBitsToFloat(0x387fe000)));
+        // Floats with absolute value above +/-65519 are rounded to +/-inf
+        // when using round-to-even
+        assertEquals((short) 0x7bff, toHalf(65519.0f));
+        assertEquals((short) 0x7bff, toHalf(65519.9f));
+        assertEquals(POSITIVE_INFINITY, toHalf(65520.0f));
+        assertEquals(NEGATIVE_INFINITY, toHalf(-65520.0f));
+        // Check if numbers are rounded to nearest even when they
+        // cannot be accurately represented by Half
+        assertEquals((short) 0x6800, toHalf(2049.0f));
+        assertEquals((short) 0x6c00, toHalf(4098.0f));
+        assertEquals((short) 0x7000, toHalf(8196.0f));
+        assertEquals((short) 0x7400, toHalf(16392.0f));
+        assertEquals((short) 0x7800, toHalf(32784.0f));
+    }
+
+    public void testHalfToSingle() {
+        // Zeroes, NaN and infinities
+        assertEquals(0.0f, toFloat(toHalf(0.0f)), 0.0f);
+        assertEquals(-0.0f, toFloat(toHalf(-0.0f)), 0.0f);
+        assertEquals(Float.NaN, toFloat(toHalf(Float.NaN)), 0.0f);
+        assertEquals(Float.POSITIVE_INFINITY, toFloat(toHalf(Float.POSITIVE_INFINITY)), 0.0f);
+        assertEquals(Float.NEGATIVE_INFINITY, toFloat(toHalf(Float.NEGATIVE_INFINITY)), 0.0f);
+        // Known values
+        assertEquals(1.0009765625f, toFloat(toHalf(1.0009765625f)), 0.0f);
+        assertEquals(-2.0f, toFloat(toHalf(-2.0f)), 0.0f);
+        assertEquals(6.1035156e-5f, toFloat(toHalf(6.10352e-5f)), 0.0f); // Inexact
+        assertEquals(65504.0f, toFloat(toHalf(65504.0f)), 0.0f);
+        assertEquals(0.33325195f, toFloat(toHalf(1.0f / 3.0f)), 0.0f); // Inexact
+        // Denormals (flushed to +/-0)
+        assertEquals(6.097555e-5f, toFloat(toHalf(6.09756e-5f)), 0.0f);
+        assertEquals(5.9604645e-8f, toFloat(toHalf(5.96046e-8f)), 0.0f);
+        assertEquals(-6.097555e-5f, toFloat(toHalf(-6.09756e-5f)), 0.0f);
+        assertEquals(-5.9604645e-8f, toFloat(toHalf(-5.96046e-8f)), 0.0f);
+    }
+
+    public void testHexString() {
+        assertEquals("NaN", toHexString(NaN));
+        assertEquals("Infinity", toHexString(POSITIVE_INFINITY));
+        assertEquals("-Infinity", toHexString(NEGATIVE_INFINITY));
+        assertEquals("0x0.0p0", toHexString(POSITIVE_ZERO));
+        assertEquals("-0x0.0p0", toHexString(NEGATIVE_ZERO));
+        assertEquals("0x1.0p0", toHexString(toHalf(1.0f)));
+        assertEquals("-0x1.0p0", toHexString(toHalf(-1.0f)));
+        assertEquals("0x1.0p1", toHexString(toHalf(2.0f)));
+        assertEquals("0x1.0p8", toHexString(toHalf(256.0f)));
+        assertEquals("0x1.0p-1", toHexString(toHalf(0.5f)));
+        assertEquals("0x1.0p-2", toHexString(toHalf(0.25f)));
+        assertEquals("0x1.3ffp15", toHexString(MAX_VALUE));
+        assertEquals("0x0.1p-14", toHexString(MIN_VALUE));
+        assertEquals("0x1.0p-14", toHexString(MIN_NORMAL));
+        assertEquals("-0x1.3ffp15", toHexString(LOWEST_VALUE));
+    }
+
+    public void testIsInfinite() {
+        assertTrue(FP16.isInfinite(POSITIVE_INFINITY));
+        assertTrue(FP16.isInfinite(NEGATIVE_INFINITY));
+        assertFalse(FP16.isInfinite(POSITIVE_ZERO));
+        assertFalse(FP16.isInfinite(NEGATIVE_ZERO));
+        assertFalse(FP16.isInfinite(NaN));
+        assertFalse(FP16.isInfinite(MAX_VALUE));
+        assertFalse(FP16.isInfinite(LOWEST_VALUE));
+        assertFalse(FP16.isInfinite(toHalf(-128.3f)));
+        assertFalse(FP16.isInfinite(toHalf(128.3f)));
+    }
+
+    public void testIsNaN() {
+        assertFalse(FP16.isNaN(POSITIVE_INFINITY));
+        assertFalse(FP16.isNaN(NEGATIVE_INFINITY));
+        assertFalse(FP16.isNaN(POSITIVE_ZERO));
+        assertFalse(FP16.isNaN(NEGATIVE_ZERO));
+        assertTrue(FP16.isNaN(NaN));
+        assertTrue(FP16.isNaN((short) 0x7c01));
+        assertTrue(FP16.isNaN((short) 0x7c18));
+        assertTrue(FP16.isNaN((short) 0xfc01));
+        assertTrue(FP16.isNaN((short) 0xfc98));
+        assertFalse(FP16.isNaN(MAX_VALUE));
+        assertFalse(FP16.isNaN(LOWEST_VALUE));
+        assertFalse(FP16.isNaN(toHalf(-128.3f)));
+        assertFalse(FP16.isNaN(toHalf(128.3f)));
+    }
+
+    public void testIsNormalized() {
+        assertFalse(FP16.isNormalized(POSITIVE_INFINITY));
+        assertFalse(FP16.isNormalized(NEGATIVE_INFINITY));
+        assertFalse(FP16.isNormalized(POSITIVE_ZERO));
+        assertFalse(FP16.isNormalized(NEGATIVE_ZERO));
+        assertFalse(FP16.isNormalized(NaN));
+        assertTrue(FP16.isNormalized(MAX_VALUE));
+        assertTrue(FP16.isNormalized(MIN_NORMAL));
+        assertTrue(FP16.isNormalized(LOWEST_VALUE));
+        assertTrue(FP16.isNormalized(toHalf(-128.3f)));
+        assertTrue(FP16.isNormalized(toHalf(128.3f)));
+        assertTrue(FP16.isNormalized(toHalf(0.3456f)));
+        assertFalse(FP16.isNormalized(MIN_VALUE));
+        assertFalse(FP16.isNormalized((short) 0x3ff));
+        assertFalse(FP16.isNormalized((short) 0x200));
+        assertFalse(FP16.isNormalized((short) 0x100));
+    }
+
+    public void testCeil() {
+        assertEquals(POSITIVE_INFINITY, FP16.ceil(POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, FP16.ceil(NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.ceil(POSITIVE_ZERO));
+        assertEquals(NEGATIVE_ZERO, FP16.ceil(NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.ceil(NaN));
+        assertEquals(LOWEST_VALUE, FP16.ceil(LOWEST_VALUE));
+        assertEquals(1.0f, toFloat(FP16.ceil(MIN_NORMAL)), 0.0f);
+        assertEquals(1.0f, toFloat(FP16.ceil((short) 0x3ff)), 0.0f);
+        assertEquals(1.0f, toFloat(FP16.ceil(toHalf(0.2f))), 0.0f);
+        assertEquals(NEGATIVE_ZERO, FP16.ceil(toHalf(-0.2f)));
+        assertEquals(1.0f, toFloat(FP16.ceil(toHalf(0.7f))), 0.0f);
+        assertEquals(NEGATIVE_ZERO, FP16.ceil(toHalf(-0.7f)));
+        assertEquals(125.0f, toFloat(FP16.ceil(toHalf(124.7f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.ceil(toHalf(-124.7f))), 0.0f);
+        assertEquals(125.0f, toFloat(FP16.ceil(toHalf(124.2f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.ceil(toHalf(-124.2f))), 0.0f);
+        // ceil for NaN values
+        // These tests check whether the current ceil implementation achieves
+        // bit level compatibility with the hardware implementation (ARM64)
+        assertEquals((short) 0x7e01, FP16.ceil((short) 0x7c01));
+        assertEquals((short) 0x7f00, FP16.ceil((short) 0x7d00));
+        assertEquals((short) 0xfe01, FP16.ceil((short) 0xfc01));
+        assertEquals((short) 0xff00, FP16.ceil((short) 0xfd00));
+    }
+
+    public void testEquals() {
+        assertTrue(FP16.equals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.equals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.equals(POSITIVE_ZERO, POSITIVE_ZERO));
+        assertTrue(FP16.equals(NEGATIVE_ZERO, NEGATIVE_ZERO));
+        assertTrue(FP16.equals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(FP16.equals(NaN, toHalf(12.4f)));
+        assertFalse(FP16.equals(toHalf(12.4f), NaN));
+        assertFalse(FP16.equals(NaN, NaN));
+        assertTrue(FP16.equals(toHalf(12.4f), toHalf(12.4f)));
+        assertTrue(FP16.equals(toHalf(-12.4f), toHalf(-12.4f)));
+        assertFalse(FP16.equals(toHalf(12.4f), toHalf(0.7f)));
+    }
+
+    public void testFloor() {
+        assertEquals(POSITIVE_INFINITY, FP16.floor(POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, FP16.floor(NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.floor(POSITIVE_ZERO));
+        assertEquals(NEGATIVE_ZERO, FP16.floor(NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.floor(NaN));
+        assertEquals(LOWEST_VALUE, FP16.floor(LOWEST_VALUE));
+        assertEquals(POSITIVE_ZERO, FP16.floor(MIN_NORMAL));
+        assertEquals(POSITIVE_ZERO, FP16.floor((short) 0x3ff));
+        assertEquals(POSITIVE_ZERO, FP16.floor(toHalf(0.2f)));
+        assertEquals(-1.0f, toFloat(FP16.floor(toHalf(-0.2f))), 0.0f);
+        assertEquals(-1.0f, toFloat(FP16.floor(toHalf(-0.7f))), 0.0f);
+        assertEquals(POSITIVE_ZERO, FP16.floor(toHalf(0.7f)));
+        assertEquals(124.0f, toFloat(FP16.floor(toHalf(124.7f))), 0.0f);
+        assertEquals(-125.0f, toFloat(FP16.floor(toHalf(-124.7f))), 0.0f);
+        assertEquals(124.0f, toFloat(FP16.floor(toHalf(124.2f))), 0.0f);
+        assertEquals(-125.0f, toFloat(FP16.floor(toHalf(-124.2f))), 0.0f);
+        // floor for NaN values
+        assertEquals((short) 0x7e01, FP16.floor((short) 0x7c01));
+        assertEquals((short) 0x7f00, FP16.floor((short) 0x7d00));
+        assertEquals((short) 0xfe01, FP16.floor((short) 0xfc01));
+        assertEquals((short) 0xff00, FP16.floor((short) 0xfd00));
+    }
+
+    public void testRint() {
+        assertEquals(POSITIVE_INFINITY, FP16.rint(POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, FP16.rint(NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.rint(POSITIVE_ZERO));
+        assertEquals(NEGATIVE_ZERO, FP16.rint(NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.rint(NaN));
+        assertEquals(LOWEST_VALUE, FP16.rint(LOWEST_VALUE));
+        assertEquals(POSITIVE_ZERO, FP16.rint(MIN_VALUE));
+        assertEquals(POSITIVE_ZERO, FP16.rint((short) 0x200));
+        assertEquals(POSITIVE_ZERO, FP16.rint((short) 0x3ff));
+        assertEquals(POSITIVE_ZERO, FP16.rint(toHalf(0.2f)));
+        assertEquals(NEGATIVE_ZERO, FP16.rint(toHalf(-0.2f)));
+        assertEquals(1.0f, toFloat(FP16.rint(toHalf(0.7f))), 0.0f);
+        assertEquals(-1.0f, toFloat(FP16.rint(toHalf(-0.7f))), 0.0f);
+        assertEquals(0.0f, toFloat(FP16.rint(toHalf(0.5f))), 0.0f);
+        assertEquals(-0.0f, toFloat(FP16.rint(toHalf(-0.5f))), 0.0f);
+        assertEquals(2.0f, toFloat(FP16.rint(toHalf(1.5f))), 0.0f);
+        assertEquals(-2.0f, toFloat(FP16.rint(toHalf(-1.5f))), 0.0f);
+        assertEquals(1022.0f, toFloat(FP16.rint(toHalf(1022.5f))), 0.0f);
+        assertEquals(-1022.0f, toFloat(FP16.rint(toHalf(-1022.5f))), 0.0f);
+        assertEquals(125.0f, toFloat(FP16.rint(toHalf(124.7f))), 0.0f);
+        assertEquals(-125.0f, toFloat(FP16.rint(toHalf(-124.7f))), 0.0f);
+        assertEquals(124.0f, toFloat(FP16.rint(toHalf(124.2f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.rint(toHalf(-124.2f))), 0.0f);
+        // round for NaN values
+        // These tests check whether the current rint implementation achieves
+        // bit level compatibility with the hardware implementation (ARM64)
+        assertEquals((short) 0x7e01, FP16.rint((short) 0x7c01));
+        assertEquals((short) 0x7f00, FP16.rint((short) 0x7d00));
+        assertEquals((short) 0xfe01, FP16.rint((short) 0xfc01));
+        assertEquals((short) 0xff00, FP16.rint((short) 0xfd00));
+    }
+
+    public void testTrunc() {
+        assertEquals(POSITIVE_INFINITY, FP16.trunc(POSITIVE_INFINITY));
+        assertEquals(NEGATIVE_INFINITY, FP16.trunc(NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.trunc(POSITIVE_ZERO));
+        assertEquals(NEGATIVE_ZERO, FP16.trunc(NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.trunc(NaN));
+        assertEquals(LOWEST_VALUE, FP16.trunc(LOWEST_VALUE));
+        assertEquals(POSITIVE_ZERO, FP16.trunc(toHalf(0.2f)));
+        assertEquals(NEGATIVE_ZERO, FP16.trunc(toHalf(-0.2f)));
+        assertEquals(0.0f, toFloat(FP16.trunc(toHalf(0.7f))), 0.0f);
+        assertEquals(-0.0f, toFloat(FP16.trunc(toHalf(-0.7f))), 0.0f);
+        assertEquals(124.0f, toFloat(FP16.trunc(toHalf(124.7f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.trunc(toHalf(-124.7f))), 0.0f);
+        assertEquals(124.0f, toFloat(FP16.trunc(toHalf(124.2f))), 0.0f);
+        assertEquals(-124.0f, toFloat(FP16.trunc(toHalf(-124.2f))), 0.0f);
+    }
+
+    public void testLess() {
+        assertTrue(FP16.less(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.less(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(FP16.less(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(FP16.less(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(FP16.less(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertFalse(FP16.less(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(FP16.less(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(FP16.less(NaN, toHalf(12.3f)));
+        assertFalse(FP16.less(toHalf(12.3f), NaN));
+        assertTrue(FP16.less(MIN_VALUE, MIN_NORMAL));
+        assertFalse(FP16.less(MIN_NORMAL, MIN_VALUE));
+        assertTrue(FP16.less(toHalf(12.3f), toHalf(12.4f)));
+        assertFalse(FP16.less(toHalf(12.4f), toHalf(12.3f)));
+        assertFalse(FP16.less(toHalf(-12.3f), toHalf(-12.4f)));
+        assertTrue(FP16.less(toHalf(-12.4f), toHalf(-12.3f)));
+        assertTrue(FP16.less(MIN_VALUE, (short) 0x3ff));
+    }
+
+    public void testLessEquals() {
+        assertTrue(FP16.lessEquals(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.lessEquals(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(FP16.lessEquals(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(FP16.lessEquals(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(FP16.lessEquals(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(FP16.lessEquals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertTrue(FP16.lessEquals(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(FP16.lessEquals(NaN, toHalf(12.3f)));
+        assertFalse(FP16.lessEquals(toHalf(12.3f), NaN));
+        assertTrue(FP16.lessEquals(MIN_VALUE, MIN_NORMAL));
+        assertFalse(FP16.lessEquals(MIN_NORMAL, MIN_VALUE));
+        assertTrue(FP16.lessEquals(toHalf(12.3f), toHalf(12.4f)));
+        assertFalse(FP16.lessEquals(toHalf(12.4f), toHalf(12.3f)));
+        assertFalse(FP16.lessEquals(toHalf(-12.3f), toHalf(-12.4f)));
+        assertTrue(FP16.lessEquals(toHalf(-12.4f), toHalf(-12.3f)));
+        assertTrue(FP16.lessEquals(MIN_VALUE, (short) 0x3ff));
+        assertTrue(FP16.lessEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.lessEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.lessEquals(toHalf(12.12356f), toHalf(12.12356f)));
+        assertTrue(FP16.lessEquals(toHalf(-12.12356f), toHalf(-12.12356f)));
+    }
+
+    public void testGreater() {
+        assertTrue(FP16.greater(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.greater(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(FP16.greater(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(FP16.greater(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(FP16.greater(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertFalse(FP16.greater(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertFalse(FP16.greater(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(FP16.greater(toHalf(12.3f), NaN));
+        assertFalse(FP16.greater(NaN, toHalf(12.3f)));
+        assertTrue(FP16.greater(MIN_NORMAL, MIN_VALUE));
+        assertFalse(FP16.greater(MIN_VALUE, MIN_NORMAL));
+        assertTrue(FP16.greater(toHalf(12.4f), toHalf(12.3f)));
+        assertFalse(FP16.greater(toHalf(12.3f), toHalf(12.4f)));
+        assertFalse(FP16.greater(toHalf(-12.4f), toHalf(-12.3f)));
+        assertTrue(FP16.greater(toHalf(-12.3f), toHalf(-12.4f)));
+        assertTrue(FP16.greater((short) 0x3ff, MIN_VALUE));
+    }
+
+    public void testGreaterEquals() {
+        assertTrue(FP16.greaterEquals(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.greaterEquals(POSITIVE_INFINITY, MAX_VALUE));
+        assertFalse(FP16.greaterEquals(MAX_VALUE, POSITIVE_INFINITY));
+        assertFalse(FP16.greaterEquals(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertTrue(FP16.greaterEquals(LOWEST_VALUE, NEGATIVE_INFINITY));
+        assertTrue(FP16.greaterEquals(NEGATIVE_ZERO, POSITIVE_ZERO));
+        assertTrue(FP16.greaterEquals(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertFalse(FP16.greaterEquals(toHalf(12.3f), NaN));
+        assertFalse(FP16.greaterEquals(NaN, toHalf(12.3f)));
+        assertTrue(FP16.greaterEquals(MIN_NORMAL, MIN_VALUE));
+        assertFalse(FP16.greaterEquals(MIN_VALUE, MIN_NORMAL));
+        assertTrue(FP16.greaterEquals(toHalf(12.4f), toHalf(12.3f)));
+        assertFalse(FP16.greaterEquals(toHalf(12.3f), toHalf(12.4f)));
+        assertFalse(FP16.greaterEquals(toHalf(-12.4f), toHalf(-12.3f)));
+        assertTrue(FP16.greaterEquals(toHalf(-12.3f), toHalf(-12.4f)));
+        assertTrue(FP16.greaterEquals((short) 0x3ff, MIN_VALUE));
+        assertTrue(FP16.greaterEquals(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertTrue(FP16.greaterEquals(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertTrue(FP16.greaterEquals(toHalf(12.12356f), toHalf(12.12356f)));
+        assertTrue(FP16.greaterEquals(toHalf(-12.12356f), toHalf(-12.12356f)));
+    }
+
+    public void testMin() {
+        assertEquals(NEGATIVE_INFINITY, FP16.min(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertEquals(NEGATIVE_ZERO, FP16.min(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.min(NaN, LOWEST_VALUE));
+        assertEquals(NaN, FP16.min(LOWEST_VALUE, NaN));
+        assertEquals(NEGATIVE_INFINITY, FP16.min(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertEquals(MAX_VALUE, FP16.min(POSITIVE_INFINITY, MAX_VALUE));
+        assertEquals(MIN_VALUE, FP16.min(MIN_VALUE, MIN_NORMAL));
+        assertEquals(POSITIVE_ZERO, FP16.min(MIN_VALUE, POSITIVE_ZERO));
+        assertEquals(POSITIVE_ZERO, FP16.min(MIN_NORMAL, POSITIVE_ZERO));
+        assertEquals(toHalf(-3.456f), FP16.min(toHalf(-3.456f), toHalf(-3.453f)));
+        assertEquals(toHalf(3.453f), FP16.min(toHalf(3.456f), toHalf(3.453f)));
+    }
+
+    public void testMax() {
+        assertEquals(POSITIVE_INFINITY, FP16.max(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertEquals(POSITIVE_ZERO, FP16.max(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertEquals(NaN, FP16.max(NaN, MAX_VALUE));
+        assertEquals(NaN, FP16.max(MAX_VALUE, NaN));
+        assertEquals(LOWEST_VALUE, FP16.max(NEGATIVE_INFINITY, LOWEST_VALUE));
+        assertEquals(POSITIVE_INFINITY, FP16.max(POSITIVE_INFINITY, MAX_VALUE));
+        assertEquals(MIN_NORMAL, FP16.max(MIN_VALUE, MIN_NORMAL));
+        assertEquals(MIN_VALUE, FP16.max(MIN_VALUE, POSITIVE_ZERO));
+        assertEquals(MIN_NORMAL, FP16.max(MIN_NORMAL, POSITIVE_ZERO));
+        assertEquals(toHalf(-3.453f), FP16.max(toHalf(-3.456f), toHalf(-3.453f)));
+        assertEquals(toHalf(3.456f), FP16.max(toHalf(3.456f), toHalf(3.453f)));
+    }
+
+    public void testCompare() {
+        assertEquals(0, FP16.compare(NaN, NaN));
+        assertEquals(0, FP16.compare(NaN, (short) 0xfc98));
+        assertEquals(1, FP16.compare(NaN, POSITIVE_INFINITY));
+        assertEquals(-1, FP16.compare(POSITIVE_INFINITY, NaN));
+
+        assertEquals(0, FP16.compare(POSITIVE_INFINITY, POSITIVE_INFINITY));
+        assertEquals(0, FP16.compare(NEGATIVE_INFINITY, NEGATIVE_INFINITY));
+        assertEquals(1, FP16.compare(POSITIVE_INFINITY, NEGATIVE_INFINITY));
+        assertEquals(-1, FP16.compare(NEGATIVE_INFINITY, POSITIVE_INFINITY));
+
+        assertEquals(0, FP16.compare(POSITIVE_ZERO, POSITIVE_ZERO));
+        assertEquals(0, FP16.compare(NEGATIVE_ZERO, NEGATIVE_ZERO));
+        assertEquals(1, FP16.compare(POSITIVE_ZERO, NEGATIVE_ZERO));
+        assertEquals(-1, FP16.compare(NEGATIVE_ZERO, POSITIVE_ZERO));
+
+        assertEquals(0, FP16.compare(toHalf(12.462f), toHalf(12.462f)));
+        assertEquals(0, FP16.compare(toHalf(-12.462f), toHalf(-12.462f)));
+        assertEquals(1, FP16.compare(toHalf(12.462f), toHalf(-12.462f)));
+        assertEquals(-1, FP16.compare(toHalf(-12.462f), toHalf(12.462f)));
+    }
+}
diff --git a/luni/src/test/java/libcore/libcore/util/HexEncodingTest.java b/luni/src/test/java/libcore/libcore/util/HexEncodingTest.java
index 4de1a01..800928f 100644
--- a/luni/src/test/java/libcore/libcore/util/HexEncodingTest.java
+++ b/luni/src/test/java/libcore/libcore/util/HexEncodingTest.java
@@ -18,28 +18,69 @@
 
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.Locale;
+
 import junit.framework.TestCase;
 import static libcore.util.HexEncoding.decode;
 import static libcore.util.HexEncoding.encode;
+import static libcore.util.HexEncoding.encodeToString;
 
 public class HexEncodingTest extends TestCase {
-  public void testEncode() {
-    final byte[] avocados = "avocados".getBytes(StandardCharsets.UTF_8);
 
-    assertArraysEqual("61766F6361646F73".toCharArray(), encode(avocados));
-    assertArraysEqual(avocados, decode(encode(avocados), false));
-    // Make sure we can handle lower case hex encodings as well.
-    assertArraysEqual(avocados, decode("61766f6361646f73".toCharArray(), false));
+  public void testEncodeByte() {
+    Object[][] testCases = new Object[][] {
+        { 0x01, "01" },
+        { 0x09, "09" },
+        { 0x0A, "0A" },
+        { 0x0F, "0F" },
+        { 0x10, "10" },
+        { 0x1F, "1F" },
+        { 0x20, "20" },
+        { 0x7F, "7F" },
+        { 0x80, "80" },
+        { 0xFF, "FF" },
+    };
+    for (Object[] testCase : testCases) {
+      Number toEncode = (Number) testCase[0];
+      String expected = (String) testCase[1];
+
+      String actualUpper = encodeToString(toEncode.byteValue(), true /* upperCase */);
+      assertEquals(upper(expected), actualUpper);
+
+      String actualLower = encodeToString(toEncode.byteValue(), false /* upperCase */);
+      assertEquals(lower(expected), actualLower);
+    }
+  }
+
+  public void testEncodeBytes() {
+    Object[][] testCases = new Object[][] {
+        { "avocados".getBytes(StandardCharsets.UTF_8), "61766F6361646F73" },
+    };
+
+    for (Object[] testCase : testCases) {
+      byte[] bytes = (byte[]) testCase[0];
+      String encodedLower = lower((String) testCase[1]);
+      String encodedUpper = upper((String) testCase[1]);
+
+      assertArraysEqual(encodedUpper.toCharArray(), encode(bytes));
+      assertArraysEqual(encodedUpper.toCharArray(), encode(bytes, true /* upperCase */));
+      assertArraysEqual(encodedLower.toCharArray(), encode(bytes, false /* upperCase */));
+
+      assertArraysEqual(bytes, decode(encode(bytes), false /* allowSingleChar */));
+
+      // Make sure we can handle lower case hex encodings as well.
+      assertArraysEqual(bytes, decode(encodedLower.toCharArray(), false /* allowSingleChar */));
+    }
   }
 
   public void testDecode_allow4Bit() {
     assertArraysEqual(new byte[] { 6 }, decode("6".toCharArray(), true));
-    assertArraysEqual(new byte[] { 6, 'v' }, decode("676".toCharArray(), true));
+    assertArraysEqual(new byte[] { 6, 0x76 }, decode("676".toCharArray(), true));
   }
 
   public void testDecode_disallow4Bit() {
     try {
-      decode("676".toCharArray(), false);
+      decode("676".toCharArray(), false /* allowSingleChar */);
       fail();
     } catch (IllegalArgumentException expected) {
     }
@@ -47,7 +88,7 @@
 
   public void testDecode_invalid() {
     try {
-      decode("DEADBARD".toCharArray(), false);
+      decode("DEADBARD".toCharArray(), false /* allowSingleChar */);
       fail();
     } catch (IllegalArgumentException expected) {
     }
@@ -56,13 +97,13 @@
     // commons uses Character.isDigit and would successfully decode a string with
     // arabic and devanagari characters.
     try {
-      decode("६१٧٥٥F6361646F73".toCharArray(), false);
+      decode("६१٧٥٥F6361646F73".toCharArray(), false /* allowSingleChar */);
       fail();
     } catch (IllegalArgumentException expected) {
     }
 
     try {
-      decode("#%6361646F73".toCharArray(), false);
+      decode("#%6361646F73".toCharArray(), false /* allowSingleChar */);
       fail();
     } catch (IllegalArgumentException expected) {
     }
@@ -75,4 +116,12 @@
   private static void assertArraysEqual(byte[] lhs, byte[] rhs) {
     assertEquals(Arrays.toString(lhs), Arrays.toString(rhs));
   }
+
+  private static String lower(String string) {
+    return string.toLowerCase(Locale.ROOT);
+  }
+
+  private static String upper(String string) {
+    return string.toUpperCase(Locale.ROOT);
+  }
 }
diff --git a/luni/src/test/java/libcore/libcore/util/NativeAllocationRegistryTest.java b/luni/src/test/java/libcore/libcore/util/NativeAllocationRegistryTest.java
index 64128da..54c8876 100644
--- a/luni/src/test/java/libcore/libcore/util/NativeAllocationRegistryTest.java
+++ b/luni/src/test/java/libcore/libcore/util/NativeAllocationRegistryTest.java
@@ -56,15 +56,18 @@
             return;
         }
         Runtime.getRuntime().gc();
+        System.runFinalization();
+        long nativeBytes = getNumNativeBytesAllocated();
+        assertEquals("Native bytes already allocated", 0, nativeBytes);
         long max = Runtime.getRuntime().maxMemory();
         long total = Runtime.getRuntime().totalMemory();
         int size = 1024*1024;
-        int expectedMaxNumAllocations = (int)(max-total)/size;
+        final int nativeSize = size/2;
+        int javaSize = size/2;
+        int expectedMaxNumAllocations = (int)(max-total)/javaSize;
         int numSavedAllocations = expectedMaxNumAllocations/2;
         Allocation[] saved = new Allocation[numSavedAllocations];
 
-        final int nativeSize = size/2;
-        int javaSize = size/2;
         NativeAllocationRegistry registry = null;
         int numAllocationsToSimulate = 10 * expectedMaxNumAllocations;
 
@@ -93,10 +96,23 @@
         // Verify most of the allocations have been freed.
         // Since we use fairly large Java objects, this doesn't test the GC triggering
         // effect; we do that elsewhere.
-        long nativeBytes = getNumNativeBytesAllocated();
-        long nativeReachableBytes = numSavedAllocations * nativeSize;
+        // Since native and java objects have the same size, and we can only have max
+        // Java bytes in use, there should be no more than max native bytes in use,
+        // once all enqueued deallocations have been processed. First make sure
+        // that the ReferenceQueueDaemon has processed all pending requests, and then
+        // check.
+        System.runFinalization();
+        nativeBytes = getNumNativeBytesAllocated();
         assertTrue("Excessive native bytes still allocated (" + nativeBytes + ")"
-                + " given max memory of (" + max + ")", nativeBytes < 2 * max);
+                + " given max memory of (" + max + ")", nativeBytes <= max);
+        // Check that the array is fully populated, and sufficiently many native bytes
+        // are live.
+        long nativeReachableBytes = numSavedAllocations * nativeSize;
+        for (int i = 0; i < numSavedAllocations; i++) {
+            assertNotNull(saved[i]);
+            assertNotNull(saved[i].javaAllocation);
+            assertTrue(saved[i].nativeAllocation != 0);
+        }
         assertTrue("Too few native bytes still allocated (" + nativeBytes + "); "
                 + nativeReachableBytes + " bytes are reachable",
                 nativeBytes >= nativeReachableBytes);
diff --git a/luni/src/test/java/libcore/libcore/util/ZoneInfoTest.java b/luni/src/test/java/libcore/libcore/util/ZoneInfoTest.java
index cddf41b..8b9715f 100644
--- a/luni/src/test/java/libcore/libcore/util/ZoneInfoTest.java
+++ b/luni/src/test/java/libcore/libcore/util/ZoneInfoTest.java
@@ -26,7 +26,7 @@
 import java.util.Arrays;
 import java.util.Date;
 import libcore.io.BufferIterator;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
 import libcore.timezone.testing.ZoneInfoTestHelper;
 import libcore.util.ZoneInfo;
 
@@ -39,7 +39,7 @@
    * Checks that a {@link ZoneInfo} cannot be created without any types.
    */
   public void testMakeTimeZone_NoTypes() throws Exception {
-    int[][] transitions = {};
+    long[][] transitions = {};
     int[][] types = {};
     try {
       createZoneInfo(transitions, types);
@@ -52,7 +52,7 @@
    * Checks that a {@link ZoneInfo} can be created with one type and no transitions.
    */
   public void testMakeTimeZone_OneType_NoTransitions() throws Exception {
-    int[][] transitions = {};
+    long[][] transitions = {};
     int[][] types = {
         { 4800, 0 }
     };
@@ -78,7 +78,7 @@
    * Checks that a {@link ZoneInfo} can be created with one non-DST transition.
    */
   public void testReadTimeZone_OneNonDstTransition() throws Exception {
-    int[][] transitions = {
+    long[][] transitions = {
         { 0, 0 }
     };
     int[][] types = {
@@ -102,7 +102,7 @@
    * Checks that a {@link ZoneInfo} cannot be created with one DST but no non-DSTs transitions.
    */
   public void testReadTimeZone_OneDstTransition() throws Exception {
-    int[][] transitions = {
+    long[][] transitions = {
         { 0, 0 }
     };
     int[][] types = {
@@ -120,7 +120,7 @@
    * around the boundary of negative transitions.
    */
   public void testReadTimeZone_NegativeTransition() throws Exception {
-    int[][] transitions = {
+    long[][] transitions = {
         { -2000, 0 },
         { -5, 1 },
         { 0, 2 },
@@ -157,7 +157,7 @@
    * around the boundary of positive transitions.
    */
   public void testReadTimeZone_PositiveTransition() throws Exception {
-    int[][] transitions = {
+    long[][] transitions = {
         { 0, 0 },
         { 5, 1 },
         { 2000, 2 },
@@ -195,7 +195,7 @@
    * transitions where the transition times are negative is not affected by rounding issues.
    */
   public void testReadTimeZone_HasFutureDST_NoPastDST_NegativeTransitions() throws Exception {
-    int[][] transitions = {
+    long[][] transitions = {
         { -2000, 0 },
         { -500, 1 },
         { -100, 2 },
@@ -228,7 +228,7 @@
    * transitions where the transition times are positive is not affected by rounding issues.
    */
   public void testReadTimeZone_HasFutureDST_NoPastDST_PositiveTransitions() throws Exception {
-    int[][] transitions = {
+    long[][] transitions = {
         { 4000, 0 },
         { 5500, 1 },
         { 6000, 2 },
@@ -261,7 +261,7 @@
    * transitions where the transition times are negative is not affected by rounding issues.
    */
   public void testReadTimeZone_HasPastDST_NoFutureDST_NegativeTransitions() throws Exception {
-    int[][] transitions = {
+    long[][] transitions = {
         { -5000, 0 },
         { -2000, 1 },
         { -500, 0 },
@@ -290,7 +290,7 @@
    * transitions where the transition times are positive is not affected by rounding issues.
    */
   public void testReadTimeZone_HasPastDST_NoFutureDST_PositiveTransitions() throws Exception {
-    int[][] transitions = {
+    long[][] transitions = {
         { 1000, 0 },
         { 4000, 1 },
         { 5500, 0 },
@@ -315,24 +315,17 @@
   }
 
   /**
-   * TimeZone APIs use long times in millis. Android uses TZif version 1 format data which
-   * uses 32-bit time values for transitions so it only gives accurate results for times in that
-   * range.
+   * TimeZone APIs use Java long times in millis.
    *
-   * <p>Newer versions of zic after 2014b introduce an explicit transition at the earliest
-   * representable time, which is Integer.MIN_VALUE for TZif version 1 files. Previously the type
-   * used was left implicit and readers were expected to use the first non-DST type in the file.
-   * This extra transition mostly went away again with zic 2018f.
-   *
-   * <p>Testing newer zic versions demonstrated that Android had been mishandling the lookup of
-   * offset for times before the first transition. The logic has been corrected. This test would
-   * fail on versions of Android <= P.
+   * <p>Android has historically mishandled the lookup of offset for times before Integer.MIN_VALUE
+   * seconds for various reasons. The logic has been corrected. This test would fail on versions of
+   * Android <= P.
    */
   public void testReadTimeZone_Bug118835133_extraFirstTransition() throws Exception {
-    // A time before the first representable time in a TZif version 1 file.
+    // A time before the first representable time in seconds with a java int.
     Instant before32BitTime = timeFromSeconds(Integer.MIN_VALUE).minusMillis(1);
 
-    // Times between the start of the 32-bit time range and the first "official" transition.
+    // Times around the 32-bit seconds minimum.
     Instant[] earlyTimes = {
             timeFromSeconds(Integer.MIN_VALUE),
             timeFromSeconds(Integer.MIN_VALUE).plusMillis(1),
@@ -358,10 +351,9 @@
             { offsetToSeconds(type2Offset), 0 },
     };
 
-    // Creates a simulation of zic version <= 2014b or zic version >= 2018f where there is often
-    // no explicit transition at Integer.MIN_VALUE seconds in TZif version 1 data.
+    // Simulates a zone with a single transition.
     {
-      int[][] transitions = {
+      long[][] transitions = {
               { timeToSeconds(firstRealTransitionTime), 2 /* type 2 */ },
       };
       ZoneInfo oldZoneInfo = createZoneInfo(transitions, types, currentTime);
@@ -375,11 +367,11 @@
       assertOffsetAt(oldZoneInfo, type2Offset, afterFirstRealTransitionTimes);
     }
 
-    // Creates a simulation of zic version > 2014b and zic version < 2018f where there is usually an
-    // explicit transition at Integer.MIN_VALUE seconds for TZif version 1 data.
+    // Simulation a zone where there is an explicit transition at Integer.MIN_VALUE seconds. This
+    // used to be common when Android used 32-bit data from the TZif file.
     {
-      int[][] transitions = {
-              { Integer.MIN_VALUE, 1 /* type 1 */ }, // The extra transition added by zic.
+      long[][] transitions = {
+              { Integer.MIN_VALUE, 1 /* type 1 */ },
               { timeToSeconds(firstRealTransitionTime), 2 /* type 2 */ },
       };
       ZoneInfo newZoneInfo = createZoneInfo(transitions, types, currentTime);
@@ -398,7 +390,7 @@
 
   /**
    * Newer versions of zic after 2014b sometime introduce an explicit transition at
-   * Integer.MAX_VALUE.
+   * Integer.MAX_VALUE seconds.
    */
   public void testReadTimeZone_Bug118835133_extraLastTransition() throws Exception {
     // An arbitrary time to use as currentTime. Not important for this test.
@@ -419,10 +411,10 @@
     };
     Duration expectedLateOffset = offsetFromSeconds(latestOffsetSeconds);
 
-    // Create a simulation of zic version <= 2014b where there is usually no explicit transition at
-    // Integer.MAX_VALUE seconds.
+    // Create a simulation of a zone where there is no explicit transition at Integer.MAX_VALUE
+    // seconds.
     {
-      int[][] transitions = {
+      long[][] transitions = {
               { 1000, 0 },
               { 2000, 1 },
       };
@@ -430,10 +422,10 @@
       assertOffsetAt(oldZoneInfo, expectedLateOffset, timesToCheck);
     }
 
-    // Create a simulation of zic version > 2014b where there is sometimes an explicit transition at
-    // Integer.MAX_VALUE seconds.
+    // Create a simulation of a zone where there is an explicit transition at Integer.MAX_VALUE
+    // seconds.
     {
-      int[][] transitions = {
+      long[][] transitions = {
               { 1000, 0 },
               { 2000, 1 },
               { Integer.MAX_VALUE, 1}, // The extra transition.
@@ -444,12 +436,14 @@
   }
 
   /**
-   * Checks to make sure that it can handle up to 256 types.
+   * Checks to make sure that ZoneInfo can handle up to 256 types.
    */
-  public void testReadTimeZone_LotsOfTypes() throws Exception {
-    int[][] transitions = {
+  public void testReadTimeZone_MaxTypeCount() throws Exception {
+    long[][] transitions = {
         { -2000, 255 },
     };
+    // Create 256 types, each with zero offset and without DST except the last, which is offset by
+    // one hour but also without DST.
     int[][] types = new int[256][];
     Arrays.fill(types, new int[2]);
     types[255] = new int[] { 3600, 0 };
@@ -476,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) {
@@ -491,14 +485,14 @@
     }
   }
 
-  public void testReadTimeZone_valid() throws Exception {
+  public void testReadTimeZone_Valid() throws Exception {
     ZoneInfoTestHelper.ZicDataBuilder builder =
             new ZoneInfoTestHelper.ZicDataBuilder()
                     .initializeToValid();
     assertNotNull(createZoneInfo(getName(), Instant.now(), builder.build()));
   }
 
-  public void testReadTimeZone_badMagic() throws Exception {
+  public void testReadTimeZone_BadMagic() {
     ZoneInfoTestHelper.ZicDataBuilder builder =
             new ZoneInfoTestHelper.ZicDataBuilder()
                     .initializeToValid()
@@ -512,11 +506,15 @@
   /**
    * Checks to make sure that ZoneInfo rejects more than 256 types.
    */
-  public void testReadTimeZone_TooManyTypes() throws Exception {
+  public void testReadTimeZone_TooManyTypes() {
+    int typeCount = 257; // Max types allowed is 256
+    int transitionCount = 5;
+    long[][] transitions = createTransitions(transitionCount, typeCount);
+    int[][] types = createTypes(typeCount);
     ZoneInfoTestHelper.ZicDataBuilder builder =
             new ZoneInfoTestHelper.ZicDataBuilder()
                     .initializeToValid()
-                    .setTypeCountOverride(257);
+                    .setTransitionsAndTypes(transitions, types);
     byte[] bytes = builder.build();
     try {
       createZoneInfo(getName(), Instant.now(), bytes);
@@ -528,11 +526,15 @@
   /**
    * Checks to make sure that ZoneInfo rejects more than 2000 transitions.
    */
-  public void testReadTimeZone_TooManyTransitions() throws Exception {
+  public void testReadTimeZone_TooManyTransitions() {
+    int typeCount = 5;
+    int transitionCount = 2001; // Max transitions allowed is 2000.
+    long[][] transitions = createTransitions(transitionCount, typeCount);
+    int[][] types = createTypes(typeCount);
     ZoneInfoTestHelper.ZicDataBuilder builder =
             new ZoneInfoTestHelper.ZicDataBuilder()
                     .initializeToValid()
-                    .setTransitionCountOverride(2001);
+                    .setTransitionsAndTypes(transitions, types);
     byte[] bytes = builder.build();
     try {
       createZoneInfo(getName(), Instant.now(), bytes);
@@ -541,40 +543,8 @@
     }
   }
 
-  /**
-   * Checks to make sure that ZoneInfo rejects a negative type count.
-   */
-  public void testReadTimeZone_NegativeTypes() throws Exception {
-    ZoneInfoTestHelper.ZicDataBuilder builder =
-            new ZoneInfoTestHelper.ZicDataBuilder()
-                    .initializeToValid()
-                    .setTypeCountOverride(-1);
-    byte[] bytes = builder.build();
-    try {
-      createZoneInfo(getName(), Instant.now(), bytes);
-      fail();
-    } catch (IOException expected) {
-    }
-  }
-
-  /**
-   * Checks to make sure that ZoneInfo rejects a negative transition count.
-   */
-  public void testReadTimeZone_NegativeTransitions() throws Exception {
-    ZoneInfoTestHelper.ZicDataBuilder builder =
-            new ZoneInfoTestHelper.ZicDataBuilder()
-                    .initializeToValid()
-                    .setTransitionCountOverride(-1);
-    byte[] bytes = builder.build();
-    try {
-      createZoneInfo(getName(), Instant.now(), bytes);
-      fail();
-    } catch (IOException expected) {
-    }
-  }
-
-  public void testReadTimeZone_TransitionsNotSorted() throws Exception {
-    int[][] transitions = {
+  public void testReadTimeZone_TransitionsNotSorted() {
+    long[][] transitions = {
             { 1000, 0 },
             { 3000, 1 }, // Out of transition order.
             { 2000, 0 },
@@ -597,8 +567,8 @@
     }
   }
 
-  public void testReadTimeZone_InvalidTypeIndex() throws Exception {
-    int[][] transitions = {
+  public void testReadTimeZone_InvalidTypeIndex() {
+    long[][] transitions = {
             { 1000, 0 },
             { 2000, 2 }, // Invalid type index - only 0 and 1 defined below.
             { 3000, 0 },
@@ -621,8 +591,8 @@
     }
   }
 
-  public void testReadTimeZone_InvalidIsDst() throws Exception {
-    int[][] transitions = {
+  public void testReadTimeZone_InvalidIsDst() {
+    long[][] transitions = {
             { 1000, 0 },
             { 2000, 1 },
             { 3000, 0 },
@@ -664,7 +634,7 @@
       zoneInfoRead = (ZoneInfo) object;
     }
 
-    int[][] transitions = {
+    long[][] transitions = {
         { -5000, 0 },
         { -2000, 1 },
         { -500, 0 },
@@ -705,16 +675,12 @@
     }
   }
 
-  private static Instant timeFromSeconds(int timeInSeconds) {
+  private static Instant timeFromSeconds(long timeInSeconds) {
     return Instant.ofEpochSecond(timeInSeconds);
   }
 
-  private static int timeToSeconds(Instant time) {
-    long seconds = time.getEpochSecond();
-    if (seconds < Integer.MIN_VALUE || seconds > Integer.MAX_VALUE) {
-      fail("Time out of seconds range: " + time);
-    }
-    return (int) seconds;
+  private static long timeToSeconds(Instant time) {
+    return time.getEpochSecond();
   }
 
   private static Duration offsetFromSeconds(int offsetSeconds) {
@@ -729,17 +695,17 @@
     return (int) seconds;
   }
 
-  private ZoneInfo createZoneInfo(int[][] transitions, int[][] types)
+  private ZoneInfo createZoneInfo(long[][] transitions, int[][] types)
       throws Exception {
     return createZoneInfo(getName(), transitions, types, Instant.now());
   }
 
-  private ZoneInfo createZoneInfo(int[][] transitions, int[][] types, Instant currentTime)
+  private ZoneInfo createZoneInfo(long[][] transitions, int[][] types, Instant currentTime)
           throws Exception {
     return createZoneInfo(getName(), transitions, types, currentTime);
   }
 
-  private ZoneInfo createZoneInfo(String name, int[][] transitions, int[][] types,
+  private ZoneInfo createZoneInfo(String name, long[][] transitions, int[][] types,
           Instant currentTime) throws Exception {
 
     ZoneInfoTestHelper.ZicDataBuilder builder =
@@ -748,7 +714,7 @@
     return createZoneInfo(name, currentTime, builder.build());
   }
 
-  private ZoneInfo createZoneInfo(String name, Instant currentTime, byte[] bytes)
+  private static ZoneInfo createZoneInfo(String name, Instant currentTime, byte[] bytes)
           throws IOException {
     ByteBufferIterator bufferIterator = new ByteBufferIterator(ByteBuffer.wrap(bytes));
     return ZoneInfo.readTimeZone(
@@ -756,6 +722,38 @@
   }
 
   /**
+   * Creates {@code typeCount} "types" for use with
+   * {@link ZoneInfoTestHelper.ZicDataBuilder#setTypes(int[][])} and related methods. Each type is
+   * given an arbitrary offset and "isDst" value.
+   */
+  private static int[][] createTypes(int typeCount) {
+    int[][] types = new int[typeCount][2];
+    for (int i = 0; i < typeCount; i++) {
+      // [0] holds the offset from UTC in seconds.
+      types[i][0] = typeCount;
+      // [1] holds isDst: 0 == STD, 1 == DST
+      types[i][1] = typeCount % 2;
+    }
+    return types;
+  }
+
+  /**
+   * Creates {@code transitionCount} "transition pairs" for use with
+   * {@link ZoneInfoTestHelper.ZicDataBuilder#setTransitions(long[][])} and related methods. Each
+   * transition is given an arbitrary (but increasing) time referencing an arbitrary type.
+   */
+  private static long[][] createTransitions(int transitionCount, int typeCount) {
+    long[][] transitions = new long[transitionCount][2];
+    for (int i = 0; i < transitionCount; i++) {
+      // [0] holds the transition time.
+      transitions[i][0] = (i * 3600) + 100;
+      // [1] holds the type index to use. Must be > 0 and < typeCount to be valid.
+      transitions[i][1] = i % typeCount;
+    }
+    return transitions;
+  }
+
+  /**
    * A {@link BufferIterator} that wraps a {@link ByteBuffer}.
    */
   private static class ByteBufferIterator extends BufferIterator {
@@ -782,8 +780,8 @@
     }
 
     @Override
-    public void readByteArray(byte[] dst, int dstOffset, int byteCount) {
-      buffer.get(dst, dstOffset, byteCount);
+    public void readByteArray(byte[] bytes, int arrayOffset, int byteCount) {
+      buffer.get(bytes, arrayOffset, byteCount);
     }
 
     @Override
@@ -796,16 +794,24 @@
       int value = buffer.asIntBuffer().get();
       // Using a separate view does not update the position of this buffer so do it
       // explicitly.
-      skip(4);
+      skip(Integer.BYTES);
       return value;
     }
 
     @Override
-    public void readIntArray(int[] dst, int dstOffset, int intCount) {
-      buffer.asIntBuffer().get(dst, dstOffset, intCount);
+    public void readIntArray(int[] ints, int arrayOffset, int intCount) {
+      buffer.asIntBuffer().get(ints, arrayOffset, intCount);
       // Using a separate view does not update the position of this buffer so do it
       // explicitly.
-      skip(4 * intCount);
+      skip(Integer.BYTES * intCount);
+    }
+
+    @Override
+    public void readLongArray(long[] longs, int arrayOffset, int longCount) {
+      buffer.asLongBuffer().get(longs, arrayOffset, longCount);
+      // Using a separate view does not update the position of this buffer so do it
+      // explicitly.
+      skip(Long.BYTES * longCount);
     }
 
     @Override
@@ -813,7 +819,7 @@
       short value = buffer.asShortBuffer().get();
       // Using a separate view does not update the position of this buffer so do it
       // explicitly.
-      skip(2);
+      skip(Short.BYTES);
       return value;
     }
   }
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
index 7d8aff0..751a99e 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
@@ -39,39 +39,29 @@
 import javax.crypto.ShortBufferException;
 import javax.crypto.spec.DHGenParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
 import org.apache.harmony.crypto.tests.support.MyMacSpi;
 import org.apache.harmony.security.tests.support.SpiEngUtils;
-import junit.framework.TestCase;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 import libcore.java.security.StandardNames;
 import libcore.javax.crypto.MockKey;
 import libcore.javax.crypto.MockKey2;
-
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
 /**
  * Tests for Mac class constructors and methods
  *
  */
-public class MacTest extends TestCase {
+public class MacTest extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     public static final String srvMac = "Mac";
 
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/KeyAgreementThread.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/KeyAgreementThread.java
index 480ea7f..33e9c21 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/KeyAgreementThread.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/func/KeyAgreementThread.java
@@ -15,7 +15,6 @@
  */
 package org.apache.harmony.crypto.tests.javax.crypto.func;
 
-import com.android.org.bouncycastle.util.Arrays;
 import java.security.AlgorithmParameterGenerator;
 import java.security.AlgorithmParameters;
 import java.security.KeyFactory;
@@ -25,6 +24,7 @@
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
 import javax.crypto.KeyAgreement;
 import javax.crypto.spec.DHParameterSpec;
 
@@ -80,7 +80,7 @@
         byte[] sk1 = kag1.getSecretKey(algName, bArray2);
         byte[] sk2 = kag2.getSecretKey(algName, bArray1);
 
-        if (Arrays.areEqual(sk1, sk2) == false) {
+        if (!Arrays.equals(sk1, sk2)) {
             throw new Exception ("Generated keys are not the same");
         }
     }
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest2Test.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest2Test.java
index 689efa5..5367dcd 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest2Test.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest2Test.java
@@ -33,9 +33,19 @@
 import java.util.Map.Entry;
 
 import dalvik.system.VMRuntime;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 import sun.security.jca.Providers;
 
-public class MessageDigest2Test extends junit.framework.TestCase {
+public class MessageDigest2Test extends TestCaseWithRules {
+
+    // Allow access to deprecated BC algorithms in this test, so we can ensure they
+    // continue to work
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     private static final String MESSAGEDIGEST_ID = "MessageDigest.";
 
@@ -434,18 +444,6 @@
         for (Provider provider : providers) {
             digestAlgs.put(provider, getDigestAlgorithms(provider));
         }
-
-        // Allow access to deprecated BC algorithms in this test, so we can ensure they
-        // continue to work
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
     }
 
     /*
diff --git a/luni/src/test/java/tests/security/cert/CertPathBuilder1Test.java b/luni/src/test/java/tests/security/cert/CertPathBuilder1Test.java
index aae021b..20597db 100644
--- a/luni/src/test/java/tests/security/cert/CertPathBuilder1Test.java
+++ b/luni/src/test/java/tests/security/cert/CertPathBuilder1Test.java
@@ -22,8 +22,6 @@
 
 package tests.security.cert;
 
-import dalvik.annotation.KnownFailure;
-
 import org.apache.harmony.security.tests.support.SpiEngUtils;
 import org.apache.harmony.security.tests.support.cert.MyCertPathBuilderSpi;
 import org.apache.harmony.security.tests.support.cert.TestUtils;
@@ -316,8 +314,6 @@
         }
     }
 
-    // Test passed on RI
-    @KnownFailure(value="expired certificate bug 2322662")
     public void testBuild() throws Exception {
         TestUtils.initCertPathSSCertChain();
         CertPathParameters params = TestUtils.getCertPathParameters();
diff --git a/luni/src/test/java/tests/security/cert/CertificateFactory4Test.java b/luni/src/test/java/tests/security/cert/CertificateFactory4Test.java
index 18fe0c4..1b3f00c 100644
--- a/luni/src/test/java/tests/security/cert/CertificateFactory4Test.java
+++ b/luni/src/test/java/tests/security/cert/CertificateFactory4Test.java
@@ -17,10 +17,10 @@
 
 package tests.security.cert;
 
-import junit.framework.TestCase;
-
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 import tests.support.resource.Support_Resources;
 
 import tests.support.Support_GetResource;
@@ -40,23 +40,13 @@
 import java.util.Collection;
 import java.util.List;
 
-public class CertificateFactory4Test extends TestCase {
+public class CertificateFactory4Test extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     private static final String BASE_URL = Support_GetResource
             .getResourceURL("/../internalres/");
diff --git a/luni/src/test/java/tests/targets/security/cert/CertificateTest.java b/luni/src/test/java/tests/targets/security/cert/CertificateTest.java
index 80b34c0..4a8e5ef 100644
--- a/luni/src/test/java/tests/targets/security/cert/CertificateTest.java
+++ b/luni/src/test/java/tests/targets/security/cert/CertificateTest.java
@@ -32,29 +32,19 @@
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.List;
-import junit.framework.TestCase;
 import libcore.java.security.StandardNames;
+import libcore.junit.junit3.TestCaseWithRules;
+import libcore.junit.util.EnableDeprecatedBouncyCastleAlgorithmsRule;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
 
-import dalvik.system.VMRuntime;
-import sun.security.jca.Providers;
-
-public class CertificateTest extends TestCase {
+public class CertificateTest extends TestCaseWithRules {
 
     // Allow access to deprecated BC algorithms in this test, so we can ensure they
     // continue to work
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                VMRuntime.getRuntime().getTargetSdkVersion());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        Providers.setMaximumAllowableApiLevelForBcDeprecation(
-                Providers.DEFAULT_MAXIMUM_ALLOWABLE_TARGET_API_LEVEL_FOR_BC_DEPRECATION);
-        super.tearDown();
-    }
+    @Rule
+    public TestRule enableDeprecatedBCAlgorithmsRule =
+            EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
 
     /*
      * Following certificate chain was taken from https://www.verisign.com and
diff --git a/luni/src/test/java9language/Android.bp b/luni/src/test/java9language/Android.bp
new file mode 100644
index 0000000..dddc184
--- /dev/null
+++ b/luni/src/test/java9language/Android.bp
@@ -0,0 +1,74 @@
+// 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.
+
+// Android tests related to Java 9 language features.
+
+// Use jarjar to repackage Java9LanguageFeatures, to be used in tests below.
+java_library {
+    name: "core-java-9-language-features-repackaged-for-test",
+    hostdex: true,
+
+    srcs: [":core-java-9-language-features-source"],
+    jarjar_rules: "jarjar_rules_java9_language_features.txt",
+    java_version: "1.9",
+
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
+    patch_module: "java.base",
+
+    visibility: ["//visibility:private"],
+}
+
+// Generate a clone of Java9LanguageFeaturesTest which uses a version of
+// Java9LanguageFeatures repackaged by jarjar. This ensures that jarjar is able
+// to handle a class file which must be at least v53 and includes bytecode
+// compiled from Java 9 language features.
+filegroup {
+    name: "core-rewrite-test-for-jarjar-sed-script",
+    srcs: ["rewrite-test-for-jarjar.sed"],
+    visibility: ["//visibility:private"],
+}
+
+filegroup {
+    name: "core-java-9-language-features-test-src",
+    srcs: ["java/libcore/libcore/internal/Java9LanguageFeaturesTest.java"],
+    visibility: ["//visibility:private"],
+}
+
+genrule {
+    name: "core-gen-test-repackaged-java-9-language-features",
+    srcs: [
+        ":core-rewrite-test-for-jarjar-sed-script",
+        ":core-java-9-language-features-test-src",
+    ],
+    out: ["libcore/libcore/internal/Java9LanguageFeaturesJarjarTest.java"],
+    cmd: "sed -r -f $(location :core-rewrite-test-for-jarjar-sed-script) $(location :core-java-9-language-features-test-src) > $(out)",
+    visibility: ["//visibility:private"],
+}
+
+java_library {
+    name: "core-java-9-language-tests",
+    hostdex: true,
+    srcs: [
+        "java/**/*.java",
+        ":core-gen-test-repackaged-java-9-language-features",
+    ],
+    sdk_version: "none",
+    system_modules: "core-all-system-modules",
+    static_libs: [
+        "core-java-9-language-features-repackaged-for-test",
+        "junit",
+    ],
+    visibility: ["//libcore"],
+}
diff --git a/luni/src/test/java9language/jarjar_rules_java9_language_features.txt b/luni/src/test/java9language/jarjar_rules_java9_language_features.txt
new file mode 100644
index 0000000..dee72bc
--- /dev/null
+++ b/luni/src/test/java9language/jarjar_rules_java9_language_features.txt
@@ -0,0 +1 @@
+rule libcore.internal.** libcore.internal.repackaged.@1
diff --git a/luni/src/test/java/libcore/libcore/internal/Java9LanguageFeaturesTest.java b/luni/src/test/java9language/java/libcore/libcore/internal/Java9LanguageFeaturesTest.java
similarity index 100%
rename from luni/src/test/java/libcore/libcore/internal/Java9LanguageFeaturesTest.java
rename to luni/src/test/java9language/java/libcore/libcore/internal/Java9LanguageFeaturesTest.java
diff --git a/ojluni/Android.mk b/luni/src/test/java9language/rewrite-test-for-jarjar.sed
similarity index 60%
rename from ojluni/Android.mk
rename to luni/src/test/java9language/rewrite-test-for-jarjar.sed
index 8eef8b5..525a14a 100644
--- a/ojluni/Android.mk
+++ b/luni/src/test/java9language/rewrite-test-for-jarjar.sed
@@ -1,5 +1,4 @@
-# -*- mode: makefile -*-
-# Copyright (C) 2016 The Android Open Source Project
+# 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.
@@ -13,9 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
+# This is a sed script that modifies Java source code in two ways.
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := ojluni-phony
-include $(BUILD_PHONY_PACKAGE)
+# Replace libcore.internal with libcore.internal.repackaged in imports:
+s/import libcore.internal/import libcore.internal.repackaged/
 
+# Replace Test with JarjarTest in class declarations.
+s/class ([A-Za-z0-9_]+)Test/class \1JarjarTest/
diff --git a/luni/src/test/native/libcore_java_lang_ThreadTest.cpp b/luni/src/test/native/libcore_java_lang_ThreadTest.cpp
index f942607..a20ff48 100644
--- a/luni/src/test/native/libcore_java_lang_ThreadTest.cpp
+++ b/luni/src/test/native/libcore_java_lang_ThreadTest.cpp
@@ -71,7 +71,9 @@
 
 
     if (javaVm->DetachCurrentThread() != JNI_OK) {
-        exception_message = new std::string("Detach failed");
+        if (exception_message == nullptr) {
+            exception_message = new std::string("Detach failed");
+        }
     }
 
     return exception_message;
diff --git a/luni/src/test/native/libcore_libcore_util_NativeAllocationRegistryTest.cpp b/luni/src/test/native/libcore_libcore_util_NativeAllocationRegistryTest.cpp
index 62982f4..b901189 100644
--- a/luni/src/test/native/libcore_libcore_util_NativeAllocationRegistryTest.cpp
+++ b/luni/src/test/native/libcore_libcore_util_NativeAllocationRegistryTest.cpp
@@ -18,6 +18,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <atomic>
 #include <string>
 
 #include <jni.h>
@@ -69,7 +70,7 @@
   return static_cast<jboolean>(is_native_bridged_abi);
 }
 
-uint64_t gNumNativeBytesAllocated = 0;
+std::atomic<uint64_t> gNumNativeBytesAllocated = 0;
 
 static void finalize(uint64_t* ptr) {
   gNumNativeBytesAllocated -= *ptr;
diff --git a/luni/src/test/parameter_metadata/Android.bp b/luni/src/test/parameter_metadata/Android.bp
new file mode 100644
index 0000000..0eec841
--- /dev/null
+++ b/luni/src/test/parameter_metadata/Android.bp
@@ -0,0 +1,34 @@
+// 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.
+
+// Contains classes for testing access to parameter information via reflection.
+//
+// This is a separate library so it can use the -parameters javac flag (to add parameter information
+// to the class files) without affecting other tests.
+//
+// Included as a resource by //libcore:core-tests and loaded into its own
+// class loader by libcore.java.lang.reflect.ParameterTest.
+java_library {
+    name: "parameter-metadata-test",
+    visibility: [
+        "//libcore",
+    ],
+    compile_dex: true,
+    srcs: ["src/**/*.java"],
+    sdk_version: "core_platform",
+    javacflags: ["-parameters"],
+    errorprone: {
+        javacflags: ["-Xep:MissingOverride:OFF"],
+    },
+}
diff --git a/metrictests/memory/README b/metrictests/memory/README
index 77574ef..e0b083b 100644
--- a/metrictests/memory/README
+++ b/metrictests/memory/README
@@ -27,7 +27,7 @@
 then dumps another heap. You can run it manually as follows:
 
   make LibcoreHeapDumper
-  adb install -g -r ${ANDROID_PRODUCT_OUT}/data/app/LibcoreHeapDumper/LibcoreHeapDumper.apk
+  adb install -g -r ${ANDROID_PRODUCT_OUT}/testcases/LibcoreHeapDumper/arm64/LibcoreHeapDumper.apk
 
   DEVICE_EXTERNAL_STORAGE=$(adb shell 'echo -n ${EXTERNAL_STORAGE}')
   # Pick a suitable name here:
diff --git a/metrictests/memory/apps/AndroidManifest.xml b/metrictests/memory/apps/AndroidManifest.xml
index a8856aa..aca7177 100644
--- a/metrictests/memory/apps/AndroidManifest.xml
+++ b/metrictests/memory/apps/AndroidManifest.xml
@@ -18,7 +18,9 @@
     package="libcore.heapdumper">
 
     <uses-sdk android:minSdkVersion="19" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
 
     <instrumentation
             android:name="libcore.heapdumper.HeapDumpInstrumentation"
@@ -30,6 +32,7 @@
 
     <application
             android:allowBackup="false"
+            android:requestLegacyExternalStorage="true"
             android:label="@string/libcore_heap_dumper_title">
     </application>
 </manifest>
diff --git a/metrictests/memory/apps/src/libcore/heapdumper/Actions.java b/metrictests/memory/apps/src/libcore/heapdumper/Actions.java
index e8b56f1..e5ef4ba 100644
--- a/metrictests/memory/apps/src/libcore/heapdumper/Actions.java
+++ b/metrictests/memory/apps/src/libcore/heapdumper/Actions.java
@@ -19,6 +19,8 @@
 import java.text.Collator;
 import java.util.Arrays;
 import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * An enumeration of actions for which we'd like to measure the effect on the post-GC heap.
@@ -65,6 +67,33 @@
         }
     },
 
+    REGEX {
+        @Override
+        public void run() {
+            final String sequence = "foo 123 bar baz";
+            Pattern p = Pattern.compile("foo (\\d+) bar (\\w+)");
+            Matcher m = p.matcher(sequence);
+
+            boolean found = m.find();
+            boolean matches = m.matches();
+            int groups = m.groupCount();
+            String first = m.group(1);
+            String second = m.group(2);
+            boolean hitEnd = m.hitEnd();
+
+            // Set region to prefix of the original sequence
+            m.region(0, "foo 123".length());
+            boolean matchesPrefix = m.lookingAt();
+            boolean requireEnd = m.requireEnd();
+
+            m.useTransparentBounds(true);
+            boolean matchesPrefixTransparentBounds = m.lookingAt();
+
+            m.useAnchoringBounds(true);
+            boolean matchesPrefixAnchoringBounds = m.lookingAt();
+        }
+    }
+
     ;
 
     private static void useCollatorForLocale(Locale locale) {
diff --git a/metrictests/memory/host/Android.bp b/metrictests/memory/host/Android.bp
index a70afc6..beed9e1 100644
--- a/metrictests/memory/host/Android.bp
+++ b/metrictests/memory/host/Android.bp
@@ -15,7 +15,7 @@
 java_test_host {
     name: "libcore-memory-metrics-tests",
     srcs: ["src/**/*.java"],
-    libs: [
+    static_libs: [
         "tradefed",
         "ahat",
     ],
diff --git a/metrictests/memory/host/src/libcore/heapmetrics/LibcoreHeapMetricsTest.java b/metrictests/memory/host/src/libcore/heapmetrics/LibcoreHeapMetricsTest.java
index 5340d90..2231614 100644
--- a/metrictests/memory/host/src/libcore/heapmetrics/LibcoreHeapMetricsTest.java
+++ b/metrictests/memory/host/src/libcore/heapmetrics/LibcoreHeapMetricsTest.java
@@ -103,6 +103,12 @@
         recordBeforeAndAfterAppHeapMetrics(result.getBeforeDump(), result.getAfterDump());
     }
 
+    @Test
+    public void measureRegexes() throws Exception {
+        MetricsRunner.Result result = metricsRunner.runAllInstrumentations("REGEX");
+        recordBeforeAndAfterAppHeapMetrics(result.getBeforeDump(), result.getAfterDump());
+    }
+
     private void recordHeapMetrics(AhatSnapshot dump, String metricPrefix, String heapName) {
         AhatHeap heap = dump.getHeap(heapName);
         recordSizeMetric(metricPrefix, heap.getSize());
diff --git a/metrictests/memory/host/src/libcore/heapmetrics/MetricsRunner.java b/metrictests/memory/host/src/libcore/heapmetrics/MetricsRunner.java
index c3f9e0d..e96bc72 100644
--- a/metrictests/memory/host/src/libcore/heapmetrics/MetricsRunner.java
+++ b/metrictests/memory/host/src/libcore/heapmetrics/MetricsRunner.java
@@ -30,8 +30,7 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.time.Instant;
 
 /**
  * Helper class that runs the metric instrumentations on a test device.
@@ -243,10 +242,14 @@
         }
     }
 
+    /**
+     * Returns the ISO 8601 form of the current time in UTC, for use as a timestamp in filenames.
+     * (Note that using UTC avoids an issue where the timezone indicator includes a + sign for the
+     * offset, which triggers an issue with URL encoding in tradefed, which causes the calls to
+     * {@code testDevice.pullFile()} to fail. See b/149018916.)
+     */
     private static String getCurrentTimeIso8601() {
-        SimpleDateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
-        Date now = new Date();
-        return iso8601Format.format(now);
+        return Instant.now().toString();
     }
 
     /**
diff --git a/mmodules/core_platform_api/Android.bp b/mmodules/core_platform_api/Android.bp
index 4210597..f2a042b 100644
--- a/mmodules/core_platform_api/Android.bp
+++ b/mmodules/core_platform_api/Android.bp
@@ -12,21 +12,31 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Build rules for the APIs that various core libraries provide to other parts
-// of the Android software stack: these include the public SDK APIs plus some
-// "core platform APIs" that only the Android software stack can use.
-
-// Generates stub source files for the {public SDK + core platform} API of the
-// core jars.
+// Generates stub source files for the core platform API of the ART module.
+// i.e. every class/member that is either in the public API or annotated with
+// @CorePlatformApi.
+//
+// The API specification .txt files managed by this only contain the additional
+// classes/members that are in the intra-core API but which are not in the public
+// API.
 droidstubs {
-    name: "core-platform-api-stubs",
-    srcs: [":core_api_files"],
-    no_standard_libs: true,
+    name: "art-module-platform-api-stubs-source",
+    srcs: [
+        ":art_module_api_files",
+    ],
+    sdk_version: "none",
+    system_modules: "none",
+    libs: [
+        // Needed to break the cycle in the platform api caused by
+        // b/141747409.
+        "i18n.module.intra.core.api.stubs",
+    ],
 
     installable: false,
-    args: "--hide-annotation libcore.api.Hide "
-        + "--show-single-annotation libcore.api.CorePlatformApi "
-        + "--skip-annotation-instance-methods=false ",
+    args: "--hide HiddenSuperclass " +
+        "--hide-annotation libcore.api.Hide " +
+        "--show-single-annotation libcore.api.CorePlatformApi " +
+        "--skip-annotation-instance-methods=false ",
     merge_inclusion_annotations_dirs: ["ojluni-annotated-mmodule-stubs"],
 
     api_filename: "api.txt",
@@ -45,7 +55,52 @@
     },
 }
 
-// A library containing the {public SDK + core platform} API stubs for the core jars.
+// A special set of system modules that is needed to break the cycle in the
+// platform api caused by b/141747409.
+java_system_modules {
+    name: "break-cycle-in-core-platform-system-modules",
+    libs: [
+        "art.module.intra.core.api.stubs",
+        "i18n.module.intra.core.api.stubs",
+    ],
+}
+
+// A library containing the core platform API stubs of the ART module.
+//
+// Core platform APIs are only intended for use of other parts of the platform, not the
+// core library modules.
+java_library {
+    name: "art.module.platform.api.stubs",
+    srcs: [
+        ":art-module-platform-api-stubs-source",
+    ],
+    hostdex: true,
+
+    sdk_version: "none",
+    system_modules: "break-cycle-in-core-platform-system-modules",
+    patch_module: "java.base",
+}
+
+// Used when compiling higher-level code against core.platform.api.stubs.
+java_system_modules {
+    name: "art-module-platform-api-stubs-system-modules",
+    visibility: [
+        "//art/build/sdk",
+        "//external/conscrypt",
+        "//external/icu/android_icu4j",
+        "//external/wycheproof",
+    ],
+    libs: [
+        "art.module.platform.api.stubs",
+    ],
+}
+
+// Ideally this should be a restricted whitelist but there are hundreds of modules that depend on
+// this.
+// TODO(http://b/134561230) - limit the number of dependents on this.
+core_platform_visibility = ["//visibility:public"]
+
+// A library containing the core platform API stubs for the core libraries.
 //
 // Although this stubs library is primarily used by the Java compiler / build to indicate
 // the core platform API surface area, compile_dex: true is used so that the Core Platform
@@ -53,23 +108,33 @@
 // accessibility. b/119068555
 java_library {
     name: "core.platform.api.stubs",
-    srcs: [":core-platform-api-stubs"],
+    visibility: core_platform_visibility,
     hostdex: true,
     compile_dex: true,
 
-    no_standard_libs: true,
+    sdk_version: "none",
     system_modules: "none",
+    static_libs: [
+        "art.module.platform.api.stubs",
+        "conscrypt.module.platform.api.stubs",
+        "i18n.module.platform.api.stubs",
+    ],
     patch_module: "java.base",
 }
 
 // Used when compiling higher-level code against core.platform.api.stubs.
 java_system_modules {
     name: "core-platform-api-stubs-system-modules",
+    visibility: core_platform_visibility,
     libs: [
         "core.platform.api.stubs",
         // This one is not on device but it's needed when javac compiles code
         // containing lambdas.
         "core-lambda-stubs-for-system-modules",
+        // This one is not on device but it's needed when javac compiles code
+        // containing @Generated annotations produced by some code generation
+        // tools.
+        // See http://b/123891440.
+        "core-generated-annotation-stubs",
     ],
 }
-
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index b2b81df..15a0a48 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -1,88 +1,42 @@
 // Signature format: 2.0
-package android.icu.impl {
+package android.compat {
 
-  public class CalendarAstronomer {
-    ctor public CalendarAstronomer(double, double);
-    method public long getSunRiseSet(boolean);
-    method public void setTime(long);
+  public final class Compatibility {
+    method public static void clearOverrides();
+    method public static boolean isChangeEnabled(long);
+    method public static void reportChange(long);
+    method public static void setCallbacks(android.compat.Compatibility.Callbacks);
+    method public static void setOverrides(android.compat.Compatibility.ChangeConfig);
   }
 
-  public class TimeZoneAdapter extends java.util.TimeZone {
-    method public static java.util.TimeZone wrap(android.icu.util.TimeZone);
+  public static class Compatibility.Callbacks {
+    ctor protected Compatibility.Callbacks();
+    method protected boolean isChangeEnabled(long);
+    method protected void reportChange(long);
   }
 
-}
-
-package android.icu.text {
-
-  public final class StringPrep {
-    method public static android.icu.text.StringPrep getInstance(int);
-    method public String prepare(String, int) throws android.icu.text.StringPrepParseException;
-    field public static final int DEFAULT = 0; // 0x0
-    field public static final int RFC3920_RESOURCEPREP = 8; // 0x8
-  }
-
-  public class StringPrepParseException extends java.text.ParseException {
-    ctor public StringPrepParseException(String, int);
-    ctor public StringPrepParseException(String, int, String, int);
-    ctor public StringPrepParseException(String, int, String, int, int);
-    method public int getError();
-    field public static final int ACE_PREFIX_ERROR = 6; // 0x6
-    field public static final int BUFFER_OVERFLOW_ERROR = 9; // 0x9
-    field public static final int CHECK_BIDI_ERROR = 4; // 0x4
-    field public static final int DOMAIN_NAME_TOO_LONG_ERROR = 11; // 0xb
-    field public static final int ILLEGAL_CHAR_FOUND = 1; // 0x1
-    field public static final int INVALID_CHAR_FOUND = 0; // 0x0
-    field public static final int LABEL_TOO_LONG_ERROR = 8; // 0x8
-    field public static final int PROHIBITED_ERROR = 2; // 0x2
-    field public static final int STD3_ASCII_RULES_ERROR = 5; // 0x5
-    field public static final int UNASSIGNED_ERROR = 3; // 0x3
-    field public static final int VERIFICATION_ERROR = 7; // 0x7
-    field public static final int ZERO_LENGTH_LABEL = 10; // 0xa
-  }
-
-}
-
-package android.icu.util {
-
-  public abstract class BasicTimeZone extends android.icu.util.TimeZone {
-    method public abstract android.icu.util.TimeZoneTransition getNextTransition(long, boolean);
-  }
-
-  public class Region implements java.lang.Comparable<android.icu.util.Region> {
-    method public static java.util.Set<android.icu.util.Region> getAvailable(android.icu.util.Region.RegionType);
-  }
-
-  public enum Region.RegionType {
-    enum_constant public static final android.icu.util.Region.RegionType TERRITORY;
-  }
-
-  public abstract class TimeZoneRule implements java.io.Serializable {
-    method public int getDSTSavings();
-  }
-
-  public class TimeZoneTransition {
-    method public android.icu.util.TimeZoneRule getFrom();
-    method public long getTime();
-    method public android.icu.util.TimeZoneRule getTo();
+  public static final class Compatibility.ChangeConfig {
+    ctor public Compatibility.ChangeConfig(java.util.Set<java.lang.Long>, java.util.Set<java.lang.Long>);
+    method public long[] forceDisabledChangesArray();
+    method public java.util.Set<java.lang.Long> forceDisabledSet();
+    method public long[] forceEnabledChangesArray();
+    method public java.util.Set<java.lang.Long> forceEnabledSet();
+    method public boolean isEmpty();
+    method public boolean isForceDisabled(long);
+    method public boolean isForceEnabled(long);
   }
 
 }
 
 package android.system {
 
-  public final class ErrnoException extends java.lang.Exception {
-    method public java.io.IOException rethrowAsIOException() throws java.io.IOException;
-    method public java.net.SocketException rethrowAsSocketException() throws java.net.SocketException;
-  }
-
   public class Int32Ref {
     ctor public Int32Ref(int);
-    field @dalvik.annotation.compat.UnsupportedAppUsage public int value;
+    field public int value;
   }
 
   public final class NetlinkSocketAddress extends java.net.SocketAddress {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public NetlinkSocketAddress(int, int);
+    ctor public NetlinkSocketAddress(int, int);
     method public int getGroupsMask();
     method public int getPortId();
   }
@@ -90,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;
@@ -101,36 +54,35 @@
     method public static void setpgid(int, int) throws android.system.ErrnoException;
     method public static void setregid(int, int) throws android.system.ErrnoException;
     method public static void setreuid(int, int) throws android.system.ErrnoException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void setsockoptIfreq(java.io.FileDescriptor, int, int, String) throws android.system.ErrnoException;
+    method public static void setsockoptIfreq(java.io.FileDescriptor, int, int, String) throws android.system.ErrnoException;
     method public static void setsockoptLinger(java.io.FileDescriptor, int, int, android.system.StructLinger) throws android.system.ErrnoException;
     method public static long splice(java.io.FileDescriptor, android.system.Int64Ref, java.io.FileDescriptor, android.system.Int64Ref, long, int) throws android.system.ErrnoException;
     method public static void unlink(String) throws android.system.ErrnoException;
   }
 
   public final class OsConstants {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static int CAP_TO_INDEX(int);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static int CAP_TO_MASK(int);
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int ENONET;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int EUSERS;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int MAP_POPULATE;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int NETLINK_NETFILTER;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int O_DIRECT;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int PR_CAP_AMBIENT;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int PR_CAP_AMBIENT_RAISE;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int RLIMIT_NOFILE;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int RTMGRP_IPV4_IFADDR;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int SPLICE_F_MORE;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int SPLICE_F_MOVE;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int TIOCOUTQ;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int UDP_ENCAP;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int UDP_ENCAP_ESPINUDP;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int XATTR_CREATE;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int _LINUX_CAPABILITY_VERSION_3;
+    method public static int CAP_TO_INDEX(int);
+    method public static int CAP_TO_MASK(int);
+    field public static final int ARPHRD_LOOPBACK;
+    field public static final int ENONET;
+    field public static final int EUSERS;
+    field public static final int MAP_POPULATE;
+    field public static final int O_DIRECT;
+    field public static final int PR_CAP_AMBIENT;
+    field public static final int PR_CAP_AMBIENT_RAISE;
+    field public static final int RLIMIT_NOFILE;
+    field public static final int RTMGRP_IPV4_IFADDR;
+    field public static final int SPLICE_F_MORE;
+    field public static final int SPLICE_F_MOVE;
+    field public static final int TIOCOUTQ;
+    field public static final int UDP_ENCAP;
+    field public static final int UDP_ENCAP_ESPINUDP;
+    field public static final int XATTR_CREATE;
+    field public static final int _LINUX_CAPABILITY_VERSION_3;
   }
 
   public final class PacketSocketAddress extends java.net.SocketAddress {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public PacketSocketAddress(short, int);
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public PacketSocketAddress(int, byte[]);
+    ctor public PacketSocketAddress(int, int, byte[]);
   }
 
   public final class StructCapUserData {
@@ -208,18 +160,18 @@
   }
 
   public class ASN1EncodableVector {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public ASN1EncodableVector();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void add(com.android.org.bouncycastle.asn1.ASN1Encodable);
+    ctor public ASN1EncodableVector();
+    method public void add(com.android.org.bouncycastle.asn1.ASN1Encodable);
   }
 
   public class ASN1InputStream extends java.io.FilterInputStream {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public ASN1InputStream(java.io.InputStream);
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public ASN1InputStream(byte[]);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public com.android.org.bouncycastle.asn1.ASN1Primitive readObject() throws java.io.IOException;
+    ctor public ASN1InputStream(java.io.InputStream);
+    ctor public ASN1InputStream(byte[]);
+    method public com.android.org.bouncycastle.asn1.ASN1Primitive readObject() throws java.io.IOException;
   }
 
   public class ASN1Integer extends com.android.org.bouncycastle.asn1.ASN1Primitive {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public ASN1Integer(java.math.BigInteger);
+    ctor public ASN1Integer(java.math.BigInteger);
   }
 
   public abstract class ASN1Null extends com.android.org.bouncycastle.asn1.ASN1Primitive {
@@ -256,24 +208,24 @@
   }
 
   public class DERBitString extends com.android.org.bouncycastle.asn1.ASN1BitString {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public DERBitString(byte[]);
+    ctor public DERBitString(byte[]);
   }
 
   @Deprecated public class DERInteger extends com.android.org.bouncycastle.asn1.ASN1Integer {
-    ctor @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public DERInteger(long);
+    ctor @Deprecated public DERInteger(long);
   }
 
   public class DERNull extends com.android.org.bouncycastle.asn1.ASN1Null {
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final com.android.org.bouncycastle.asn1.DERNull INSTANCE;
+    field public static final com.android.org.bouncycastle.asn1.DERNull INSTANCE;
   }
 
   public class DEROctetString extends com.android.org.bouncycastle.asn1.ASN1OctetString {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public DEROctetString(byte[]);
+    ctor public DEROctetString(byte[]);
   }
 
   public class DERSequence extends com.android.org.bouncycastle.asn1.ASN1Sequence {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public DERSequence();
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public DERSequence(com.android.org.bouncycastle.asn1.ASN1EncodableVector);
+    ctor public DERSequence();
+    ctor public DERSequence(com.android.org.bouncycastle.asn1.ASN1EncodableVector);
   }
 
   public class DERTaggedObject extends com.android.org.bouncycastle.asn1.ASN1TaggedObject {
@@ -290,7 +242,7 @@
 package com.android.org.bouncycastle.asn1.pkcs {
 
   public interface PKCSObjectIdentifiers {
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier sha256WithRSAEncryption;
+    field public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier sha256WithRSAEncryption;
     field public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier sha512WithRSAEncryption;
   }
 
@@ -321,8 +273,8 @@
 package com.android.org.bouncycastle.asn1.x509 {
 
   public class AlgorithmIdentifier extends com.android.org.bouncycastle.asn1.ASN1Object {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public AlgorithmIdentifier(com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier);
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public AlgorithmIdentifier(com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier, com.android.org.bouncycastle.asn1.ASN1Encodable);
+    ctor public AlgorithmIdentifier(com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier);
+    ctor public AlgorithmIdentifier(com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier, com.android.org.bouncycastle.asn1.ASN1Encodable);
     method public com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier getAlgorithm();
   }
 
@@ -332,7 +284,7 @@
   }
 
   public class Certificate extends com.android.org.bouncycastle.asn1.ASN1Object {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static com.android.org.bouncycastle.asn1.x509.Certificate getInstance(Object);
+    method public static com.android.org.bouncycastle.asn1.x509.Certificate getInstance(Object);
   }
 
   public class GeneralName extends com.android.org.bouncycastle.asn1.ASN1Object {
@@ -345,35 +297,35 @@
   }
 
   public class SubjectPublicKeyInfo extends com.android.org.bouncycastle.asn1.ASN1Object {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo getInstance(Object);
+    method public static com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo getInstance(Object);
   }
 
   public class TBSCertificate extends com.android.org.bouncycastle.asn1.ASN1Object {
   }
 
   public class Time extends com.android.org.bouncycastle.asn1.ASN1Object {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public Time(java.util.Date);
+    ctor public Time(java.util.Date);
   }
 
   public class V3TBSCertificateGenerator {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public V3TBSCertificateGenerator();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public com.android.org.bouncycastle.asn1.x509.TBSCertificate generateTBSCertificate();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setEndDate(com.android.org.bouncycastle.asn1.x509.Time);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setIssuer(com.android.org.bouncycastle.asn1.x509.X509Name);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setSerialNumber(com.android.org.bouncycastle.asn1.ASN1Integer);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setSignature(com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setStartDate(com.android.org.bouncycastle.asn1.x509.Time);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setSubject(com.android.org.bouncycastle.asn1.x509.X509Name);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setSubjectPublicKeyInfo(com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo);
+    ctor public V3TBSCertificateGenerator();
+    method public com.android.org.bouncycastle.asn1.x509.TBSCertificate generateTBSCertificate();
+    method public void setEndDate(com.android.org.bouncycastle.asn1.x509.Time);
+    method @Deprecated public void setIssuer(com.android.org.bouncycastle.asn1.x509.X509Name);
+    method public void setSerialNumber(com.android.org.bouncycastle.asn1.ASN1Integer);
+    method public void setSignature(com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier);
+    method public void setStartDate(com.android.org.bouncycastle.asn1.x509.Time);
+    method @Deprecated public void setSubject(com.android.org.bouncycastle.asn1.x509.X509Name);
+    method public void setSubjectPublicKeyInfo(com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo);
   }
 
   @Deprecated public class X509Name extends com.android.org.bouncycastle.asn1.ASN1Object {
-    ctor @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public X509Name(String);
+    ctor @Deprecated public X509Name(String);
     method @Deprecated public static com.android.org.bouncycastle.asn1.x509.X509Name getInstance(Object);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public java.util.Vector getOIDs();
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public java.util.Vector getValues();
+    method @Deprecated public java.util.Vector getOIDs();
+    method @Deprecated public java.util.Vector getValues();
     method @Deprecated public String toString(boolean, java.util.Hashtable);
-    field @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier CN;
+    field @Deprecated public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier CN;
     field @Deprecated public static final java.util.Hashtable DefaultSymbols;
     field @Deprecated public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier O;
     field @Deprecated public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier OU;
@@ -384,7 +336,7 @@
 package com.android.org.bouncycastle.asn1.x9 {
 
   public interface X9ObjectIdentifiers {
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier ecdsa_with_SHA256;
+    field public static final com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier ecdsa_with_SHA256;
   }
 
 }
@@ -401,6 +353,28 @@
 
 }
 
+package com.android.org.bouncycastle.crypto.digests {
+
+  public abstract class GeneralDigest {
+    method public void finish();
+    method protected abstract void processBlock();
+    method public void update(byte[], int, int);
+  }
+
+  public class MD4Digest extends com.android.org.bouncycastle.crypto.digests.GeneralDigest {
+    ctor public MD4Digest();
+    method public int doFinal(byte[], int);
+    method protected void processBlock();
+  }
+
+  public class SHA1Digest extends com.android.org.bouncycastle.crypto.digests.GeneralDigest {
+    ctor public SHA1Digest();
+    method public int doFinal(byte[], int);
+    method protected void processBlock();
+  }
+
+}
+
 package com.android.org.bouncycastle.crypto.generators {
 
   public class OpenSSLPBEParametersGenerator extends com.android.org.bouncycastle.crypto.PBEParametersGenerator {
@@ -430,7 +404,7 @@
 package com.android.org.bouncycastle.jce {
 
   @Deprecated public class X509Principal extends com.android.org.bouncycastle.asn1.x509.X509Name implements java.security.Principal {
-    ctor @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public X509Principal(byte[]) throws java.io.IOException;
+    ctor @Deprecated public X509Principal(byte[]) throws java.io.IOException;
     ctor @Deprecated public X509Principal(java.util.Vector, java.util.Hashtable);
     method public byte[] getEncoded();
   }
@@ -440,11 +414,11 @@
 package com.android.org.bouncycastle.jce.provider {
 
   public final class BouncyCastleProvider extends java.security.Provider {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public BouncyCastleProvider();
+    ctor public BouncyCastleProvider();
   }
 
   @Deprecated public class X509CertificateObject extends java.security.cert.X509Certificate {
-    ctor @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public X509CertificateObject(com.android.org.bouncycastle.asn1.x509.Certificate) throws java.security.cert.CertificateParsingException;
+    ctor @Deprecated public X509CertificateObject(com.android.org.bouncycastle.asn1.x509.Certificate) throws java.security.cert.CertificateParsingException;
   }
 
 }
@@ -499,129 +473,38 @@
   }
 
   @Deprecated public class X509V3CertificateGenerator {
-    ctor @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public X509V3CertificateGenerator();
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public java.security.cert.X509Certificate generate(java.security.PrivateKey) throws java.security.cert.CertificateEncodingException, java.lang.IllegalStateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setIssuerDN(javax.security.auth.x500.X500Principal);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setNotAfter(java.util.Date);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setNotBefore(java.util.Date);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setPublicKey(java.security.PublicKey) throws java.lang.IllegalArgumentException;
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setSerialNumber(java.math.BigInteger);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setSignatureAlgorithm(String);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void setSubjectDN(javax.security.auth.x500.X500Principal);
+    ctor @Deprecated public X509V3CertificateGenerator();
+    method @Deprecated public java.security.cert.X509Certificate generate(java.security.PrivateKey) throws java.security.cert.CertificateEncodingException, java.lang.IllegalStateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
+    method @Deprecated public void setIssuerDN(javax.security.auth.x500.X500Principal);
+    method @Deprecated public void setNotAfter(java.util.Date);
+    method @Deprecated public void setNotBefore(java.util.Date);
+    method @Deprecated public void setPublicKey(java.security.PublicKey) throws java.lang.IllegalArgumentException;
+    method @Deprecated public void setSerialNumber(java.math.BigInteger);
+    method @Deprecated public void setSignatureAlgorithm(String);
+    method @Deprecated public void setSubjectDN(javax.security.auth.x500.X500Principal);
   }
 
 }
 
-package com.android.org.conscrypt {
+package dalvik.annotation.codegen {
 
-  public interface CertPinManager {
+  @java.lang.annotation.Repeatable(CovariantReturnType.CovariantReturnTypes.class) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface CovariantReturnType {
+    method public abstract int presentAfter();
+    method public abstract Class<?> returnType();
   }
 
-  public final class ClientSessionContext implements javax.net.ssl.SSLSessionContext {
-    method public final java.util.Enumeration<byte[]> getIds();
-    method public final javax.net.ssl.SSLSession getSession(byte[]);
-    method public final int getSessionCacheSize();
-    method public final int getSessionTimeout();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setPersistentCache(com.android.org.conscrypt.SSLClientSessionCache);
-    method public final void setSessionCacheSize(int) throws java.lang.IllegalArgumentException;
-    method public final void setSessionTimeout(int) throws java.lang.IllegalArgumentException;
-  }
-
-  public final class Conscrypt {
-    method public static javax.net.ssl.X509TrustManager getDefaultX509TrustManager() throws java.security.KeyManagementException;
-  }
-
-  public interface ConscryptCertStore {
-  }
-
-  public final class FileClientSessionCache {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static com.android.org.conscrypt.SSLClientSessionCache usingDirectory(java.io.File) throws java.io.IOException;
-  }
-
-  public final class OpenSSLProvider extends java.security.Provider {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public OpenSSLProvider();
-  }
-
-  public abstract class OpenSSLSocketImpl extends javax.net.ssl.SSLSocket {
-    method public void addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
-    method public final void connect(java.net.SocketAddress) throws java.io.IOException;
-    method public final void connect(java.net.SocketAddress, int) throws java.io.IOException;
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public final byte[] getAlpnSelectedProtocol();
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public final byte[] getNpnSelectedProtocol();
-    method public final int getPort();
-    method public final int getSoTimeout() throws java.net.SocketException;
-    method public void removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener);
-    method public final void sendUrgentData(int) throws java.io.IOException;
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public final void setAlpnProtocols(byte[]);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public abstract void setChannelIdPrivateKey(java.security.PrivateKey);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setHandshakeTimeout(int) throws java.net.SocketException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setHostname(String);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public final void setNpnProtocols(byte[]);
-    method public final void setOOBInline(boolean) throws java.net.SocketException;
-    method public final void setSoTimeout(int) throws java.net.SocketException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void setSoWriteTimeout(int) throws java.net.SocketException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public abstract void setUseSessionTickets(boolean);
-  }
-
-  public interface SSLClientSessionCache {
-  }
-
-  public final class TrustManagerImpl extends javax.net.ssl.X509ExtendedTrustManager {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public TrustManagerImpl(java.security.KeyStore);
-    ctor public TrustManagerImpl(java.security.KeyStore, com.android.org.conscrypt.CertPinManager, com.android.org.conscrypt.ConscryptCertStore);
-    method public void checkClientTrusted(java.security.cert.X509Certificate[], String) throws java.security.cert.CertificateException;
-    method public void checkClientTrusted(java.security.cert.X509Certificate[], String, java.net.Socket) throws java.security.cert.CertificateException;
-    method public void checkClientTrusted(java.security.cert.X509Certificate[], String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], String, String) throws java.security.cert.CertificateException;
-    method public java.util.List<java.security.cert.X509Certificate> getTrustedChainForServer(java.security.cert.X509Certificate[], String, java.net.Socket) throws java.security.cert.CertificateException;
-    method public java.util.List<java.security.cert.X509Certificate> getTrustedChainForServer(java.security.cert.X509Certificate[], String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
-    method public void handleTrustStorageUpdate();
-  }
-
-  public final class TrustedCertificateIndex {
-    ctor public TrustedCertificateIndex();
-    method public java.util.Set<java.security.cert.TrustAnchor> findAllByIssuerAndSignature(java.security.cert.X509Certificate);
-    method public java.security.cert.TrustAnchor findByIssuerAndSignature(java.security.cert.X509Certificate);
-    method public java.security.cert.TrustAnchor findBySubjectAndPublicKey(java.security.cert.X509Certificate);
-    method public java.security.cert.TrustAnchor index(java.security.cert.X509Certificate);
-  }
-
-  public class TrustedCertificateStore implements com.android.org.conscrypt.ConscryptCertStore {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public TrustedCertificateStore();
-    method public java.util.Set<java.lang.String> aliases();
-    method public java.util.Set<java.lang.String> allSystemAliases();
-    method public boolean containsAlias(String);
-    method public void deleteCertificateEntry(String) throws java.security.cert.CertificateException, java.io.IOException;
-    method public java.util.Set<java.security.cert.X509Certificate> findAllIssuers(java.security.cert.X509Certificate);
-    method public java.security.cert.X509Certificate findIssuer(java.security.cert.X509Certificate);
-    method public java.security.cert.Certificate getCertificate(String);
-    method public java.security.cert.Certificate getCertificate(String, boolean);
-    method public String getCertificateAlias(java.security.cert.Certificate);
-    method public String getCertificateAlias(java.security.cert.Certificate, boolean);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public java.util.List<java.security.cert.X509Certificate> getCertificateChain(java.security.cert.X509Certificate) throws java.security.cert.CertificateException;
-    method public java.io.File getCertificateFile(java.io.File, java.security.cert.X509Certificate);
-    method public java.util.Date getCreationDate(String);
-    method public java.security.cert.X509Certificate getTrustAnchor(java.security.cert.X509Certificate);
-    method public void installCertificate(java.security.cert.X509Certificate) throws java.security.cert.CertificateException, java.io.IOException;
-    method public static final boolean isUser(String);
-    method public boolean isUserAddedCertificate(java.security.cert.X509Certificate);
-    method public static void setDefaultUserDirectory(java.io.File);
-    method public java.util.Set<java.lang.String> userAliases();
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public static @interface CovariantReturnType.CovariantReturnTypes {
+    method public abstract dalvik.annotation.codegen.CovariantReturnType[] value();
   }
 
 }
 
 package dalvik.annotation.compat {
 
-  @java.lang.annotation.Repeatable(UnsupportedAppUsage.Container.class) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.TYPE}) public @interface UnsupportedAppUsage {
-    method public abstract String expectedSignature() default "";
-    method public abstract String implicitMember() default "";
-    method public abstract int maxTargetSdk() default java.lang.Integer.MAX_VALUE;
-    method public abstract long trackingBug() default 0;
-  }
-
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public static @interface UnsupportedAppUsage.Container {
-    method public abstract dalvik.annotation.compat.UnsupportedAppUsage[] value();
+  public class VersionCodes {
+    field public static final int O = 26; // 0x1a
+    field public static final int P = 28; // 0x1c
+    field public static final int Q = 29; // 0x1d
   }
 
 }
@@ -645,28 +528,29 @@
   }
 
   public class BaseDexClassLoader extends java.lang.ClassLoader {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void addDexPath(String);
+    method public void addDexPath(String);
     method public void addNativePath(java.util.Collection<java.lang.String>);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public String getLdLibraryPath();
+    method public String getLdLibraryPath();
+    method public void reportClassLoaderChain();
     method public static void setReporter(dalvik.system.BaseDexClassLoader.Reporter);
   }
 
   public static interface BaseDexClassLoader.Reporter {
-    method public void report(java.util.List<java.lang.ClassLoader>, java.util.List<java.lang.String>);
+    method public void report(java.util.Map<java.lang.String,java.lang.String>);
   }
 
   public final class BlockGuard {
-    method @NonNull @dalvik.annotation.compat.UnsupportedAppUsage public static dalvik.system.BlockGuard.Policy getThreadPolicy();
+    method @NonNull public static dalvik.system.BlockGuard.Policy getThreadPolicy();
     method @NonNull public static dalvik.system.BlockGuard.VmPolicy getVmPolicy();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void setThreadPolicy(@NonNull dalvik.system.BlockGuard.Policy);
+    method public static void setThreadPolicy(@NonNull dalvik.system.BlockGuard.Policy);
     method public static void setVmPolicy(@NonNull dalvik.system.BlockGuard.VmPolicy);
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final dalvik.system.BlockGuard.Policy LAX_POLICY;
+    field public static final dalvik.system.BlockGuard.Policy LAX_POLICY;
     field public static final dalvik.system.BlockGuard.VmPolicy LAX_VM_POLICY;
   }
 
   public static interface BlockGuard.Policy {
     method public int getPolicyMask();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void onReadFromDisk();
+    method public void onReadFromDisk();
     method public void onUnbufferedIO();
     method public void onWriteToDisk();
   }
@@ -676,17 +560,19 @@
   }
 
   public final class CloseGuard {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void close();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static dalvik.system.CloseGuard get();
+    method public void close();
+    method public static dalvik.system.CloseGuard get();
     method public static dalvik.system.CloseGuard.Reporter getReporter();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void open(String);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void setEnabled(boolean);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void setReporter(dalvik.system.CloseGuard.Reporter);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void warnIfOpen();
+    method public void open(String);
+    method public void openWithCallSite(String, String);
+    method public static void setEnabled(boolean);
+    method public static void setReporter(dalvik.system.CloseGuard.Reporter);
+    method public void warnIfOpen();
   }
 
   public static interface CloseGuard.Reporter {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void report(String, Throwable);
+    method public void report(String, Throwable);
+    method public default void report(String);
   }
 
   public interface DalvikLogHandler {
@@ -730,22 +616,28 @@
   }
 
   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);
   }
 
   public abstract class SocketTagger {
     ctor public SocketTagger();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static dalvik.system.SocketTagger get();
+    method public static dalvik.system.SocketTagger get();
     method public static void set(dalvik.system.SocketTagger);
     method public abstract void tag(java.io.FileDescriptor) throws java.net.SocketException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public final void tag(java.net.Socket) throws java.net.SocketException;
+    method public final void tag(java.net.Socket) throws java.net.SocketException;
     method public final void tag(java.net.DatagramSocket) throws java.net.SocketException;
     method public abstract void untag(java.io.FileDescriptor) throws java.net.SocketException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public final void untag(java.net.Socket) throws java.net.SocketException;
+    method public final void untag(java.net.Socket) throws java.net.SocketException;
     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);
@@ -754,14 +646,14 @@
     method public static void dumpHprofData(String) throws java.io.IOException;
     method public static void dumpHprofData(String, java.io.FileDescriptor) throws java.io.IOException;
     method public static void dumpHprofDataDdms();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void dumpReferenceTables();
+    method public static void dumpReferenceTables();
     method public static int getAllocCount(int);
     method @dalvik.annotation.optimization.FastNative public static int getLoadedClassCount();
     method public static int getMethodTracingMode();
     method public static String getRuntimeStat(String);
     method public static java.util.Map<java.lang.String,java.lang.String> getRuntimeStats();
     method public static String[] getVmFeatureList();
-    method @dalvik.annotation.compat.UnsupportedAppUsage @dalvik.annotation.optimization.FastNative public static boolean isDebuggerConnected();
+    method @dalvik.annotation.optimization.FastNative public static boolean isDebuggerConnected();
     method @dalvik.annotation.optimization.FastNative public static boolean isDebuggingEnabled();
     method @dalvik.annotation.optimization.FastNative public static long lastDebuggerActivity();
     method @dalvik.annotation.optimization.FastNative public static void printLoadedClasses(int);
@@ -791,47 +683,51 @@
   }
 
   public final class VMRuntime {
-    method @dalvik.annotation.compat.UnsupportedAppUsage @dalvik.annotation.optimization.FastNative public long addressOf(Object);
+    method @dalvik.annotation.optimization.FastNative public long addressOf(Object);
+    method public static void bootCompleted();
     method public void clampGrowthLimit();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void clearGrowthLimit();
+    method public void clearGrowthLimit();
     method public static boolean didPruneDalvikCache();
     method public void disableJitCompilation();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static String getCurrentInstructionSet();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static String getInstructionSet(String);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static dalvik.system.VMRuntime getRuntime();
+    method public static String getCurrentInstructionSet();
+    method public static String getInstructionSet(String);
+    method public static dalvik.system.VMRuntime getRuntime();
     method public float getTargetHeapUtilization();
     method public int getTargetSdkVersion();
     method @dalvik.annotation.optimization.FastNative public static boolean hasBootImageSpaces();
-    method @dalvik.annotation.compat.UnsupportedAppUsage @dalvik.annotation.optimization.FastNative public boolean is64Bit();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static boolean is64BitAbi(String);
+    method @dalvik.annotation.optimization.FastNative public boolean is64Bit();
+    method public static boolean is64BitAbi(String);
     method public static boolean is64BitInstructionSet(String);
     method public static boolean isBootClassPathOnDisk(String);
     method @dalvik.annotation.optimization.FastNative public boolean isCheckJniEnabled();
     method @dalvik.annotation.optimization.FastNative public boolean isNativeDebuggable();
-    method @dalvik.annotation.compat.UnsupportedAppUsage @dalvik.annotation.optimization.FastNative public Object newNonMovableArray(Class<?>, int);
+    method public static boolean isValidClassLoaderContext(String);
+    method @dalvik.annotation.optimization.FastNative public Object newNonMovableArray(Class<?>, int);
     method @dalvik.annotation.optimization.FastNative public Object newUnpaddedArray(Class<?>, int);
     method public void notifyStartupCompleted();
     method public void preloadDexCaches();
     method public static void registerAppInfo(String, String[]);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void registerNativeAllocation(long);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void registerNativeAllocation(int);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void registerNativeFree(long);
-    method @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage public void registerNativeFree(int);
+    method public void registerNativeAllocation(long);
+    method @Deprecated public void registerNativeAllocation(int);
+    method public void registerNativeFree(long);
+    method @Deprecated public void registerNativeFree(int);
     method public static void registerSensitiveThread();
     method public void requestConcurrentGC();
+    method public static void resetJitCounters();
     method public static void setDedupeHiddenApiWarnings(boolean);
+    method public void setDisabledCompatChanges(long[]);
     method public void setHiddenApiAccessLogSamplingRate(int);
     method public void setHiddenApiExemptions(String[]);
     method public static void setHiddenApiUsageLogger(dalvik.system.VMRuntime.HiddenApiUsageLogger);
     method public static void setNonSdkApiUsageConsumer(java.util.function.Consumer<java.lang.String>);
     method public static void setProcessDataDirectory(String);
     method public static void setProcessPackageName(String);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public float setTargetHeapUtilization(float);
+    method public float setTargetHeapUtilization(float);
     method public void setTargetSdkVersion(int);
     method public void startJitCompilation();
     method public void updateProcessState(int);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public String vmInstructionSet();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public String vmLibrary();
+    method public String vmInstructionSet();
+    method public String vmLibrary();
     field public static final int SDK_VERSION_CUR_DEVELOPMENT = 10000; // 0x2710
   }
 
@@ -847,18 +743,13 @@
     method @dalvik.annotation.optimization.FastNative public static dalvik.system.AnnotatedStackTraceElement[] getAnnotatedThreadStackTrace(Thread);
   }
 
-  public class VersionCodes {
-    field public static final int O = 26; // 0x1a
-    field public static final int P = 28; // 0x1c
-  }
-
   public final class ZygoteHooks {
     method public static void gcAndFinalize();
     method public static void onBeginPreload();
     method public static void onEndPreload();
     method public static void postForkChild(int, boolean, boolean, String);
     method public static void postForkCommon();
-    method public static void postForkSystemServer();
+    method public static void postForkSystemServer(int);
     method public static void preFork();
     method public static void startZygoteNoThreadCreation();
     method public static void stopZygoteNoThreadCreation();
@@ -881,10 +772,6 @@
 
 package java.lang {
 
-  public final class Byte extends java.lang.Number implements java.lang.Comparable<java.lang.Byte> {
-    method public static String toHexString(byte, boolean);
-  }
-
   public final class Class<T> implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
     method @dalvik.annotation.optimization.FastNative public java.lang.reflect.Field[] getDeclaredFieldsUnchecked(boolean);
     method @dalvik.annotation.optimization.FastNative public java.lang.reflect.Method[] getDeclaredMethodsUnchecked(boolean);
@@ -966,10 +853,15 @@
     method public final void setAccessible(boolean);
   }
 
+  public final class NIOAccess {
+    method public static Object getBaseArray(java.nio.Buffer);
+    method public static int getBaseArrayOffset(java.nio.Buffer);
+  }
+
   public final class NioUtils {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void freeDirectBuffer(java.nio.ByteBuffer);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static byte[] unsafeArray(java.nio.ByteBuffer);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static int unsafeArrayOffset(java.nio.ByteBuffer);
+    method public static void freeDirectBuffer(java.nio.ByteBuffer);
+    method public static byte[] unsafeArray(java.nio.ByteBuffer);
+    method public static int unsafeArrayOffset(java.nio.ByteBuffer);
   }
 
 }
@@ -1035,45 +927,73 @@
 
 }
 
+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 {
+    method public libcore.content.type.MimeMap.Builder buildUpon();
+    method public static libcore.content.type.MimeMap.Builder builder();
+    method @NonNull public java.util.Set<java.lang.String> extensions();
+    method @NonNull public static libcore.content.type.MimeMap getDefault();
+    method @Nullable public String guessExtensionFromMimeType(@Nullable String);
+    method @Nullable public String guessMimeTypeFromExtension(@Nullable String);
+    method public boolean hasExtension(@Nullable String);
+    method public boolean hasMimeType(@Nullable String);
+    method @NonNull public java.util.Set<java.lang.String> mimeTypes();
+    method public static void setDefaultSupplier(@NonNull java.util.function.Supplier<libcore.content.type.MimeMap>);
+  }
+
+  public static final class MimeMap.Builder {
+    method public libcore.content.type.MimeMap build();
+    method public libcore.content.type.MimeMap.Builder put(@NonNull String, @NonNull java.util.List<java.lang.String>);
+  }
+
+}
+
 package libcore.icu {
 
   public final class DateIntervalFormat {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static String formatDateRange(long, long, int, String);
+    method public static String formatDateRange(long, long, int, String);
   }
 
   public final class ICU {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static java.util.Locale addLikelySubtags(java.util.Locale);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static String getBestDateTimePattern(String, java.util.Locale);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static char[] getDateFormatOrder(String);
-    method public static String getTZDataVersion();
+    method public static String getBestDateTimePattern(String, java.util.Locale);
+    method public static char[] getDateFormatOrder(String);
   }
 
   public final class LocaleData {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static libcore.icu.LocaleData get(java.util.Locale);
+    method public static libcore.icu.LocaleData get(java.util.Locale);
     method public String getDateFormat(int);
     field public String[] amPm;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public Integer firstDayOfWeek;
+    field public Integer firstDayOfWeek;
     field public String[] longMonthNames;
     field public String[] longStandAloneMonthNames;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public String[] longStandAloneWeekdayNames;
+    field public String[] longStandAloneWeekdayNames;
     field public String[] longWeekdayNames;
     field public String narrowAm;
     field public String narrowPm;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public String[] shortMonthNames;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public String[] shortStandAloneMonthNames;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public String[] shortStandAloneWeekdayNames;
+    field public String[] shortMonthNames;
+    field public String[] shortStandAloneMonthNames;
+    field public String[] shortStandAloneWeekdayNames;
     field public String[] shortWeekdayNames;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public String timeFormat_Hm;
+    field public String timeFormat_Hm;
     field public String timeFormat_Hms;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public String timeFormat_hm;
+    field public String timeFormat_hm;
     field public String timeFormat_hms;
     field public String[] tinyMonthNames;
     field public String[] tinyStandAloneMonthNames;
     field public String[] tinyStandAloneWeekdayNames;
     field public String[] tinyWeekdayNames;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public String today;
+    field public String today;
     field public String yesterday;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public char zeroDigit;
+    field public char zeroDigit;
   }
 
   public final class RelativeDateTimeFormatter {
@@ -1095,13 +1015,13 @@
 package libcore.io {
 
   public class ForwardingOs implements libcore.io.Os {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage protected ForwardingOs(libcore.io.Os);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public boolean access(String, int) throws android.system.ErrnoException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public java.io.FileDescriptor open(String, int, int) throws android.system.ErrnoException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void remove(String) throws android.system.ErrnoException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void rename(String, String) throws android.system.ErrnoException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public android.system.StructStat stat(String) throws android.system.ErrnoException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public void unlink(String) throws android.system.ErrnoException;
+    ctor protected ForwardingOs(libcore.io.Os);
+    method public boolean access(String, int) throws android.system.ErrnoException;
+    method public java.io.FileDescriptor open(String, int, int) throws android.system.ErrnoException;
+    method public void remove(String) throws android.system.ErrnoException;
+    method public void rename(String, String) throws android.system.ErrnoException;
+    method public android.system.StructStat stat(String) throws android.system.ErrnoException;
+    method public void unlink(String) throws android.system.ErrnoException;
   }
 
   public final class IoBridge {
@@ -1118,14 +1038,13 @@
   public final class IoUtils {
     method public static int acquireRawFd(@NonNull java.io.FileDescriptor);
     method public static void close(java.io.FileDescriptor) throws java.io.IOException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void closeQuietly(AutoCloseable);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void closeQuietly(java.io.FileDescriptor);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void closeQuietly(java.net.Socket);
-    method @Deprecated public static java.io.File createTemporaryDirectory(String);
+    method public static void closeQuietly(AutoCloseable);
+    method public static void closeQuietly(java.io.FileDescriptor);
+    method public static void closeQuietly(java.net.Socket);
     method @Deprecated public static void deleteContents(java.io.File) throws java.io.IOException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static byte[] readFileAsByteArray(String) throws java.io.IOException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static String readFileAsString(String) throws java.io.IOException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void setBlocking(java.io.FileDescriptor, boolean) throws java.io.IOException;
+    method public static byte[] readFileAsByteArray(String) throws java.io.IOException;
+    method public static String readFileAsString(String) throws java.io.IOException;
+    method public static void setBlocking(java.io.FileDescriptor, boolean) throws java.io.IOException;
     method public static void setFdOwner(@NonNull java.io.FileDescriptor, @NonNull Object);
   }
 
@@ -1144,14 +1063,14 @@
   }
 
   public final class Streams {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static int copy(java.io.InputStream, java.io.OutputStream) throws java.io.IOException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void readFully(java.io.InputStream, byte[]) throws java.io.IOException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static byte[] readFully(java.io.InputStream) throws java.io.IOException;
+    method public static int copy(java.io.InputStream, java.io.OutputStream) throws java.io.IOException;
+    method public static void readFully(java.io.InputStream, byte[]) throws java.io.IOException;
+    method public static byte[] readFully(java.io.InputStream) throws java.io.IOException;
     method public static String readFully(java.io.Reader) throws java.io.IOException;
     method public static byte[] readFullyNoClose(java.io.InputStream) throws java.io.IOException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static int readSingleByte(java.io.InputStream) throws java.io.IOException;
+    method public static int readSingleByte(java.io.InputStream) throws java.io.IOException;
     method public static long skipByReading(java.io.InputStream, long) throws java.io.IOException;
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void writeSingleByte(java.io.OutputStream, int) throws java.io.IOException;
+    method public static void writeSingleByte(java.io.OutputStream, int) throws java.io.IOException;
   }
 
 }
@@ -1163,18 +1082,11 @@
     method public static java.net.InetAddress parseNumericAddress(String);
   }
 
-  public final class MimeUtils {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static String guessExtensionFromMimeType(String);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static String guessMimeTypeFromExtension(String);
-    method public static boolean hasExtension(String);
-    method public static boolean hasMimeType(String);
-  }
-
   public abstract class NetworkSecurityPolicy {
     ctor public NetworkSecurityPolicy();
     method public static libcore.net.NetworkSecurityPolicy getInstance();
     method public abstract boolean isCertificateTransparencyVerificationRequired(String);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public abstract boolean isCleartextTrafficPermitted();
+    method public abstract boolean isCleartextTrafficPermitted();
     method public abstract boolean isCleartextTrafficPermitted(String);
     method public static void setInstance(libcore.net.NetworkSecurityPolicy);
   }
@@ -1184,7 +1096,7 @@
 package libcore.net.event {
 
   public class NetworkEventDispatcher {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static libcore.net.event.NetworkEventDispatcher getInstance();
+    method public static libcore.net.event.NetworkEventDispatcher getInstance();
     method public void onNetworkConfigurationChanged();
   }
 
@@ -1194,24 +1106,28 @@
 
   public final class CountryTimeZones {
     method public String getCountryIso();
+    method public android.icu.util.TimeZone getDefaultTimeZone();
     method public String getDefaultTimeZoneId();
+    method public java.util.List<libcore.timezone.CountryTimeZones.TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long);
     method public java.util.List<libcore.timezone.CountryTimeZones.TimeZoneMapping> getTimeZoneMappings();
     method public boolean hasUtcZone(long);
-    method public boolean isDefaultOkForCountryTimeZoneDetection(long);
+    method public boolean isDefaultTimeZoneBoosted();
     method public boolean isForCountryCode(String);
-    method @Deprecated public libcore.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(int, boolean, long, android.icu.util.TimeZone);
+    method public libcore.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(long, android.icu.util.TimeZone, int, boolean);
+    method public libcore.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(long, android.icu.util.TimeZone, int);
   }
 
   public static final class CountryTimeZones.OffsetResult {
-    field public final boolean mOneMatch;
-    field public final android.icu.util.TimeZone mTimeZone;
+    method public android.icu.util.TimeZone getTimeZone();
+    method public boolean isOnlyMatch();
   }
 
   public static final class CountryTimeZones.TimeZoneMapping {
     method public static libcore.timezone.CountryTimeZones.TimeZoneMapping createForTests(String, boolean, Long);
-    field public final Long notUsedAfter;
-    field public final boolean showInPicker;
-    field public final String timeZoneId;
+    method public Long getNotUsedAfter();
+    method public android.icu.util.TimeZone getTimeZone();
+    method public String getTimeZoneId();
+    method public boolean isShownInPicker();
   }
 
   public final class CountryZonesFinder {
@@ -1220,10 +1136,27 @@
     method public java.util.List<libcore.timezone.CountryTimeZones> lookupCountryTimeZonesForZoneId(String);
   }
 
+  public final class TelephonyLookup {
+    method public static libcore.timezone.TelephonyLookup createInstance(String) throws java.io.IOException;
+    method public static libcore.timezone.TelephonyLookup getInstance();
+    method public libcore.timezone.TelephonyNetworkFinder getTelephonyNetworkFinder();
+    method public void validate() throws java.io.IOException;
+  }
+
+  public final class TelephonyNetwork {
+    method public String getCountryIsoCode();
+    method public String getMcc();
+    method public String getMnc();
+  }
+
+  public final class TelephonyNetworkFinder {
+    method public libcore.timezone.TelephonyNetwork findNetworkByMccMnc(String, String);
+  }
+
   public final class TimeZoneDataFiles {
     method public static String getDataTimeZoneFile(String);
     method public static String getDataTimeZoneRootDir();
-    method public static String getRuntimeModuleTzVersionFile();
+    method public static String getTimeZoneModuleTzVersionFile();
   }
 
   public final class TimeZoneFinder {
@@ -1232,22 +1165,22 @@
     method public String getIanaVersion();
     method public static libcore.timezone.TimeZoneFinder getInstance();
     method public libcore.timezone.CountryTimeZones lookupCountryTimeZones(String);
-    method public String lookupDefaultTimeZoneIdByCountry(String);
-    method public android.icu.util.TimeZone lookupTimeZoneByCountryAndOffset(String, int, boolean, long, android.icu.util.TimeZone);
-    method public java.util.List<java.lang.String> lookupTimeZoneIdsByCountry(String);
-    method public java.util.List<android.icu.util.TimeZone> lookupTimeZonesByCountry(String);
     method public void validate() throws java.io.IOException;
   }
 
-  public class TzDataSetVersion {
+  public final class TzDataSetVersion {
     ctor public TzDataSetVersion(int, int, String, int) throws libcore.timezone.TzDataSetVersion.TzDataSetException;
     method public static int currentFormatMajorVersion();
     method public static int currentFormatMinorVersion();
+    method public int getFormatMajorVersion();
+    method public int getFormatMinorVersion();
+    method public int getRevision();
+    method public String getRulesVersion();
     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 String rulesVersion;
   }
 
   public static class TzDataSetVersion.TzDataSetException extends java.lang.Exception {
@@ -1255,14 +1188,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;
   }
@@ -1294,21 +1224,66 @@
 
   public final class EmptyArray {
     field public static final boolean[] BOOLEAN;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final byte[] BYTE;
+    field public static final byte[] BYTE;
     field public static final float[] FLOAT;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final int[] INT;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final long[] LONG;
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final Object[] OBJECT;
+    field public static final int[] INT;
+    field public static final long[] LONG;
+    field public static final Object[] OBJECT;
     field public static final String[] STRING;
   }
 
+  public class FP16 {
+    method public static short ceil(short);
+    method public static int compare(short, short);
+    method public static boolean equals(short, short);
+    method public static short floor(short);
+    method public static boolean greater(short, short);
+    method public static boolean greaterEquals(short, short);
+    method public static boolean isInfinite(short);
+    method public static boolean isNaN(short);
+    method public static boolean isNormalized(short);
+    method public static boolean less(short, short);
+    method public static boolean lessEquals(short, short);
+    method public static short max(short, short);
+    method public static short min(short, short);
+    method public static short rint(short);
+    method public static float toFloat(short);
+    method public static short toHalf(float);
+    method public static String toHexString(short);
+    method public static short trunc(short);
+    field public static final short EPSILON = 5120; // 0x1400
+    field public static final int EXPONENT_BIAS = 15; // 0xf
+    field public static final int EXPONENT_SHIFT = 10; // 0xa
+    field public static final int EXPONENT_SIGNIFICAND_MASK = 32767; // 0x7fff
+    field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+    field public static final int MAX_EXPONENT = 15; // 0xf
+    field public static final short MAX_VALUE = 31743; // 0x7bff
+    field public static final int MIN_EXPONENT = -14; // 0xfffffff2
+    field public static final short MIN_NORMAL = 1024; // 0x400
+    field public static final short MIN_VALUE = 1; // 0x1
+    field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+    field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+    field public static final short NaN = 32256; // 0x7e00
+    field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+    field public static final short POSITIVE_ZERO = 0; // 0x0
+    field public static final int SHIFTED_EXPONENT_MASK = 31; // 0x1f
+    field public static final int SIGNIFICAND_MASK = 1023; // 0x3ff
+    field public static final int SIGN_MASK = 32768; // 0x8000
+    field public static final int SIGN_SHIFT = 15; // 0xf
+    field public static final int SIZE = 16; // 0x10
+  }
+
   public class HexEncoding {
     method public static byte[] decode(String) throws java.lang.IllegalArgumentException;
+    method public static byte[] decode(String, boolean) throws java.lang.IllegalArgumentException;
     method public static byte[] decode(char[]) throws java.lang.IllegalArgumentException;
     method public static byte[] decode(char[], boolean) throws java.lang.IllegalArgumentException;
     method public static char[] encode(byte[]);
+    method public static char[] encode(byte[], boolean);
     method public static char[] encode(byte[], int, int);
+    method public static String encodeToString(byte, boolean);
     method public static String encodeToString(byte[]);
+    method public static String encodeToString(byte[], boolean);
   }
 
   public class NativeAllocationRegistry {
@@ -1391,7 +1366,7 @@
 
   public class Chunk {
     ctor public Chunk(int, byte[], int, int);
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage public Chunk(int, java.nio.ByteBuffer);
+    ctor public Chunk(int, java.nio.ByteBuffer);
     field public int type;
   }
 
@@ -1406,21 +1381,21 @@
     method public static void putString(java.nio.ByteBuffer, String);
     method public static int type(String);
     method public static java.nio.ByteBuffer wrapChunk(org.apache.harmony.dalvik.ddmc.Chunk);
-    field @dalvik.annotation.compat.UnsupportedAppUsage public static final java.nio.ByteOrder CHUNK_ORDER;
+    field public static final java.nio.ByteOrder CHUNK_ORDER;
   }
 
   public class DdmServer {
     method public static void registerHandler(int, org.apache.harmony.dalvik.ddmc.ChunkHandler);
     method public static void registrationComplete();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static void sendChunk(org.apache.harmony.dalvik.ddmc.Chunk);
+    method public static void sendChunk(org.apache.harmony.dalvik.ddmc.Chunk);
   }
 
   public class DdmVmInternal {
     method public static void enableRecentAllocations(boolean);
     method @dalvik.annotation.optimization.FastNative public static boolean getRecentAllocationStatus();
     method @dalvik.annotation.optimization.FastNative public static byte[] getRecentAllocations();
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static StackTraceElement[] getStackTraceById(int);
-    method @dalvik.annotation.compat.UnsupportedAppUsage public static byte[] getThreadStats();
+    method public static StackTraceElement[] getStackTraceById(int);
+    method public static byte[] getThreadStats();
     method @dalvik.annotation.optimization.FastNative public static boolean heapInfoNotify(int);
     method public static boolean heapSegmentNotify(int, int, boolean);
     method public static void threadNotify(boolean);
@@ -1431,7 +1406,7 @@
 package org.json {
 
   public class JSONObject {
-    method @dalvik.annotation.compat.UnsupportedAppUsage public java.util.Set<java.lang.String> keySet();
+    method public java.util.Set<java.lang.String> keySet();
   }
 
 }
@@ -1445,14 +1420,30 @@
 
   public final class Unsafe {
     method public int arrayBaseOffset(Class);
+    method public int arrayIndexScale(Class);
+    method @dalvik.annotation.optimization.FastNative public void copyMemory(long, long, long);
+    method @dalvik.annotation.optimization.FastNative public boolean getBoolean(Object, long);
     method @dalvik.annotation.optimization.FastNative public byte getByte(Object, long);
     method @dalvik.annotation.optimization.FastNative public byte getByte(long);
+    method @dalvik.annotation.optimization.FastNative public double getDouble(Object, long);
+    method @dalvik.annotation.optimization.FastNative public float getFloat(Object, long);
+    method @dalvik.annotation.optimization.FastNative public int getInt(Object, long);
+    method @dalvik.annotation.optimization.FastNative public int getInt(long);
     method @dalvik.annotation.optimization.FastNative public long getLong(Object, long);
     method @dalvik.annotation.optimization.FastNative public long getLong(long);
+    method @dalvik.annotation.optimization.FastNative public Object getObject(Object, long);
     method public static sun.misc.Unsafe getUnsafe();
     method public long objectFieldOffset(java.lang.reflect.Field);
+    method @dalvik.annotation.optimization.FastNative public void putBoolean(Object, long, boolean);
     method @dalvik.annotation.optimization.FastNative public void putByte(Object, long, byte);
     method @dalvik.annotation.optimization.FastNative public void putByte(long, byte);
+    method @dalvik.annotation.optimization.FastNative public void putDouble(Object, long, double);
+    method @dalvik.annotation.optimization.FastNative public void putFloat(Object, long, float);
+    method @dalvik.annotation.optimization.FastNative public void putInt(Object, long, int);
+    method @dalvik.annotation.optimization.FastNative public void putInt(long, int);
+    method @dalvik.annotation.optimization.FastNative public void putLong(Object, long, long);
+    method @dalvik.annotation.optimization.FastNative public void putLong(long, long);
+    method @dalvik.annotation.optimization.FastNative public void putObject(Object, long, Object);
   }
 
 }
diff --git a/mmodules/intracoreapi/Android.bp b/mmodules/intracoreapi/Android.bp
index a07f540..c2a3de3 100644
--- a/mmodules/intracoreapi/Android.bp
+++ b/mmodules/intracoreapi/Android.bp
@@ -12,22 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Build rules for the APIs that the various core libraries can depend on from
-// each other: public SDK APIs and "intra-core" APIs. Intra-core APIs are not
-// for use by other parts of the Android software stack.
-
-// Generates stub source files for the {public SDK + intra-core} API
-// of the core jars.
+// Generates stub source files for the intra-core API of the ART module.
+// i.e. every class/member that is either in the public API or annotated with
+// @IntraCoreApi.
+//
+// The API specification .txt files managed by this only contain the additional
+// classes/members that are in the intra-core API but which are not in the public
+// API.
 droidstubs {
-    name: "core-intra-stubs",
-    srcs: [":core_api_files"],
-    no_standard_libs: true,
-    libs: ["core-all"],
+    name: "art-module-intra-core-api-stubs-source",
+    srcs: [
+        ":art_module_api_files",
+    ],
+    sdk_version: "none",
+    system_modules: "none",
 
     installable: false,
-    args: "--hide-annotation libcore.api.Hide "
-        + "--show-single-annotation libcore.api.IntraCoreApi "
-        + "--skip-annotation-instance-methods=false ",
+    args: "--hide-annotation libcore.api.Hide " +
+        "--show-single-annotation libcore.api.IntraCoreApi " +
+        "--skip-annotation-instance-methods=false ",
     merge_inclusion_annotations_dirs: ["ojluni-annotated-mmodule-stubs"],
 
     api_filename: "api.txt",
@@ -45,51 +48,33 @@
     },
 }
 
-// A library containing the {public SDK + intra-core} API stubs for the
-// core jars.
+// A library containing the intra-core API stubs of the ART module.
+//
+// Intra-core APIs are only intended for the use of other core library modules.
 java_library {
-    name: "core.intra.stubs",
-    srcs: [":core-intra-stubs"],
-
-    no_standard_libs: true,
-    libs: ["core-all"],
-    system_modules: "core-all-system-modules",
-    openjdk9: {
-        javacflags: ["--patch-module=java.base=."],
-    },
-}
-
-// Used when compiling against core.intra.stubs.
-java_system_modules {
-    name: "core-intra-stubs-system-modules",
-    libs: ["core.intra.stubs"],
-}
-
-// A rule that checks we can build core-libart and core-oj using only the source
-// for core-libart and core-oj and the APIs in core-intra-stubs. This proves we
-// don't actually depend on things from (for example) conscrypt we haven't added
-// to the intra-core API.
-java_library {
-    name: "core-libart-oj.depscheck",
-    srcs: [
-        ":core_libart_java_files",
-        ":core_oj_java_files",
+    name: "art.module.intra.core.api.stubs",
+    visibility: [
+        "//libcore/mmodules/core_platform_api",
     ],
-    errorprone: {
-        javacflags: [
-            "-Xep:MissingOverride:OFF",  // Ignore missing @Override.
-            "-Xep:ConstantOverflow:WARN",  // Known constant overflow in SplittableRandom
-        ],
-    },
+    srcs: [
+        ":art-module-intra-core-api-stubs-source",
+        ":openjdk_lambda_stub_files",
+        ":openjdk_generated_annotation_stub_files",
+    ],
 
-    installable: false,
-
-    no_standard_libs: true,
-    libs: ["core.intra.stubs"],
-    system_modules: "core-intra-stubs-system-modules",
-    java_version: "1.9",
-    openjdk9: {
-        javacflags: ["--patch-module=java.base=."],
-    },
+    sdk_version: "none",
+    system_modules: "none",
+    patch_module: "java.base",
 }
 
+// Used when compiling against art.module.intra.core.api.stubs.
+java_system_modules {
+    name: "art-module-intra-core-api-stubs-system-modules",
+    visibility: [
+        "//art/build/sdk",
+        "//external/bouncycastle",
+        "//external/conscrypt",
+        "//external/icu/android_icu4j",
+    ],
+    libs: ["art.module.intra.core.api.stubs"],
+}
diff --git a/mmodules/intracoreapi/api/intra/current-api.txt b/mmodules/intracoreapi/api/intra/current-api.txt
index a7a2fdc..5137a10 100644
--- a/mmodules/intracoreapi/api/intra/current-api.txt
+++ b/mmodules/intracoreapi/api/intra/current-api.txt
@@ -1,415 +1,37 @@
 // Signature format: 2.0
-package android.system {
+package android.compat {
 
-  public final class ErrnoException extends java.lang.Exception {
-    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public java.net.SocketException rethrowAsSocketException() throws java.net.SocketException;
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public final class Compatibility {
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static boolean isChangeEnabled(long);
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static void reportChange(long);
   }
 
-}
-
-package com.android.org.conscrypt {
-
-  @libcore.api.IntraCoreApi public class DESEDESecretKeyFactory extends javax.crypto.SecretKeyFactorySpi {
-    ctor @libcore.api.IntraCoreApi public DESEDESecretKeyFactory();
-  }
-
-  @libcore.api.IntraCoreApi public final class DefaultSSLContextImpl extends com.android.org.conscrypt.OpenSSLContextImpl {
-    ctor @libcore.api.IntraCoreApi public DefaultSSLContextImpl() throws java.security.GeneralSecurityException, java.io.IOException;
-  }
-
-  @libcore.api.IntraCoreApi public class ECParameters extends java.security.AlgorithmParametersSpi {
-    ctor @libcore.api.IntraCoreApi public ECParameters();
-  }
-
-  @libcore.api.IntraCoreApi public final class GCMParameters extends java.security.AlgorithmParametersSpi {
-    ctor @libcore.api.IntraCoreApi public GCMParameters();
-  }
-
-  @libcore.api.IntraCoreApi public class IvParameters extends java.security.AlgorithmParametersSpi {
-    ctor @libcore.api.IntraCoreApi public IvParameters();
-  }
-
-  @libcore.api.IntraCoreApi public static class IvParameters.AES extends com.android.org.conscrypt.IvParameters {
-    ctor @libcore.api.IntraCoreApi public IvParameters.AES();
-  }
-
-  @libcore.api.IntraCoreApi public static class IvParameters.ChaCha20 extends com.android.org.conscrypt.IvParameters {
-    ctor @libcore.api.IntraCoreApi public IvParameters.ChaCha20();
-  }
-
-  @libcore.api.IntraCoreApi public static class IvParameters.DESEDE extends com.android.org.conscrypt.IvParameters {
-    ctor @libcore.api.IntraCoreApi public IvParameters.DESEDE();
-  }
-
-  @libcore.api.IntraCoreApi public abstract class KeyGeneratorImpl extends javax.crypto.KeyGeneratorSpi {
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.AES extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.AES();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.ARC4 extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.ARC4();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.ChaCha20 extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.ChaCha20();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.DESEDE extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.DESEDE();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.HmacMD5 extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.HmacMD5();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.HmacSHA1 extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.HmacSHA1();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.HmacSHA224 extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.HmacSHA224();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.HmacSHA256 extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.HmacSHA256();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.HmacSHA384 extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.HmacSHA384();
-  }
-
-  @libcore.api.IntraCoreApi public static final class KeyGeneratorImpl.HmacSHA512 extends com.android.org.conscrypt.KeyGeneratorImpl {
-    ctor @libcore.api.IntraCoreApi public KeyGeneratorImpl.HmacSHA512();
-  }
-
-  @libcore.api.IntraCoreApi public class OAEPParameters extends java.security.AlgorithmParametersSpi {
-    ctor @libcore.api.IntraCoreApi public OAEPParameters();
-  }
-
-  @libcore.api.IntraCoreApi public abstract class OpenSSLCipher extends javax.crypto.CipherSpi {
-  }
-
-  @libcore.api.IntraCoreApi public abstract static class OpenSSLCipher.EVP_AEAD extends com.android.org.conscrypt.OpenSSLCipher {
-  }
-
-  @libcore.api.IntraCoreApi public abstract static class OpenSSLCipher.EVP_AEAD.AES extends com.android.org.conscrypt.OpenSSLCipher.EVP_AEAD {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_AEAD.AES.GCM extends com.android.org.conscrypt.OpenSSLCipher.EVP_AEAD.AES {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_AEAD.AES.GCM();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_AEAD.AES.GCM.AES_128 extends com.android.org.conscrypt.OpenSSLCipher.EVP_AEAD.AES.GCM {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_AEAD.AES.GCM.AES_128();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_AEAD.AES.GCM.AES_256 extends com.android.org.conscrypt.OpenSSLCipher.EVP_AEAD.AES.GCM {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_AEAD.AES.GCM.AES_256();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_AEAD.ChaCha20 extends com.android.org.conscrypt.OpenSSLCipher.EVP_AEAD {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_AEAD.ChaCha20();
-  }
-
-  @libcore.api.IntraCoreApi public abstract static class OpenSSLCipher.EVP_CIPHER extends com.android.org.conscrypt.OpenSSLCipher {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES.CBC extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES.CBC.NoPadding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES.CBC {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES.CBC.NoPadding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES.CBC.PKCS5Padding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES.CBC {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES.CBC.PKCS5Padding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES.CTR extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES.CTR();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES.ECB extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES.ECB.NoPadding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES.ECB {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES.ECB.NoPadding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES.ECB.PKCS5Padding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES.ECB {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES.ECB.PKCS5Padding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_128 extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_128.CBC extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_128 {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_128.CBC.NoPadding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_128.CBC {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES_128.CBC.NoPadding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_128.CBC.PKCS5Padding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_128.CBC {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES_128.CBC.PKCS5Padding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_128.ECB extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_128 {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_128.ECB.NoPadding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_128.ECB {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES_128.ECB.NoPadding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_128.ECB.PKCS5Padding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_128.ECB {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES_128.ECB.PKCS5Padding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_256 extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_256.CBC extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_256 {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_256.CBC.NoPadding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_256.CBC {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES_256.CBC.NoPadding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_256.CBC.PKCS5Padding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_256.CBC {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES_256.CBC.PKCS5Padding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_256.ECB extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_256 {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_256.ECB.NoPadding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_256.ECB {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES_256.ECB.NoPadding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.AES_256.ECB.PKCS5Padding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.AES_256.ECB {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.AES_256.ECB.PKCS5Padding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.ARC4 extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.ARC4();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.DESEDE extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.DESEDE.CBC extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.DESEDE {
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.DESEDE.CBC.NoPadding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.DESEDE.CBC {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.DESEDE.CBC.NoPadding();
-  }
-
-  @libcore.api.IntraCoreApi public static class OpenSSLCipher.EVP_CIPHER.DESEDE.CBC.PKCS5Padding extends com.android.org.conscrypt.OpenSSLCipher.EVP_CIPHER.DESEDE.CBC {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipher.EVP_CIPHER.DESEDE.CBC.PKCS5Padding();
-  }
-
-  @libcore.api.IntraCoreApi public class OpenSSLCipherChaCha20 extends com.android.org.conscrypt.OpenSSLCipher {
-    ctor @libcore.api.IntraCoreApi public OpenSSLCipherChaCha20();
-  }
-
-  @libcore.api.IntraCoreApi public abstract class OpenSSLContextImpl extends javax.net.ssl.SSLContextSpi {
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLContextImpl.TLSv1 extends com.android.org.conscrypt.OpenSSLContextImpl {
-    ctor @libcore.api.IntraCoreApi public OpenSSLContextImpl.TLSv1();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLContextImpl.TLSv11 extends com.android.org.conscrypt.OpenSSLContextImpl {
-    ctor @libcore.api.IntraCoreApi public OpenSSLContextImpl.TLSv11();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLContextImpl.TLSv12 extends com.android.org.conscrypt.OpenSSLContextImpl {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage @libcore.api.IntraCoreApi public OpenSSLContextImpl.TLSv12();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLContextImpl.TLSv13 extends com.android.org.conscrypt.OpenSSLContextImpl {
-    ctor @libcore.api.IntraCoreApi public OpenSSLContextImpl.TLSv13();
-  }
-
-  @libcore.api.IntraCoreApi public final class OpenSSLECDHKeyAgreement extends javax.crypto.KeyAgreementSpi {
-    ctor @libcore.api.IntraCoreApi public OpenSSLECDHKeyAgreement();
-  }
-
-  @libcore.api.IntraCoreApi public final class OpenSSLECKeyFactory extends java.security.KeyFactorySpi {
-    ctor @libcore.api.IntraCoreApi public OpenSSLECKeyFactory();
-  }
-
-  @libcore.api.IntraCoreApi public final class OpenSSLECKeyPairGenerator extends java.security.KeyPairGenerator {
-    ctor @libcore.api.IntraCoreApi public OpenSSLECKeyPairGenerator();
-  }
-
-  @libcore.api.IntraCoreApi public abstract class OpenSSLMac extends javax.crypto.MacSpi {
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMac.HmacMD5 extends com.android.org.conscrypt.OpenSSLMac {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMac.HmacMD5();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMac.HmacSHA1 extends com.android.org.conscrypt.OpenSSLMac {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMac.HmacSHA1();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMac.HmacSHA224 extends com.android.org.conscrypt.OpenSSLMac {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMac.HmacSHA224() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMac.HmacSHA256 extends com.android.org.conscrypt.OpenSSLMac {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMac.HmacSHA256() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMac.HmacSHA384 extends com.android.org.conscrypt.OpenSSLMac {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMac.HmacSHA384() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMac.HmacSHA512 extends com.android.org.conscrypt.OpenSSLMac {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMac.HmacSHA512();
-  }
-
-  @libcore.api.IntraCoreApi public class OpenSSLMessageDigestJDK extends java.security.MessageDigestSpi implements java.lang.Cloneable {
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMessageDigestJDK.MD5 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMessageDigestJDK.MD5() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMessageDigestJDK.SHA1 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMessageDigestJDK.SHA1() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMessageDigestJDK.SHA224 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMessageDigestJDK.SHA224() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMessageDigestJDK.SHA256 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMessageDigestJDK.SHA256() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMessageDigestJDK.SHA384 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMessageDigestJDK.SHA384() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLMessageDigestJDK.SHA512 extends com.android.org.conscrypt.OpenSSLMessageDigestJDK {
-    ctor @libcore.api.IntraCoreApi public OpenSSLMessageDigestJDK.SHA512() throws java.security.NoSuchAlgorithmException;
-  }
-
-  @libcore.api.IntraCoreApi public final class OpenSSLRSAKeyFactory extends java.security.KeyFactorySpi {
-    ctor @libcore.api.IntraCoreApi public OpenSSLRSAKeyFactory();
-  }
-
-  @libcore.api.IntraCoreApi public final class OpenSSLRSAKeyPairGenerator extends java.security.KeyPairGeneratorSpi {
-    ctor @libcore.api.IntraCoreApi public OpenSSLRSAKeyPairGenerator();
-  }
-
-  @libcore.api.IntraCoreApi public final class OpenSSLRandom extends java.security.SecureRandomSpi implements java.io.Serializable {
-    ctor @dalvik.annotation.compat.UnsupportedAppUsage @libcore.api.IntraCoreApi public OpenSSLRandom();
-  }
-
-  @libcore.api.IntraCoreApi public class OpenSSLSignature extends java.security.SignatureSpi {
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.MD5RSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.MD5RSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA1ECDSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA1ECDSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA1RSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA1RSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA1RSAPSS extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA1RSAPSS();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA224ECDSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA224ECDSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA224RSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA224RSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA224RSAPSS extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA224RSAPSS();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA256ECDSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA256ECDSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA256RSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA256RSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA256RSAPSS extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA256RSAPSS();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA384ECDSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA384ECDSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA384RSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA384RSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA384RSAPSS extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA384RSAPSS();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA512ECDSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA512ECDSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA512RSA extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA512RSA();
-  }
-
-  @libcore.api.IntraCoreApi public static final class OpenSSLSignature.SHA512RSAPSS extends com.android.org.conscrypt.OpenSSLSignature {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignature.SHA512RSAPSS();
-  }
-
-  @libcore.api.IntraCoreApi public class OpenSSLSignatureRawECDSA extends java.security.SignatureSpi {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignatureRawECDSA();
-  }
-
-  @libcore.api.IntraCoreApi public final class OpenSSLSignatureRawRSA extends java.security.SignatureSpi {
-    ctor @libcore.api.IntraCoreApi public OpenSSLSignatureRawRSA();
-  }
-
-  @libcore.api.IntraCoreApi public class OpenSSLX509CertificateFactory extends java.security.cert.CertificateFactorySpi {
-    ctor @libcore.api.IntraCoreApi public OpenSSLX509CertificateFactory();
-  }
-
-  @libcore.api.IntraCoreApi public class PSSParameters extends java.security.AlgorithmParametersSpi {
-    ctor @libcore.api.IntraCoreApi public PSSParameters();
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static final class Compatibility.ChangeConfig {
+    ctor public Compatibility.ChangeConfig(java.util.Set<java.lang.Long>, java.util.Set<java.lang.Long>);
+    method public long[] forceDisabledChangesArray();
+    method public java.util.Set<java.lang.Long> forceDisabledSet();
+    method public long[] forceEnabledChangesArray();
+    method public java.util.Set<java.lang.Long> forceEnabledSet();
+    method public boolean isEmpty();
+    method public boolean isForceDisabled(long);
+    method public boolean isForceEnabled(long);
   }
 
 }
 
 package dalvik.annotation.compat {
 
-  @java.lang.annotation.Repeatable(UnsupportedAppUsage.Container.class) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.TYPE}) @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public @interface UnsupportedAppUsage {
-    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public abstract String expectedSignature() default "";
-    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public abstract String implicitMember() default "";
-    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public abstract int maxTargetSdk() default java.lang.Integer.MAX_VALUE;
-    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public abstract long trackingBug() default 0;
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public class VersionCodes {
+    field @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static final int O = 26; // 0x1a
+    field @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static final int P = 28; // 0x1c
+    field @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static final int Q = 29; // 0x1d
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static @interface UnsupportedAppUsage.Container {
-    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public abstract dalvik.annotation.compat.UnsupportedAppUsage[] value();
+}
+
+package dalvik.annotation.optimization {
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) @libcore.api.IntraCoreApi public @interface ReachabilitySensitive {
   }
 
 }
@@ -417,23 +39,18 @@
 package dalvik.system {
 
   @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public final class BlockGuard {
-    method @NonNull @dalvik.annotation.compat.UnsupportedAppUsage @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static dalvik.system.BlockGuard.Policy getThreadPolicy();
+    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 @dalvik.annotation.compat.UnsupportedAppUsage @libcore.api.IntraCoreApi public void onNetwork();
+    method @libcore.api.IntraCoreApi public void onNetwork();
   }
 
   @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public final class CloseGuard {
-    method @dalvik.annotation.compat.UnsupportedAppUsage @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public void close();
-    method @dalvik.annotation.compat.UnsupportedAppUsage @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static dalvik.system.CloseGuard get();
-    method @dalvik.annotation.compat.UnsupportedAppUsage @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public void open(String);
-    method @dalvik.annotation.compat.UnsupportedAppUsage @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public void warnIfOpen();
-  }
-
-  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public class VersionCodes {
-    field @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static final int O = 26; // 0x1a
-    field @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static final int P = 28; // 0x1c
+    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();
   }
 
 }
@@ -446,6 +63,22 @@
 
 }
 
+package java.nio.charset {
+
+  public abstract class Charset implements java.lang.Comparable<java.nio.charset.Charset> {
+    ctor @libcore.api.IntraCoreApi protected Charset(String, String[]);
+  }
+
+  public abstract class CharsetDecoder {
+    ctor protected CharsetDecoder(java.nio.charset.Charset, float, float);
+  }
+
+  public abstract class CharsetEncoder {
+    ctor protected CharsetEncoder(java.nio.charset.Charset, float, float, byte[], boolean);
+  }
+
+}
+
 package java.security.spec {
 
   public class ECParameterSpec implements java.security.spec.AlgorithmParameterSpec {
@@ -465,6 +98,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 {
@@ -477,10 +118,15 @@
 
 package libcore.util {
 
-  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE_USE}) @libcore.api.IntraCoreApi public @interface NonNull {
+  @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public class NativeAllocationRegistry {
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public static libcore.util.NativeAllocationRegistry createMalloced(ClassLoader, long);
+    method @libcore.api.CorePlatformApi @libcore.api.IntraCoreApi public Runnable registerNativeAllocation(Object, long);
   }
 
-  @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE_USE}) @libcore.api.IntraCoreApi public @interface Nullable {
+  @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 {
+  }
+
+  @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 Nullable {
   }
 
 }
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 3e4083f..e3c8c16 100644
--- a/non_openjdk_java_files.bp
+++ b/non_openjdk_java_files.bp
@@ -1,32 +1,18 @@
 filegroup {
     name: "non_openjdk_javadoc_files",
     srcs: [
-        "luni/src/main/java/android/system/ErrnoException.java",
-        "luni/src/main/java/android/system/GaiException.java",
-        "luni/src/main/java/android/system/Int32Ref.java",
-        "luni/src/main/java/android/system/Int64Ref.java",
-        "luni/src/main/java/android/system/NetlinkSocketAddress.java",
-        "luni/src/main/java/android/system/Os.java",
-        "luni/src/main/java/android/system/OsConstants.java",
-        "luni/src/main/java/android/system/PacketSocketAddress.java",
-        "luni/src/main/java/android/system/StructAddrinfo.java",
-        "luni/src/main/java/android/system/StructCapUserData.java",
-        "luni/src/main/java/android/system/StructCapUserHeader.java",
-        "luni/src/main/java/android/system/StructFlock.java",
-        "luni/src/main/java/android/system/StructGroupReq.java",
-        "luni/src/main/java/android/system/StructIcmpHdr.java",
-        "luni/src/main/java/android/system/StructIfaddrs.java",
-        "luni/src/main/java/android/system/StructLinger.java",
-        "luni/src/main/java/android/system/StructPasswd.java",
-        "luni/src/main/java/android/system/StructPollfd.java",
-        "luni/src/main/java/android/system/StructRlimit.java",
-        "luni/src/main/java/android/system/StructStat.java",
-        "luni/src/main/java/android/system/StructStatVfs.java",
-        "luni/src/main/java/android/system/StructTimeval.java",
-        "luni/src/main/java/android/system/StructTimespec.java",
-        "luni/src/main/java/android/system/StructUcred.java",
-        "luni/src/main/java/android/system/StructUtsname.java",
-        "luni/src/main/java/android/system/UnixSocketAddress.java",
+        ":non_openjdk_javadoc_dalvik_files",
+        ":non_openjdk_javadoc_json_files",
+        ":non_openjdk_javadoc_libart_files",
+        ":non_openjdk_javadoc_luni_files",
+        ":non_openjdk_javadoc_xml_files",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+filegroup {
+    name: "non_openjdk_javadoc_dalvik_files",
+    srcs: [
         "dalvik/src/main/java/dalvik/annotation/AnnotationDefault.java",
         "dalvik/src/main/java/dalvik/annotation/EnclosingClass.java",
         "dalvik/src/main/java/dalvik/annotation/EnclosingMethod.java",
@@ -39,7 +25,6 @@
         "dalvik/src/main/java/dalvik/annotation/TestTargetClass.java",
         "dalvik/src/main/java/dalvik/annotation/Throws.java",
         "dalvik/src/main/java/dalvik/annotation/codegen/CovariantReturnType.java",
-        "dalvik/src/main/java/dalvik/annotation/compat/UnsupportedAppUsage.java",
         "dalvik/src/main/java/dalvik/annotation/optimization/CriticalNative.java",
         "dalvik/src/main/java/dalvik/annotation/optimization/DeadReferenceSafe.java",
         "dalvik/src/main/java/dalvik/annotation/optimization/FastNative.java",
@@ -47,10 +32,8 @@
         "dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java",
         "dalvik/src/main/java/dalvik/bytecode/Opcodes.java",
         "dalvik/src/main/java/dalvik/system/AllocationLimitError.java",
-        "libart/src/main/java/dalvik/system/AnnotatedStackTraceElement.java",
         "dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java",
         "dalvik/src/main/java/dalvik/system/BlockGuard.java",
-        "libart/src/main/java/dalvik/system/ClassExt.java",
         "dalvik/src/main/java/dalvik/system/CloseGuard.java",
         "dalvik/src/main/java/dalvik/system/DalvikLogHandler.java",
         "dalvik/src/main/java/dalvik/system/DalvikLogging.java",
@@ -66,21 +49,114 @@
         "dalvik/src/main/java/dalvik/system/RuntimeHooks.java",
         "dalvik/src/main/java/dalvik/system/SocketTagger.java",
         "dalvik/src/main/java/dalvik/system/TemporaryDirectory.java",
-        "libart/src/main/java/dalvik/system/TransactionAbortError.java",
-        "dalvik/src/main/java/dalvik/system/VersionCodes.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",
+        "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java",
+        "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java",
+        "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java",
+        "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java",
+        ":hidden_api_surface_annotation_files",
+    ],
+    path: "dalvik/src/main",
+    visibility: ["//visibility:private"],
+}
+
+filegroup {
+    name: "non_openjdk_javadoc_json_files",
+    srcs: [
+        "json/src/main/java/org/json/JSON.java",
+        "json/src/main/java/org/json/JSONArray.java",
+        "json/src/main/java/org/json/JSONException.java",
+        "json/src/main/java/org/json/JSONObject.java",
+        "json/src/main/java/org/json/JSONStringer.java",
+        "json/src/main/java/org/json/JSONTokener.java",
+    ],
+    path: "json/src/main",
+    visibility: ["//visibility:private"],
+}
+
+filegroup {
+    name: "non_openjdk_javadoc_libart_files",
+    srcs: [
+        "libart/src/main/java/dalvik/system/AnnotatedStackTraceElement.java",
+        "libart/src/main/java/dalvik/system/ClassExt.java",
+        "libart/src/main/java/dalvik/system/TransactionAbortError.java",
         "libart/src/main/java/dalvik/system/VMRuntime.java",
         "libart/src/main/java/dalvik/system/VMStack.java",
-        "dalvik/src/main/java/dalvik/system/ZygoteHooks.java",
         "libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java",
         "libart/src/main/java/java/lang/Daemons.java",
         "libart/src/main/java/java/lang/DexCache.java",
-        "luni/src/main/java/java/lang/FindBugsSuppressWarnings.java",
         "libart/src/main/java/java/lang/VMClassLoader.java",
         "libart/src/main/java/java/lang/invoke/ArrayElementVarHandle.java",
         "libart/src/main/java/java/lang/invoke/ByteArrayViewVarHandle.java",
         "libart/src/main/java/java/lang/invoke/ByteBufferViewVarHandle.java",
         "libart/src/main/java/java/lang/invoke/FieldVarHandle.java",
+    ],
+    path: "libart/src/main",
+    visibility: ["//visibility:private"],
+}
+
+// The set of annotations used for defining visible (i.e. not hidden) API
+// surfaces.
+filegroup {
+    name: "visible_api_surface_annotation_files",
+    srcs: [
+        "luni/src/main/java/libcore/api/CorePlatformApi.java",
+        "luni/src/main/java/libcore/api/Hide.java",
+        "luni/src/main/java/libcore/api/IntraCoreApi.java",
+    ],
+}
+
+// The set of annotations used for defining the hidden API surface.
+filegroup {
+    name: "hidden_api_surface_annotation_files",
+    srcs: [
+        "dalvik/src/main/java/dalvik/annotation/compat/VersionCodes.java",
+    ],
+}
+
+// The set of annotations used for defining all API surfaces, including hidden
+// APIs.
+filegroup {
+    name: "api_surface_annotation_files",
+    srcs: [
+        ":hidden_api_surface_annotation_files",
+        ":visible_api_surface_annotation_files",
+    ],
+}
+
+filegroup {
+    name: "non_openjdk_javadoc_luni_files",
+    srcs: [
+        "luni/src/main/java/android/compat/Compatibility.java",
+        "luni/src/main/java/android/system/ErrnoException.java",
+        "luni/src/main/java/android/system/GaiException.java",
+        "luni/src/main/java/android/system/IcmpHeaders.java",
+        "luni/src/main/java/android/system/Int32Ref.java",
+        "luni/src/main/java/android/system/Int64Ref.java",
+        "luni/src/main/java/android/system/NetlinkSocketAddress.java",
+        "luni/src/main/java/android/system/Os.java",
+        "luni/src/main/java/android/system/OsConstants.java",
+        "luni/src/main/java/android/system/PacketSocketAddress.java",
+        "luni/src/main/java/android/system/StructAddrinfo.java",
+        "luni/src/main/java/android/system/StructCapUserData.java",
+        "luni/src/main/java/android/system/StructCapUserHeader.java",
+        "luni/src/main/java/android/system/StructGroupReq.java",
+        "luni/src/main/java/android/system/StructIfaddrs.java",
+        "luni/src/main/java/android/system/StructLinger.java",
+        "luni/src/main/java/android/system/StructPasswd.java",
+        "luni/src/main/java/android/system/StructPollfd.java",
+        "luni/src/main/java/android/system/StructRlimit.java",
+        "luni/src/main/java/android/system/StructStat.java",
+        "luni/src/main/java/android/system/StructStatVfs.java",
+        "luni/src/main/java/android/system/StructTimespec.java",
+        "luni/src/main/java/android/system/StructTimeval.java",
+        "luni/src/main/java/android/system/StructUcred.java",
+        "luni/src/main/java/android/system/StructUtsname.java",
+        "luni/src/main/java/android/system/UnixSocketAddress.java",
+        "luni/src/main/java/java/lang/FindBugsSuppressWarnings.java",
         "luni/src/main/java/java/lang/ref/FinalizerReference.java",
         "luni/src/main/java/java/math/BigDecimal.java",
         "luni/src/main/java/java/math/BigInt.java",
@@ -97,10 +173,6 @@
         "luni/src/main/java/java/net/DefaultFileNameMap.java",
         "luni/src/main/java/java/nio/NIOAccess.java",
         "luni/src/main/java/java/nio/NioUtils.java",
-        "luni/src/main/java/java/nio/charset/CharsetDecoderICU.java",
-        "luni/src/main/java/java/nio/charset/CharsetEncoderICU.java",
-        "luni/src/main/java/java/nio/charset/CharsetICU.java",
-        "luni/src/main/java/java/nio/charset/ModifiedUtf8.java",
         "luni/src/main/java/javax/xml/XMLConstants.java",
         "luni/src/main/java/javax/xml/datatype/DatatypeConfigurationException.java",
         "luni/src/main/java/javax/xml/datatype/DatatypeConstants.java",
@@ -159,15 +231,14 @@
         "luni/src/main/java/javax/xml/xpath/XPathFunctionException.java",
         "luni/src/main/java/javax/xml/xpath/XPathFunctionResolver.java",
         "luni/src/main/java/javax/xml/xpath/XPathVariableResolver.java",
-        "luni/src/main/java/libcore/api/CorePlatformApi.java",
+        "luni/src/main/java/libcore/content/type/MimeMap.java",
         "luni/src/main/java/libcore/icu/DateIntervalFormat.java",
-        "luni/src/main/java/libcore/api/Hide.java",
-        "luni/src/main/java/libcore/api/IntraCoreApi.java",
         "luni/src/main/java/libcore/icu/ICU.java",
         "luni/src/main/java/libcore/icu/LocaleData.java",
         "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",
@@ -176,20 +247,24 @@
         "luni/src/main/java/libcore/io/Os.java",
         "luni/src/main/java/libcore/io/Streams.java",
         "luni/src/main/java/libcore/net/InetAddressUtils.java",
-        "luni/src/main/java/libcore/net/MimeUtils.java",
         "luni/src/main/java/libcore/net/NetworkSecurityPolicy.java",
         "luni/src/main/java/libcore/net/event/NetworkEventDispatcher.java",
         "luni/src/main/java/libcore/timezone/CountryTimeZones.java",
         "luni/src/main/java/libcore/timezone/CountryZonesFinder.java",
+        "luni/src/main/java/libcore/timezone/TelephonyLookup.java",
+        "luni/src/main/java/libcore/timezone/TelephonyNetwork.java",
+        "luni/src/main/java/libcore/timezone/TelephonyNetworkFinder.java",
         "luni/src/main/java/libcore/timezone/TimeZoneDataFiles.java",
         "luni/src/main/java/libcore/timezone/TimeZoneFinder.java",
         "luni/src/main/java/libcore/timezone/TzDataSetVersion.java",
-        "luni/src/main/java/libcore/timezone/ZoneInfoDB.java",
+        "luni/src/main/java/libcore/timezone/XmlUtils.java",
+        "luni/src/main/java/libcore/timezone/ZoneInfoDb.java",
         "luni/src/main/java/libcore/util/ArrayUtils.java",
         "luni/src/main/java/libcore/util/BasicLruCache.java",
         "luni/src/main/java/libcore/util/CoreLibraryDebug.java",
         "luni/src/main/java/libcore/util/DebugInfo.java",
         "luni/src/main/java/libcore/util/EmptyArray.java",
+        "luni/src/main/java/libcore/util/FP16.java",
         "luni/src/main/java/libcore/util/HexEncoding.java",
         "luni/src/main/java/libcore/util/NativeAllocationRegistry.java",
         "luni/src/main/java/libcore/util/NonNull.java",
@@ -197,17 +272,6 @@
         "luni/src/main/java/libcore/util/SneakyThrow.java",
         "luni/src/main/java/libcore/util/XmlObjectFactory.java",
         "luni/src/main/java/libcore/util/ZoneInfo.java",
-        "dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java",
-        "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java",
-        "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java",
-        "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java",
-        "dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java",
-        "json/src/main/java/org/json/JSON.java",
-        "json/src/main/java/org/json/JSONArray.java",
-        "json/src/main/java/org/json/JSONException.java",
-        "json/src/main/java/org/json/JSONObject.java",
-        "json/src/main/java/org/json/JSONStringer.java",
-        "json/src/main/java/org/json/JSONTokener.java",
         "luni/src/main/java/org/w3c/dom/Attr.java",
         "luni/src/main/java/org/w3c/dom/CDATASection.java",
         "luni/src/main/java/org/w3c/dom/CharacterData.java",
@@ -283,24 +347,36 @@
         "luni/src/main/java/org/xml/sax/helpers/XMLFilterImpl.java",
         "luni/src/main/java/org/xml/sax/helpers/XMLReaderAdapter.java",
         "luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java",
+        ":visible_api_surface_annotation_files",
+    ],
+    path: "luni/src/main",
+    visibility: ["//visibility:private"],
+}
+
+filegroup {
+    name: "non_openjdk_javadoc_xml_files",
+    srcs: [
         "xml/src/main/java/org/xmlpull/v1/XmlPullParser.java",
         "xml/src/main/java/org/xmlpull/v1/XmlPullParserException.java",
         "xml/src/main/java/org/xmlpull/v1/XmlPullParserFactory.java",
         "xml/src/main/java/org/xmlpull/v1/XmlSerializer.java",
         "xml/src/main/java/org/xmlpull/v1/sax2/Driver.java",
     ],
+    path: "xml/src/main",
+    visibility: ["//visibility:private"],
 }
 
 filegroup {
     name: "non_openjdk_java_files",
+    visibility: [
+        "//frameworks/base",
+    ],
     srcs: [
         "luni/src/main/java/java/net/AddressCache.java",
         "luni/src/main/java/libcore/icu/CollationKeyICU.java",
         "luni/src/main/java/libcore/icu/DateTimeFormat.java",
         "luni/src/main/java/libcore/icu/DateUtilsBridge.java",
-        "luni/src/main/java/libcore/icu/NativeConverter.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",
@@ -311,7 +387,6 @@
         "luni/src/main/java/libcore/math/MathUtils.java",
         "luni/src/main/java/libcore/net/event/NetworkEventListener.java",
         "luni/src/main/java/libcore/net/http/HttpDate.java",
-        "luni/src/main/java/libcore/net/http/ResponseUtils.java",
         "luni/src/main/java/libcore/reflect/AnnotatedElements.java",
         "luni/src/main/java/libcore/reflect/AnnotationFactory.java",
         "luni/src/main/java/libcore/reflect/AnnotationMember.java",
@@ -326,8 +401,6 @@
         "luni/src/main/java/libcore/reflect/WildcardTypeImpl.java",
         "luni/src/main/java/libcore/util/CharsetUtils.java",
         "luni/src/main/java/libcore/util/CollectionUtils.java",
-        "luni/src/main/java/libcore/util/NonNull.java",
-        "luni/src/main/java/libcore/util/Nullable.java",
         "luni/src/main/java/libcore/util/NullFromTypeParam.java",
         "luni/src/main/java/libcore/util/Objects.java",
         "luni/src/main/java/org/apache/harmony/xml/ExpatAttributes.java",
@@ -373,6 +446,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/Android.bp b/ojluni/Android.bp
new file mode 100644
index 0000000..20a5a5a
--- /dev/null
+++ b/ojluni/Android.bp
@@ -0,0 +1,26 @@
+// 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.
+
+// Phony target that causes the build to check the license file in this
+// directory, detect that it is a GPL license and then copy all the files
+// from this directory and its subdirectories in to the
+// ${OUT}/obj/PACKAGING/gpl_source_intermediates/gpl_source.tgz file.
+phony {
+    name: "ojluni-phony",
+
+    // A phony module must have at least one dependency.
+    required: [
+        "core-oj",
+    ],
+}
diff --git a/ojluni/annotations/hiddenapi/com/sun/nio/file/ExtendedWatchEventModifier.java b/ojluni/annotations/hiddenapi/com/sun/nio/file/ExtendedWatchEventModifier.java
index d3d1fd7..9abd97c 100644
--- a/ojluni/annotations/hiddenapi/com/sun/nio/file/ExtendedWatchEventModifier.java
+++ b/ojluni/annotations/hiddenapi/com/sun/nio/file/ExtendedWatchEventModifier.java
@@ -27,7 +27,7 @@
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public enum ExtendedWatchEventModifier implements java.nio.file.WatchEvent.Modifier {
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     FILE_TREE;
 
     private ExtendedWatchEventModifier() {
diff --git a/ojluni/annotations/hiddenapi/java/io/Console.java b/ojluni/annotations/hiddenapi/java/io/Console.java
index 9a93310..24039a1 100644
--- a/ojluni/annotations/hiddenapi/java/io/Console.java
+++ b/ojluni/annotations/hiddenapi/java/io/Console.java
@@ -26,7 +26,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Console implements java.io.Flushable {
diff --git a/ojluni/annotations/hiddenapi/java/io/File.java b/ojluni/annotations/hiddenapi/java/io/File.java
index 7b93218..bdcce88 100644
--- a/ojluni/annotations/hiddenapi/java/io/File.java
+++ b/ojluni/annotations/hiddenapi/java/io/File.java
@@ -26,7 +26,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class File implements java.io.Serializable, java.lang.Comparable<java.io.File> {
diff --git a/ojluni/annotations/hiddenapi/java/io/FileDescriptor.java b/ojluni/annotations/hiddenapi/java/io/FileDescriptor.java
index 7872403..6e9e74d 100644
--- a/ojluni/annotations/hiddenapi/java/io/FileDescriptor.java
+++ b/ojluni/annotations/hiddenapi/java/io/FileDescriptor.java
@@ -25,7 +25,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class FileDescriptor {
diff --git a/ojluni/annotations/hiddenapi/java/io/FileInputStream.java b/ojluni/annotations/hiddenapi/java/io/FileInputStream.java
index 3de1617..1999d13 100644
--- a/ojluni/annotations/hiddenapi/java/io/FileInputStream.java
+++ b/ojluni/annotations/hiddenapi/java/io/FileInputStream.java
@@ -26,7 +26,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class FileInputStream extends java.io.InputStream {
diff --git a/ojluni/annotations/hiddenapi/java/io/FileOutputStream.java b/ojluni/annotations/hiddenapi/java/io/FileOutputStream.java
index b918f6a..5e35fc0 100644
--- a/ojluni/annotations/hiddenapi/java/io/FileOutputStream.java
+++ b/ojluni/annotations/hiddenapi/java/io/FileOutputStream.java
@@ -26,7 +26,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class FileOutputStream extends java.io.OutputStream {
diff --git a/ojluni/annotations/hiddenapi/java/io/FileSystem.java b/ojluni/annotations/hiddenapi/java/io/FileSystem.java
index 4999b3c..e522846 100644
--- a/ojluni/annotations/hiddenapi/java/io/FileSystem.java
+++ b/ojluni/annotations/hiddenapi/java/io/FileSystem.java
@@ -26,7 +26,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 abstract class FileSystem {
diff --git a/ojluni/annotations/hiddenapi/java/io/ObjectInputStream.java b/ojluni/annotations/hiddenapi/java/io/ObjectInputStream.java
index 90dcfea..562d846 100644
--- a/ojluni/annotations/hiddenapi/java/io/ObjectInputStream.java
+++ b/ojluni/annotations/hiddenapi/java/io/ObjectInputStream.java
@@ -26,7 +26,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ObjectInputStream extends java.io.InputStream
diff --git a/ojluni/annotations/hiddenapi/java/io/ObjectOutputStream.java b/ojluni/annotations/hiddenapi/java/io/ObjectOutputStream.java
index f3e462d..1e429a4 100644
--- a/ojluni/annotations/hiddenapi/java/io/ObjectOutputStream.java
+++ b/ojluni/annotations/hiddenapi/java/io/ObjectOutputStream.java
@@ -26,7 +26,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ObjectOutputStream extends java.io.OutputStream
diff --git a/ojluni/annotations/hiddenapi/java/io/ObjectStreamClass.java b/ojluni/annotations/hiddenapi/java/io/ObjectStreamClass.java
index d617d32..658d601 100644
--- a/ojluni/annotations/hiddenapi/java/io/ObjectStreamClass.java
+++ b/ojluni/annotations/hiddenapi/java/io/ObjectStreamClass.java
@@ -25,7 +25,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ObjectStreamClass implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/io/ObjectStreamField.java b/ojluni/annotations/hiddenapi/java/io/ObjectStreamField.java
index b3b7c34..36ba799 100644
--- a/ojluni/annotations/hiddenapi/java/io/ObjectStreamField.java
+++ b/ojluni/annotations/hiddenapi/java/io/ObjectStreamField.java
@@ -25,7 +25,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ObjectStreamField implements java.lang.Comparable<java.lang.Object> {
diff --git a/ojluni/annotations/hiddenapi/java/io/RandomAccessFile.java b/ojluni/annotations/hiddenapi/java/io/RandomAccessFile.java
index 32d36ab..5bc7d69 100644
--- a/ojluni/annotations/hiddenapi/java/io/RandomAccessFile.java
+++ b/ojluni/annotations/hiddenapi/java/io/RandomAccessFile.java
@@ -26,7 +26,7 @@
 
 package java.io;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class RandomAccessFile implements java.io.DataOutput, java.io.DataInput, java.io.Closeable {
diff --git a/ojluni/annotations/hiddenapi/java/lang/AbstractStringBuilder.java b/ojluni/annotations/hiddenapi/java/lang/AbstractStringBuilder.java
index 42a5b55..4ec2383 100644
--- a/ojluni/annotations/hiddenapi/java/lang/AbstractStringBuilder.java
+++ b/ojluni/annotations/hiddenapi/java/lang/AbstractStringBuilder.java
@@ -25,7 +25,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 abstract class AbstractStringBuilder implements java.lang.Appendable, java.lang.CharSequence {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Boolean.java b/ojluni/annotations/hiddenapi/java/lang/Boolean.java
index 14f0255..5f82352 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Boolean.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Boolean.java
@@ -25,8 +25,8 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Boolean
diff --git a/ojluni/annotations/hiddenapi/java/lang/Byte.java b/ojluni/annotations/hiddenapi/java/lang/Byte.java
index 6938eb7..612108b 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Byte.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Byte.java
@@ -25,8 +25,8 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Byte extends java.lang.Number implements java.lang.Comparable<java.lang.Byte> {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Character.java b/ojluni/annotations/hiddenapi/java/lang/Character.java
index 6ac842d..207008e 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Character.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Character.java
@@ -25,8 +25,8 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Character
diff --git a/ojluni/annotations/hiddenapi/java/lang/Class.java b/ojluni/annotations/hiddenapi/java/lang/Class.java
index 12a69d7..a9c1515 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Class.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Class.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Class<T>
diff --git a/ojluni/annotations/hiddenapi/java/lang/ClassLoader.java b/ojluni/annotations/hiddenapi/java/lang/ClassLoader.java
index 6af0cb8..b9c371e 100644
--- a/ojluni/annotations/hiddenapi/java/lang/ClassLoader.java
+++ b/ojluni/annotations/hiddenapi/java/lang/ClassLoader.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class ClassLoader {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Double.java b/ojluni/annotations/hiddenapi/java/lang/Double.java
index 187b7b4..1daeeb9 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Double.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Double.java
@@ -25,8 +25,8 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Double extends java.lang.Number
diff --git a/ojluni/annotations/hiddenapi/java/lang/Enum.java b/ojluni/annotations/hiddenapi/java/lang/Enum.java
index 369e58e..8cd1b6d 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Enum.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Enum.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Enum<E extends java.lang.Enum<E>>
diff --git a/ojluni/annotations/hiddenapi/java/lang/Float.java b/ojluni/annotations/hiddenapi/java/lang/Float.java
index 1081764..98f0b09 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Float.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Float.java
@@ -25,8 +25,8 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Float extends java.lang.Number implements java.lang.Comparable<java.lang.Float> {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Integer.java b/ojluni/annotations/hiddenapi/java/lang/Integer.java
index adb8c9c..388878e 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Integer.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Integer.java
@@ -26,8 +26,8 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Integer extends java.lang.Number
diff --git a/ojluni/annotations/hiddenapi/java/lang/Long.java b/ojluni/annotations/hiddenapi/java/lang/Long.java
index 2f32b27..e3041cc 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Long.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Long.java
@@ -26,8 +26,8 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Long extends java.lang.Number implements java.lang.Comparable<java.lang.Long> {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Object.java b/ojluni/annotations/hiddenapi/java/lang/Object.java
index 5289874..7b26bf5 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Object.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Object.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Object {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Runtime.java b/ojluni/annotations/hiddenapi/java/lang/Runtime.java
index ca8c56c..798967f 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Runtime.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Runtime.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Runtime {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Short.java b/ojluni/annotations/hiddenapi/java/lang/Short.java
index f1f0641..05f18ce 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Short.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Short.java
@@ -25,8 +25,8 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Short extends java.lang.Number implements java.lang.Comparable<java.lang.Short> {
diff --git a/ojluni/annotations/hiddenapi/java/lang/StackTraceElement.java b/ojluni/annotations/hiddenapi/java/lang/StackTraceElement.java
index a396013..010d949 100644
--- a/ojluni/annotations/hiddenapi/java/lang/StackTraceElement.java
+++ b/ojluni/annotations/hiddenapi/java/lang/StackTraceElement.java
@@ -25,7 +25,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class StackTraceElement implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/lang/String.java b/ojluni/annotations/hiddenapi/java/lang/String.java
index 51fdfb7..a7b137a 100644
--- a/ojluni/annotations/hiddenapi/java/lang/String.java
+++ b/ojluni/annotations/hiddenapi/java/lang/String.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class String
diff --git a/ojluni/annotations/hiddenapi/java/lang/System.java b/ojluni/annotations/hiddenapi/java/lang/System.java
index a401efd..407473b 100644
--- a/ojluni/annotations/hiddenapi/java/lang/System.java
+++ b/ojluni/annotations/hiddenapi/java/lang/System.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class System {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Thread.java b/ojluni/annotations/hiddenapi/java/lang/Thread.java
index 2e8557b..36ca327 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Thread.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Thread.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Thread implements java.lang.Runnable {
@@ -429,7 +429,9 @@
 
     long threadLocalRandomSeed;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(publicAlternatives = "Please update to a current version of the "
+        + "{@code Streamsupport} library; older versions of {@code Streamsupport} do not "
+        + "support current versions of Android.")
     java.lang.ThreadLocal.ThreadLocalMap threadLocals;
 
     private java.lang.Thread threadQ;
diff --git a/ojluni/annotations/hiddenapi/java/lang/ThreadGroup.java b/ojluni/annotations/hiddenapi/java/lang/ThreadGroup.java
index ee9feb0..bc69033 100644
--- a/ojluni/annotations/hiddenapi/java/lang/ThreadGroup.java
+++ b/ojluni/annotations/hiddenapi/java/lang/ThreadGroup.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ThreadGroup implements java.lang.Thread.UncaughtExceptionHandler {
diff --git a/ojluni/annotations/hiddenapi/java/lang/ThreadLocal.java b/ojluni/annotations/hiddenapi/java/lang/ThreadLocal.java
index 5772a6d..ca5927b 100644
--- a/ojluni/annotations/hiddenapi/java/lang/ThreadLocal.java
+++ b/ojluni/annotations/hiddenapi/java/lang/ThreadLocal.java
@@ -25,7 +25,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ThreadLocal<T> {
diff --git a/ojluni/annotations/hiddenapi/java/lang/Throwable.java b/ojluni/annotations/hiddenapi/java/lang/Throwable.java
index 0bc7d12..00a3b2c 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Throwable.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Throwable.java
@@ -26,7 +26,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Throwable implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/lang/UNIXProcess.java b/ojluni/annotations/hiddenapi/java/lang/UNIXProcess.java
index 75c3aa8..974ca3e 100644
--- a/ojluni/annotations/hiddenapi/java/lang/UNIXProcess.java
+++ b/ojluni/annotations/hiddenapi/java/lang/UNIXProcess.java
@@ -104,7 +104,7 @@
 
     private boolean hasExited;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private final int pid;
+    @android.compat.annotation.UnsupportedAppUsage private final int pid;
 
     {
         pid = 0;
diff --git a/ojluni/annotations/hiddenapi/java/lang/Void.java b/ojluni/annotations/hiddenapi/java/lang/Void.java
index e082300..35118c4 100644
--- a/ojluni/annotations/hiddenapi/java/lang/Void.java
+++ b/ojluni/annotations/hiddenapi/java/lang/Void.java
@@ -25,7 +25,7 @@
 
 package java.lang;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Void {
diff --git a/ojluni/annotations/hiddenapi/java/lang/invoke/MethodHandles.java b/ojluni/annotations/hiddenapi/java/lang/invoke/MethodHandles.java
index dcb5f11..d89c2a1 100644
--- a/ojluni/annotations/hiddenapi/java/lang/invoke/MethodHandles.java
+++ b/ojluni/annotations/hiddenapi/java/lang/invoke/MethodHandles.java
@@ -25,7 +25,7 @@
 
 package java.lang.invoke;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class MethodHandles {
diff --git a/ojluni/annotations/hiddenapi/java/lang/invoke/SerializedLambda.java b/ojluni/annotations/hiddenapi/java/lang/invoke/SerializedLambda.java
index b63d0de..fd92ce4 100644
--- a/ojluni/annotations/hiddenapi/java/lang/invoke/SerializedLambda.java
+++ b/ojluni/annotations/hiddenapi/java/lang/invoke/SerializedLambda.java
@@ -24,7 +24,7 @@
  */
 package java.lang.invoke;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import java.io.Serializable;
 
 public final class SerializedLambda implements Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/lang/ref/Reference.java b/ojluni/annotations/hiddenapi/java/lang/ref/Reference.java
index f2239ea..74359c1 100644
--- a/ojluni/annotations/hiddenapi/java/lang/ref/Reference.java
+++ b/ojluni/annotations/hiddenapi/java/lang/ref/Reference.java
@@ -26,7 +26,7 @@
 
 package java.lang.ref;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Reference<T> {
diff --git a/ojluni/annotations/hiddenapi/java/lang/ref/ReferenceQueue.java b/ojluni/annotations/hiddenapi/java/lang/ref/ReferenceQueue.java
index 423b830..e123068 100644
--- a/ojluni/annotations/hiddenapi/java/lang/ref/ReferenceQueue.java
+++ b/ojluni/annotations/hiddenapi/java/lang/ref/ReferenceQueue.java
@@ -26,7 +26,7 @@
 
 package java.lang.ref;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ReferenceQueue<T> {
diff --git a/ojluni/annotations/hiddenapi/java/lang/reflect/AccessibleObject.java b/ojluni/annotations/hiddenapi/java/lang/reflect/AccessibleObject.java
index b105a24..0a70608 100644
--- a/ojluni/annotations/hiddenapi/java/lang/reflect/AccessibleObject.java
+++ b/ojluni/annotations/hiddenapi/java/lang/reflect/AccessibleObject.java
@@ -26,7 +26,7 @@
 
 package java.lang.reflect;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
diff --git a/ojluni/annotations/hiddenapi/java/lang/reflect/Constructor.java b/ojluni/annotations/hiddenapi/java/lang/reflect/Constructor.java
index 79d24e3..5accc6a 100644
--- a/ojluni/annotations/hiddenapi/java/lang/reflect/Constructor.java
+++ b/ojluni/annotations/hiddenapi/java/lang/reflect/Constructor.java
@@ -26,7 +26,7 @@
 
 package java.lang.reflect;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Constructor<T> extends java.lang.reflect.Executable {
diff --git a/ojluni/annotations/hiddenapi/java/lang/reflect/Executable.java b/ojluni/annotations/hiddenapi/java/lang/reflect/Executable.java
index e40b1b1..198e79f 100644
--- a/ojluni/annotations/hiddenapi/java/lang/reflect/Executable.java
+++ b/ojluni/annotations/hiddenapi/java/lang/reflect/Executable.java
@@ -25,7 +25,7 @@
 
 package java.lang.reflect;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Executable extends java.lang.reflect.AccessibleObject
diff --git a/ojluni/annotations/hiddenapi/java/lang/reflect/Field.java b/ojluni/annotations/hiddenapi/java/lang/reflect/Field.java
index 2048f74..c11a65b 100644
--- a/ojluni/annotations/hiddenapi/java/lang/reflect/Field.java
+++ b/ojluni/annotations/hiddenapi/java/lang/reflect/Field.java
@@ -26,7 +26,7 @@
 
 package java.lang.reflect;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Field extends java.lang.reflect.AccessibleObject
@@ -165,10 +165,6 @@
 
     public native java.lang.annotation.Annotation[] getDeclaredAnnotations();
 
-    public int getDexFieldIndex() {
-        throw new RuntimeException("Stub!");
-    }
-
     @UnsupportedAppUsage
     public int getOffset() {
         throw new RuntimeException("Stub!");
@@ -181,7 +177,7 @@
 
     private java.lang.Class<?> declaringClass;
 
-    private int dexFieldIndex;
+    private int artFieldIndex;
 
     private int offset;
 
diff --git a/ojluni/annotations/hiddenapi/java/lang/reflect/Parameter.java b/ojluni/annotations/hiddenapi/java/lang/reflect/Parameter.java
index 40ccf9e..9982658 100644
--- a/ojluni/annotations/hiddenapi/java/lang/reflect/Parameter.java
+++ b/ojluni/annotations/hiddenapi/java/lang/reflect/Parameter.java
@@ -25,7 +25,7 @@
 
 package java.lang.reflect;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Parameter implements java.lang.reflect.AnnotatedElement {
diff --git a/ojluni/annotations/hiddenapi/java/lang/reflect/Proxy.java b/ojluni/annotations/hiddenapi/java/lang/reflect/Proxy.java
index e65bf19..593de12 100644
--- a/ojluni/annotations/hiddenapi/java/lang/reflect/Proxy.java
+++ b/ojluni/annotations/hiddenapi/java/lang/reflect/Proxy.java
@@ -26,7 +26,7 @@
 
 package java.lang.reflect;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Proxy implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/net/Authenticator.java b/ojluni/annotations/hiddenapi/java/net/Authenticator.java
index 2765044..3ac0089 100644
--- a/ojluni/annotations/hiddenapi/java/net/Authenticator.java
+++ b/ojluni/annotations/hiddenapi/java/net/Authenticator.java
@@ -25,7 +25,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Authenticator {
diff --git a/ojluni/annotations/hiddenapi/java/net/DatagramSocket.java b/ojluni/annotations/hiddenapi/java/net/DatagramSocket.java
index fd804c7..db3446a 100644
--- a/ojluni/annotations/hiddenapi/java/net/DatagramSocket.java
+++ b/ojluni/annotations/hiddenapi/java/net/DatagramSocket.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class DatagramSocket implements java.io.Closeable {
diff --git a/ojluni/annotations/hiddenapi/java/net/HttpCookie.java b/ojluni/annotations/hiddenapi/java/net/HttpCookie.java
index 113e804..97189e4 100644
--- a/ojluni/annotations/hiddenapi/java/net/HttpCookie.java
+++ b/ojluni/annotations/hiddenapi/java/net/HttpCookie.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class HttpCookie implements java.lang.Cloneable {
@@ -256,7 +256,8 @@
         header = null;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(
+        publicAlternatives = "Use {@link #setHttpOnly()}/{@link #isHttpOnly()} instead.")
     private boolean httpOnly;
 
     @UnsupportedAppUsage
diff --git a/ojluni/annotations/hiddenapi/java/net/Inet4Address.java b/ojluni/annotations/hiddenapi/java/net/Inet4Address.java
index 16395ea..b8f60cb 100644
--- a/ojluni/annotations/hiddenapi/java/net/Inet4Address.java
+++ b/ojluni/annotations/hiddenapi/java/net/Inet4Address.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Inet4Address extends java.net.InetAddress {
diff --git a/ojluni/annotations/hiddenapi/java/net/Inet6Address.java b/ojluni/annotations/hiddenapi/java/net/Inet6Address.java
index f46fa58..fc48ebc 100644
--- a/ojluni/annotations/hiddenapi/java/net/Inet6Address.java
+++ b/ojluni/annotations/hiddenapi/java/net/Inet6Address.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Inet6Address extends java.net.InetAddress {
diff --git a/ojluni/annotations/hiddenapi/java/net/Inet6AddressImpl.java b/ojluni/annotations/hiddenapi/java/net/Inet6AddressImpl.java
index 964bdda..dd25edf 100644
--- a/ojluni/annotations/hiddenapi/java/net/Inet6AddressImpl.java
+++ b/ojluni/annotations/hiddenapi/java/net/Inet6AddressImpl.java
@@ -81,7 +81,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static final java.net.AddressCache addressCache;
 
     static {
diff --git a/ojluni/annotations/hiddenapi/java/net/InetAddress.java b/ojluni/annotations/hiddenapi/java/net/InetAddress.java
index 0f128dd..2be05b7 100644
--- a/ojluni/annotations/hiddenapi/java/net/InetAddress.java
+++ b/ojluni/annotations/hiddenapi/java/net/InetAddress.java
@@ -26,8 +26,8 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class InetAddress implements java.io.Serializable {
@@ -181,7 +181,10 @@
         throw new RuntimeException("Stub!");
     }
 
-    @UnsupportedAppUsage(maxTargetSdk = VersionCodes.P, trackingBug = 78686891)
+    @UnsupportedAppUsage(maxTargetSdk = VersionCodes.P, trackingBug = 78686891,
+        publicAlternatives = "Use {@link android.net.InetAddresses#isNumericAddress} "
+        + "instead. There is a behavioural difference between the original method and its "
+        + "replacement.")
     public static boolean isNumeric(java.lang.String address) {
         throw new RuntimeException("Stub!");
     }
@@ -198,7 +201,10 @@
     /**
      * @deprecated Use {@code android.net.InetAddresses.parseNumericAddress(String)} instead.
      */
-    @UnsupportedAppUsage(maxTargetSdk = VersionCodes.P, trackingBug = 78686891)
+    @UnsupportedAppUsage(maxTargetSdk = VersionCodes.P, trackingBug = 78686891,
+        publicAlternatives = "Use {@link android.net.InetAddresses#parseNumericAddress} "
+        + "instead. There is a behavioural difference between the original method and its "
+        + "replacement.")
     public static java.net.InetAddress parseNumericAddress(java.lang.String numericAddress) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/java/net/InetSocketAddress.java b/ojluni/annotations/hiddenapi/java/net/InetSocketAddress.java
index 0a54f95..7522e0e 100644
--- a/ojluni/annotations/hiddenapi/java/net/InetSocketAddress.java
+++ b/ojluni/annotations/hiddenapi/java/net/InetSocketAddress.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class InetSocketAddress extends java.net.SocketAddress {
diff --git a/ojluni/annotations/hiddenapi/java/net/InterfaceAddress.java b/ojluni/annotations/hiddenapi/java/net/InterfaceAddress.java
index 7287847..84d3537 100644
--- a/ojluni/annotations/hiddenapi/java/net/InterfaceAddress.java
+++ b/ojluni/annotations/hiddenapi/java/net/InterfaceAddress.java
@@ -25,7 +25,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class InterfaceAddress {
diff --git a/ojluni/annotations/hiddenapi/java/net/PlainSocketImpl.java b/ojluni/annotations/hiddenapi/java/net/PlainSocketImpl.java
index 806a428..4d7b6be 100644
--- a/ojluni/annotations/hiddenapi/java/net/PlainSocketImpl.java
+++ b/ojluni/annotations/hiddenapi/java/net/PlainSocketImpl.java
@@ -29,7 +29,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 class PlainSocketImpl extends java.net.AbstractPlainSocketImpl {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     PlainSocketImpl() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/java/net/Proxy.java b/ojluni/annotations/hiddenapi/java/net/Proxy.java
index 4df3fa4..ff91f35 100644
--- a/ojluni/annotations/hiddenapi/java/net/Proxy.java
+++ b/ojluni/annotations/hiddenapi/java/net/Proxy.java
@@ -25,7 +25,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Proxy {
diff --git a/ojluni/annotations/hiddenapi/java/net/ServerSocket.java b/ojluni/annotations/hiddenapi/java/net/ServerSocket.java
index eabb247..ad0788a 100644
--- a/ojluni/annotations/hiddenapi/java/net/ServerSocket.java
+++ b/ojluni/annotations/hiddenapi/java/net/ServerSocket.java
@@ -25,7 +25,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ServerSocket implements java.io.Closeable {
diff --git a/ojluni/annotations/hiddenapi/java/net/Socket.java b/ojluni/annotations/hiddenapi/java/net/Socket.java
index 2ad18ff..495d134 100644
--- a/ojluni/annotations/hiddenapi/java/net/Socket.java
+++ b/ojluni/annotations/hiddenapi/java/net/Socket.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Socket implements java.io.Closeable {
diff --git a/ojluni/annotations/hiddenapi/java/net/SocketException.java b/ojluni/annotations/hiddenapi/java/net/SocketException.java
index 03e48e9..3775798 100644
--- a/ojluni/annotations/hiddenapi/java/net/SocketException.java
+++ b/ojluni/annotations/hiddenapi/java/net/SocketException.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class SocketException extends java.io.IOException {
diff --git a/ojluni/annotations/hiddenapi/java/net/SocketImpl.java b/ojluni/annotations/hiddenapi/java/net/SocketImpl.java
index be5c4f8..9b9461a 100644
--- a/ojluni/annotations/hiddenapi/java/net/SocketImpl.java
+++ b/ojluni/annotations/hiddenapi/java/net/SocketImpl.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class SocketImpl implements java.net.SocketOptions {
diff --git a/ojluni/annotations/hiddenapi/java/net/SocksSocketImpl.java b/ojluni/annotations/hiddenapi/java/net/SocksSocketImpl.java
index 6e0f66c..001d441 100644
--- a/ojluni/annotations/hiddenapi/java/net/SocksSocketImpl.java
+++ b/ojluni/annotations/hiddenapi/java/net/SocksSocketImpl.java
@@ -25,7 +25,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 class SocksSocketImpl extends java.net.PlainSocketImpl implements java.net.SocksConsts {
diff --git a/ojluni/annotations/hiddenapi/java/net/URI.java b/ojluni/annotations/hiddenapi/java/net/URI.java
index 2287ab8..ec7e242 100644
--- a/ojluni/annotations/hiddenapi/java/net/URI.java
+++ b/ojluni/annotations/hiddenapi/java/net/URI.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class URI implements java.lang.Comparable<java.net.URI>, java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/net/URL.java b/ojluni/annotations/hiddenapi/java/net/URL.java
index 905413c..9ba6358 100644
--- a/ojluni/annotations/hiddenapi/java/net/URL.java
+++ b/ojluni/annotations/hiddenapi/java/net/URL.java
@@ -26,7 +26,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class URL implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/net/URLClassLoader.java b/ojluni/annotations/hiddenapi/java/net/URLClassLoader.java
index 105b0c7..c9a040d 100644
--- a/ojluni/annotations/hiddenapi/java/net/URLClassLoader.java
+++ b/ojluni/annotations/hiddenapi/java/net/URLClassLoader.java
@@ -25,7 +25,7 @@
 
 package java.net;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class URLClassLoader extends java.security.SecureClassLoader implements java.io.Closeable {
diff --git a/ojluni/annotations/hiddenapi/java/nio/Buffer.java b/ojluni/annotations/hiddenapi/java/nio/Buffer.java
index cbcd8c1..fa8b31b 100644
--- a/ojluni/annotations/hiddenapi/java/nio/Buffer.java
+++ b/ojluni/annotations/hiddenapi/java/nio/Buffer.java
@@ -26,7 +26,7 @@
 
 package java.nio;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Buffer {
diff --git a/ojluni/annotations/hiddenapi/java/nio/ByteBuffer.java b/ojluni/annotations/hiddenapi/java/nio/ByteBuffer.java
index 65b6d58..32f53a4 100644
--- a/ojluni/annotations/hiddenapi/java/nio/ByteBuffer.java
+++ b/ojluni/annotations/hiddenapi/java/nio/ByteBuffer.java
@@ -28,7 +28,7 @@
 
 package java.nio;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class ByteBuffer extends java.nio.Buffer
diff --git a/ojluni/annotations/hiddenapi/java/nio/CharBuffer.java b/ojluni/annotations/hiddenapi/java/nio/CharBuffer.java
index 891e8c3..b447bb6 100644
--- a/ojluni/annotations/hiddenapi/java/nio/CharBuffer.java
+++ b/ojluni/annotations/hiddenapi/java/nio/CharBuffer.java
@@ -28,7 +28,7 @@
 
 package java.nio;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class CharBuffer extends java.nio.Buffer
diff --git a/ojluni/annotations/hiddenapi/java/nio/DirectByteBuffer.java b/ojluni/annotations/hiddenapi/java/nio/DirectByteBuffer.java
index 1d5e04f..b6ca5fb 100644
--- a/ojluni/annotations/hiddenapi/java/nio/DirectByteBuffer.java
+++ b/ojluni/annotations/hiddenapi/java/nio/DirectByteBuffer.java
@@ -26,7 +26,7 @@
 
 package java.nio;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class DirectByteBuffer extends java.nio.MappedByteBuffer implements sun.nio.ch.DirectBuffer {
diff --git a/ojluni/annotations/hiddenapi/java/nio/charset/Charset.java b/ojluni/annotations/hiddenapi/java/nio/charset/Charset.java
index daaa265..fb86662 100644
--- a/ojluni/annotations/hiddenapi/java/nio/charset/Charset.java
+++ b/ojluni/annotations/hiddenapi/java/nio/charset/Charset.java
@@ -26,7 +26,7 @@
 
 package java.nio.charset;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Charset implements java.lang.Comparable<java.nio.charset.Charset> {
diff --git a/ojluni/annotations/hiddenapi/java/nio/charset/CharsetEncoder.java b/ojluni/annotations/hiddenapi/java/nio/charset/CharsetEncoder.java
index f053cae..0e0fd2d 100644
--- a/ojluni/annotations/hiddenapi/java/nio/charset/CharsetEncoder.java
+++ b/ojluni/annotations/hiddenapi/java/nio/charset/CharsetEncoder.java
@@ -28,7 +28,7 @@
 
 package java.nio.charset;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class CharsetEncoder {
diff --git a/ojluni/annotations/hiddenapi/java/nio/file/FileTreeWalker.java b/ojluni/annotations/hiddenapi/java/nio/file/FileTreeWalker.java
index d3e6a42..0f9ae1e 100644
--- a/ojluni/annotations/hiddenapi/java/nio/file/FileTreeWalker.java
+++ b/ojluni/annotations/hiddenapi/java/nio/file/FileTreeWalker.java
@@ -72,20 +72,20 @@
 
     private boolean closed;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private final boolean followLinks;
+    @android.compat.annotation.UnsupportedAppUsage private final boolean followLinks;
 
     {
         followLinks = false;
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private final java.nio.file.LinkOption[] linkOptions;
 
     {
         linkOptions = new java.nio.file.LinkOption[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private final int maxDepth;
+    @android.compat.annotation.UnsupportedAppUsage private final int maxDepth;
 
     {
         maxDepth = 0;
diff --git a/ojluni/annotations/hiddenapi/java/security/KeyPairGenerator.java b/ojluni/annotations/hiddenapi/java/security/KeyPairGenerator.java
index 2dba7cd..e5ceb2a 100644
--- a/ojluni/annotations/hiddenapi/java/security/KeyPairGenerator.java
+++ b/ojluni/annotations/hiddenapi/java/security/KeyPairGenerator.java
@@ -25,7 +25,7 @@
 
 package java.security;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class KeyPairGenerator extends java.security.KeyPairGeneratorSpi {
diff --git a/ojluni/annotations/hiddenapi/java/security/KeyStore.java b/ojluni/annotations/hiddenapi/java/security/KeyStore.java
index ae64169..6bf29a1 100644
--- a/ojluni/annotations/hiddenapi/java/security/KeyStore.java
+++ b/ojluni/annotations/hiddenapi/java/security/KeyStore.java
@@ -25,7 +25,7 @@
 
 package java.security;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class KeyStore {
diff --git a/ojluni/annotations/hiddenapi/java/security/Signature.java b/ojluni/annotations/hiddenapi/java/security/Signature.java
index a249f65..f9d4ab7 100644
--- a/ojluni/annotations/hiddenapi/java/security/Signature.java
+++ b/ojluni/annotations/hiddenapi/java/security/Signature.java
@@ -26,7 +26,7 @@
 
 package java.security;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Signature extends java.security.SignatureSpi {
diff --git a/ojluni/annotations/hiddenapi/java/security/spec/ECParameterSpec.java b/ojluni/annotations/hiddenapi/java/security/spec/ECParameterSpec.java
index db13a4b..3166787 100644
--- a/ojluni/annotations/hiddenapi/java/security/spec/ECParameterSpec.java
+++ b/ojluni/annotations/hiddenapi/java/security/spec/ECParameterSpec.java
@@ -26,7 +26,7 @@
 
 package java.security.spec;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ECParameterSpec implements java.security.spec.AlgorithmParameterSpec {
diff --git a/ojluni/annotations/hiddenapi/java/text/Collator.java b/ojluni/annotations/hiddenapi/java/text/Collator.java
index 82aa868..befb9b9 100644
--- a/ojluni/annotations/hiddenapi/java/text/Collator.java
+++ b/ojluni/annotations/hiddenapi/java/text/Collator.java
@@ -39,7 +39,7 @@
 
 package java.text;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Collator
diff --git a/ojluni/annotations/hiddenapi/java/text/DateFormat.java b/ojluni/annotations/hiddenapi/java/text/DateFormat.java
index 7a1973f..2b8ed78 100644
--- a/ojluni/annotations/hiddenapi/java/text/DateFormat.java
+++ b/ojluni/annotations/hiddenapi/java/text/DateFormat.java
@@ -39,7 +39,7 @@
 
 package java.text;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class DateFormat extends java.text.Format {
diff --git a/ojluni/annotations/hiddenapi/java/text/DecimalFormatSymbols.java b/ojluni/annotations/hiddenapi/java/text/DecimalFormatSymbols.java
index 52395a9..1b0a68c 100644
--- a/ojluni/annotations/hiddenapi/java/text/DecimalFormatSymbols.java
+++ b/ojluni/annotations/hiddenapi/java/text/DecimalFormatSymbols.java
@@ -39,7 +39,7 @@
 
 package java.text;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class DecimalFormatSymbols implements java.lang.Cloneable, java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/text/NumberFormat.java b/ojluni/annotations/hiddenapi/java/text/NumberFormat.java
index a570716..232c94f 100644
--- a/ojluni/annotations/hiddenapi/java/text/NumberFormat.java
+++ b/ojluni/annotations/hiddenapi/java/text/NumberFormat.java
@@ -39,7 +39,7 @@
 
 package java.text;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class NumberFormat extends java.text.Format {
diff --git a/ojluni/annotations/hiddenapi/java/time/Duration.java b/ojluni/annotations/hiddenapi/java/time/Duration.java
index 3090adb..ca99832 100644
--- a/ojluni/annotations/hiddenapi/java/time/Duration.java
+++ b/ojluni/annotations/hiddenapi/java/time/Duration.java
@@ -62,7 +62,7 @@
 
 package java.time;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Duration
diff --git a/ojluni/annotations/hiddenapi/java/time/OffsetDateTime.java b/ojluni/annotations/hiddenapi/java/time/OffsetDateTime.java
index f95f12f..d4822c4 100644
--- a/ojluni/annotations/hiddenapi/java/time/OffsetDateTime.java
+++ b/ojluni/annotations/hiddenapi/java/time/OffsetDateTime.java
@@ -62,7 +62,7 @@
 
 package java.time;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class OffsetDateTime
diff --git a/ojluni/annotations/hiddenapi/java/time/ZoneId.java b/ojluni/annotations/hiddenapi/java/time/ZoneId.java
index f3ae76a..ef4a7aa 100644
--- a/ojluni/annotations/hiddenapi/java/time/ZoneId.java
+++ b/ojluni/annotations/hiddenapi/java/time/ZoneId.java
@@ -62,7 +62,7 @@
 
 package java.time;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class ZoneId implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/util/ArrayDeque.java b/ojluni/annotations/hiddenapi/java/util/ArrayDeque.java
index 59315d8..65c684a 100644
--- a/ojluni/annotations/hiddenapi/java/util/ArrayDeque.java
+++ b/ojluni/annotations/hiddenapi/java/util/ArrayDeque.java
@@ -34,7 +34,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ArrayDeque<E> extends java.util.AbstractCollection<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/ArrayList.java b/ojluni/annotations/hiddenapi/java/util/ArrayList.java
index 7457f1e..3d90fa5 100644
--- a/ojluni/annotations/hiddenapi/java/util/ArrayList.java
+++ b/ojluni/annotations/hiddenapi/java/util/ArrayList.java
@@ -26,7 +26,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ArrayList<E> extends java.util.AbstractList<E>
@@ -425,7 +425,9 @@
             parentOffset = 0;
         }
 
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(publicAlternatives = "Please update to a current version of the "
+        + "{@code Streamsupport} library; older versions of {@code Streamsupport} do not "
+        + "support current versions of Android.")
         int size;
     }
 }
diff --git a/ojluni/annotations/hiddenapi/java/util/Arrays.java b/ojluni/annotations/hiddenapi/java/util/Arrays.java
index c763a2d..040c8b0 100644
--- a/ojluni/annotations/hiddenapi/java/util/Arrays.java
+++ b/ojluni/annotations/hiddenapi/java/util/Arrays.java
@@ -26,7 +26,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Arrays {
diff --git a/ojluni/annotations/hiddenapi/java/util/Calendar.java b/ojluni/annotations/hiddenapi/java/util/Calendar.java
index 99a76f7..274f801 100644
--- a/ojluni/annotations/hiddenapi/java/util/Calendar.java
+++ b/ojluni/annotations/hiddenapi/java/util/Calendar.java
@@ -39,7 +39,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Calendar
diff --git a/ojluni/annotations/hiddenapi/java/util/Collections.java b/ojluni/annotations/hiddenapi/java/util/Collections.java
index 010ba3d..d7445f0 100644
--- a/ojluni/annotations/hiddenapi/java/util/Collections.java
+++ b/ojluni/annotations/hiddenapi/java/util/Collections.java
@@ -26,7 +26,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Collections {
diff --git a/ojluni/annotations/hiddenapi/java/util/EnumMap.java b/ojluni/annotations/hiddenapi/java/util/EnumMap.java
index 81cd885..5b0c31f 100644
--- a/ojluni/annotations/hiddenapi/java/util/EnumMap.java
+++ b/ojluni/annotations/hiddenapi/java/util/EnumMap.java
@@ -26,7 +26,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class EnumMap<K extends java.lang.Enum<K>, V> extends java.util.AbstractMap<K, V>
diff --git a/ojluni/annotations/hiddenapi/java/util/EnumSet.java b/ojluni/annotations/hiddenapi/java/util/EnumSet.java
index f8edb19..6c920b0 100644
--- a/ojluni/annotations/hiddenapi/java/util/EnumSet.java
+++ b/ojluni/annotations/hiddenapi/java/util/EnumSet.java
@@ -26,7 +26,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class EnumSet<E extends java.lang.Enum<E>> extends java.util.AbstractSet<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/HashMap.java b/ojluni/annotations/hiddenapi/java/util/HashMap.java
index af1c342..b13c25c 100644
--- a/ojluni/annotations/hiddenapi/java/util/HashMap.java
+++ b/ojluni/annotations/hiddenapi/java/util/HashMap.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class HashMap<K, V> extends java.util.AbstractMap<K, V>
diff --git a/ojluni/annotations/hiddenapi/java/util/HashSet.java b/ojluni/annotations/hiddenapi/java/util/HashSet.java
index a006121..896c1aa 100644
--- a/ojluni/annotations/hiddenapi/java/util/HashSet.java
+++ b/ojluni/annotations/hiddenapi/java/util/HashSet.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class HashSet<E> extends java.util.AbstractSet<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/LinkedHashMap.java b/ojluni/annotations/hiddenapi/java/util/LinkedHashMap.java
index 8294334..99d649b 100644
--- a/ojluni/annotations/hiddenapi/java/util/LinkedHashMap.java
+++ b/ojluni/annotations/hiddenapi/java/util/LinkedHashMap.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class LinkedHashMap<K, V> extends java.util.HashMap<K, V> implements java.util.Map<K, V> {
diff --git a/ojluni/annotations/hiddenapi/java/util/LinkedList.java b/ojluni/annotations/hiddenapi/java/util/LinkedList.java
index c7eb048..58cbb5f 100644
--- a/ojluni/annotations/hiddenapi/java/util/LinkedList.java
+++ b/ojluni/annotations/hiddenapi/java/util/LinkedList.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class LinkedList<E> extends java.util.AbstractSequentialList<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/Locale.java b/ojluni/annotations/hiddenapi/java/util/Locale.java
index 3f6a54f..73d2dfa 100644
--- a/ojluni/annotations/hiddenapi/java/util/Locale.java
+++ b/ojluni/annotations/hiddenapi/java/util/Locale.java
@@ -41,7 +41,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Locale implements java.lang.Cloneable, java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/util/PriorityQueue.java b/ojluni/annotations/hiddenapi/java/util/PriorityQueue.java
index b8d2a18..09c9d86 100644
--- a/ojluni/annotations/hiddenapi/java/util/PriorityQueue.java
+++ b/ojluni/annotations/hiddenapi/java/util/PriorityQueue.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class PriorityQueue<E> extends java.util.AbstractQueue<E> implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/util/Properties.java b/ojluni/annotations/hiddenapi/java/util/Properties.java
index 3aee2d1..397fa75 100644
--- a/ojluni/annotations/hiddenapi/java/util/Properties.java
+++ b/ojluni/annotations/hiddenapi/java/util/Properties.java
@@ -26,7 +26,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Properties extends java.util.Hashtable<java.lang.Object, java.lang.Object> {
diff --git a/ojluni/annotations/hiddenapi/java/util/Random.java b/ojluni/annotations/hiddenapi/java/util/Random.java
index ce80aa1..930688a 100644
--- a/ojluni/annotations/hiddenapi/java/util/Random.java
+++ b/ojluni/annotations/hiddenapi/java/util/Random.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Random implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/util/TimerTask.java b/ojluni/annotations/hiddenapi/java/util/TimerTask.java
index 8a5c6d5..65c845c 100644
--- a/ojluni/annotations/hiddenapi/java/util/TimerTask.java
+++ b/ojluni/annotations/hiddenapi/java/util/TimerTask.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class TimerTask implements java.lang.Runnable {
diff --git a/ojluni/annotations/hiddenapi/java/util/UUID.java b/ojluni/annotations/hiddenapi/java/util/UUID.java
index 0585e5de..353f2b6 100644
--- a/ojluni/annotations/hiddenapi/java/util/UUID.java
+++ b/ojluni/annotations/hiddenapi/java/util/UUID.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class UUID implements java.io.Serializable, java.lang.Comparable<java.util.UUID> {
diff --git a/ojluni/annotations/hiddenapi/java/util/Vector.java b/ojluni/annotations/hiddenapi/java/util/Vector.java
index 394a097..91a6aa7 100644
--- a/ojluni/annotations/hiddenapi/java/util/Vector.java
+++ b/ojluni/annotations/hiddenapi/java/util/Vector.java
@@ -25,7 +25,7 @@
 
 package java.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Vector<E> extends java.util.AbstractList<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/CopyOnWriteArrayList.java b/ojluni/annotations/hiddenapi/java/util/concurrent/CopyOnWriteArrayList.java
index 7d526a7..5a19180 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/CopyOnWriteArrayList.java
@@ -34,7 +34,7 @@
 
 package java.util.concurrent;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CopyOnWriteArrayList<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/CopyOnWriteArraySet.java b/ojluni/annotations/hiddenapi/java/util/concurrent/CopyOnWriteArraySet.java
index 98c53b0..2450ff4 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/CopyOnWriteArraySet.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/CopyOnWriteArraySet.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CopyOnWriteArraySet<E> extends java.util.AbstractSet<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/Executors.java b/ojluni/annotations/hiddenapi/java/util/concurrent/Executors.java
index 1fbd62c..cd64ac8 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/Executors.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/Executors.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Executors {
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/FutureTask.java b/ojluni/annotations/hiddenapi/java/util/concurrent/FutureTask.java
index 2274611..24746d4 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/FutureTask.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/FutureTask.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class FutureTask<V> implements java.util.concurrent.RunnableFuture<V> {
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/LinkedBlockingDeque.java b/ojluni/annotations/hiddenapi/java/util/concurrent/LinkedBlockingDeque.java
index de84037..391ba63 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/LinkedBlockingDeque.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/LinkedBlockingDeque.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class LinkedBlockingDeque<E> extends java.util.AbstractQueue<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/LinkedBlockingQueue.java b/ojluni/annotations/hiddenapi/java/util/concurrent/LinkedBlockingQueue.java
index f7aec5c..683a8f1 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/LinkedBlockingQueue.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/LinkedBlockingQueue.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class LinkedBlockingQueue<E> extends java.util.AbstractQueue<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/PriorityBlockingQueue.java b/ojluni/annotations/hiddenapi/java/util/concurrent/PriorityBlockingQueue.java
index 0577e8c..35bc3c0 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/PriorityBlockingQueue.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/PriorityBlockingQueue.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class PriorityBlockingQueue<E> extends java.util.AbstractQueue<E>
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/ThreadPoolExecutor.java b/ojluni/annotations/hiddenapi/java/util/concurrent/ThreadPoolExecutor.java
index e89f678..0d27711 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/ThreadPoolExecutor.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/ThreadPoolExecutor.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ThreadPoolExecutor extends java.util.concurrent.AbstractExecutorService {
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/atomic/AtomicInteger.java b/ojluni/annotations/hiddenapi/java/util/concurrent/atomic/AtomicInteger.java
index a5718ac..ed7ef76 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/atomic/AtomicInteger.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/atomic/AtomicInteger.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent.atomic;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class AtomicInteger extends java.lang.Number implements java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/util/concurrent/locks/ReentrantLock.java b/ojluni/annotations/hiddenapi/java/util/concurrent/locks/ReentrantLock.java
index 1ad6e8d..8921208 100644
--- a/ojluni/annotations/hiddenapi/java/util/concurrent/locks/ReentrantLock.java
+++ b/ojluni/annotations/hiddenapi/java/util/concurrent/locks/ReentrantLock.java
@@ -35,7 +35,7 @@
 
 package java.util.concurrent.locks;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ReentrantLock implements java.util.concurrent.locks.Lock, java.io.Serializable {
diff --git a/ojluni/annotations/hiddenapi/java/util/jar/JarFile.java b/ojluni/annotations/hiddenapi/java/util/jar/JarFile.java
index 1c97964..3c7d7bb 100644
--- a/ojluni/annotations/hiddenapi/java/util/jar/JarFile.java
+++ b/ojluni/annotations/hiddenapi/java/util/jar/JarFile.java
@@ -26,7 +26,7 @@
 
 package java.util.jar;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class JarFile extends java.util.zip.ZipFile {
diff --git a/ojluni/annotations/hiddenapi/java/util/logging/Handler.java b/ojluni/annotations/hiddenapi/java/util/logging/Handler.java
index 2d04f15..7243f48 100644
--- a/ojluni/annotations/hiddenapi/java/util/logging/Handler.java
+++ b/ojluni/annotations/hiddenapi/java/util/logging/Handler.java
@@ -25,7 +25,7 @@
 
 package java.util.logging;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Handler {
diff --git a/ojluni/annotations/hiddenapi/java/util/logging/LogManager.java b/ojluni/annotations/hiddenapi/java/util/logging/LogManager.java
index a140100..8900a5a 100644
--- a/ojluni/annotations/hiddenapi/java/util/logging/LogManager.java
+++ b/ojluni/annotations/hiddenapi/java/util/logging/LogManager.java
@@ -26,7 +26,7 @@
 
 package java.util.logging;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class LogManager {
diff --git a/ojluni/annotations/hiddenapi/java/util/logging/Logger.java b/ojluni/annotations/hiddenapi/java/util/logging/Logger.java
index f504c96..1c14d54 100644
--- a/ojluni/annotations/hiddenapi/java/util/logging/Logger.java
+++ b/ojluni/annotations/hiddenapi/java/util/logging/Logger.java
@@ -25,7 +25,7 @@
 
 package java.util.logging;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Logger {
diff --git a/ojluni/annotations/hiddenapi/java/util/regex/Matcher.java b/ojluni/annotations/hiddenapi/java/util/regex/Matcher.java
index 18d6d95..686f1bd 100644
--- a/ojluni/annotations/hiddenapi/java/util/regex/Matcher.java
+++ b/ojluni/annotations/hiddenapi/java/util/regex/Matcher.java
@@ -26,7 +26,7 @@
 
 package java.util.regex;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Matcher implements java.util.regex.MatchResult {
diff --git a/ojluni/annotations/hiddenapi/java/util/zip/Adler32.java b/ojluni/annotations/hiddenapi/java/util/zip/Adler32.java
index f78844f..e22aec4 100644
--- a/ojluni/annotations/hiddenapi/java/util/zip/Adler32.java
+++ b/ojluni/annotations/hiddenapi/java/util/zip/Adler32.java
@@ -25,7 +25,7 @@
 
 package java.util.zip;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Adler32 implements java.util.zip.Checksum {
diff --git a/ojluni/annotations/hiddenapi/java/util/zip/CRC32.java b/ojluni/annotations/hiddenapi/java/util/zip/CRC32.java
index 0e25349..6766fa1 100644
--- a/ojluni/annotations/hiddenapi/java/util/zip/CRC32.java
+++ b/ojluni/annotations/hiddenapi/java/util/zip/CRC32.java
@@ -25,7 +25,7 @@
 
 package java.util.zip;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CRC32 implements java.util.zip.Checksum {
diff --git a/ojluni/annotations/hiddenapi/java/util/zip/Deflater.java b/ojluni/annotations/hiddenapi/java/util/zip/Deflater.java
index f8f419d..0dbe2a5 100644
--- a/ojluni/annotations/hiddenapi/java/util/zip/Deflater.java
+++ b/ojluni/annotations/hiddenapi/java/util/zip/Deflater.java
@@ -25,7 +25,7 @@
 
 package java.util.zip;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Deflater {
diff --git a/ojluni/annotations/hiddenapi/java/util/zip/Inflater.java b/ojluni/annotations/hiddenapi/java/util/zip/Inflater.java
index c4194d2..e5a5dcc 100644
--- a/ojluni/annotations/hiddenapi/java/util/zip/Inflater.java
+++ b/ojluni/annotations/hiddenapi/java/util/zip/Inflater.java
@@ -26,7 +26,7 @@
 
 package java.util.zip;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Inflater {
diff --git a/ojluni/annotations/hiddenapi/java/util/zip/ZipEntry.java b/ojluni/annotations/hiddenapi/java/util/zip/ZipEntry.java
index 87ca0f5..91440c2 100644
--- a/ojluni/annotations/hiddenapi/java/util/zip/ZipEntry.java
+++ b/ojluni/annotations/hiddenapi/java/util/zip/ZipEntry.java
@@ -26,7 +26,7 @@
 
 package java.util.zip;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ZipEntry implements java.util.zip.ZipConstants, java.lang.Cloneable {
diff --git a/ojluni/annotations/hiddenapi/java/util/zip/ZipFile.java b/ojluni/annotations/hiddenapi/java/util/zip/ZipFile.java
index 371659a..b2c72a7 100644
--- a/ojluni/annotations/hiddenapi/java/util/zip/ZipFile.java
+++ b/ojluni/annotations/hiddenapi/java/util/zip/ZipFile.java
@@ -26,7 +26,7 @@
 
 package java.util.zip;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ZipFile implements java.util.zip.ZipConstants, java.io.Closeable {
diff --git a/ojluni/annotations/hiddenapi/java/util/zip/ZipInputStream.java b/ojluni/annotations/hiddenapi/java/util/zip/ZipInputStream.java
index 90947b7..18c1b2e 100644
--- a/ojluni/annotations/hiddenapi/java/util/zip/ZipInputStream.java
+++ b/ojluni/annotations/hiddenapi/java/util/zip/ZipInputStream.java
@@ -26,7 +26,7 @@
 
 package java.util.zip;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ZipInputStream extends java.util.zip.InflaterInputStream
diff --git a/ojluni/annotations/hiddenapi/java/util/zip/ZipOutputStream.java b/ojluni/annotations/hiddenapi/java/util/zip/ZipOutputStream.java
index 943fefa..fd4276a 100644
--- a/ojluni/annotations/hiddenapi/java/util/zip/ZipOutputStream.java
+++ b/ojluni/annotations/hiddenapi/java/util/zip/ZipOutputStream.java
@@ -26,7 +26,7 @@
 
 package java.util.zip;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ZipOutputStream extends java.util.zip.DeflaterOutputStream
diff --git a/ojluni/annotations/hiddenapi/javax/net/ssl/SSLServerSocketFactory.java b/ojluni/annotations/hiddenapi/javax/net/ssl/SSLServerSocketFactory.java
index 26989a8..e947a88 100644
--- a/ojluni/annotations/hiddenapi/javax/net/ssl/SSLServerSocketFactory.java
+++ b/ojluni/annotations/hiddenapi/javax/net/ssl/SSLServerSocketFactory.java
@@ -26,8 +26,8 @@
 
 package javax.net.ssl;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class SSLServerSocketFactory extends javax.net.ServerSocketFactory {
@@ -55,7 +55,11 @@
      * changes.
      */
     @UnsupportedAppUsage(maxTargetSdk = VersionCodes.P,
-        trackingBug = 118741276)
+        trackingBug = 118741276,
+        publicAlternatives = "Use {@link #getDefault()} to read the current default; from Android "
+        + "API level 21 onwards, apps should have no need to ever write this value because it is "
+        + "automatically recomputed when the set of {@link java.security.Provider} security "
+        + "providers changes.")
     private static javax.net.ssl.SSLServerSocketFactory defaultServerSocketFactory;
 
     private static int lastVersion = -1; // 0xffffffff
diff --git a/ojluni/annotations/hiddenapi/javax/net/ssl/SSLSocketFactory.java b/ojluni/annotations/hiddenapi/javax/net/ssl/SSLSocketFactory.java
index 6ce4b5e..b945122 100644
--- a/ojluni/annotations/hiddenapi/javax/net/ssl/SSLSocketFactory.java
+++ b/ojluni/annotations/hiddenapi/javax/net/ssl/SSLSocketFactory.java
@@ -26,8 +26,8 @@
 
 package javax.net.ssl;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class SSLSocketFactory extends javax.net.SocketFactory {
@@ -76,7 +76,11 @@
      * changes.
      */
     @UnsupportedAppUsage(maxTargetSdk = VersionCodes.P,
-            trackingBug = 118741276)
+            trackingBug = 118741276,
+            publicAlternatives = "Use {@link #getDefault()} to read the current default; from "
+            + "Android API level 21 onwards, apps should have no need to ever write this value "
+            + "because it is automatically recomputed when the set of "
+            + "{@link java.security.Provider} security providers changes.")
     private static javax.net.ssl.SSLSocketFactory defaultSocketFactory;
 
     private static int lastVersion = -1; // 0xffffffff
diff --git a/ojluni/annotations/hiddenapi/sun/misc/ASCIICaseInsensitiveComparator.java b/ojluni/annotations/hiddenapi/sun/misc/ASCIICaseInsensitiveComparator.java
index b632c1e..2df53e2 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/ASCIICaseInsensitiveComparator.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/ASCIICaseInsensitiveComparator.java
@@ -36,7 +36,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static int lowerCaseHashCode(java.lang.String s) {
         throw new RuntimeException("Stub!");
     }
@@ -57,7 +57,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final java.util.Comparator<java.lang.String> CASE_INSENSITIVE_ORDER;
 
     static {
diff --git a/ojluni/annotations/hiddenapi/sun/misc/BASE64Decoder.java b/ojluni/annotations/hiddenapi/sun/misc/BASE64Decoder.java
index 2ce6dc8..65b4682 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/BASE64Decoder.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/BASE64Decoder.java
@@ -28,7 +28,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class BASE64Decoder extends sun.misc.CharacterDecoder {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public BASE64Decoder() {
         throw new RuntimeException("Stub!");
     }
@@ -55,7 +55,7 @@
         pem_array = new char[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private static final byte[] pem_convert_array;
+    @android.compat.annotation.UnsupportedAppUsage private static final byte[] pem_convert_array;
 
     static {
         pem_convert_array = new byte[0];
diff --git a/ojluni/annotations/hiddenapi/sun/misc/BASE64Encoder.java b/ojluni/annotations/hiddenapi/sun/misc/BASE64Encoder.java
index 8a9ef70..146b543 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/BASE64Encoder.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/BASE64Encoder.java
@@ -28,7 +28,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class BASE64Encoder extends sun.misc.CharacterEncoder {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public BASE64Encoder() {
         throw new RuntimeException("Stub!");
     }
@@ -46,7 +46,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private static final char[] pem_array;
+    @android.compat.annotation.UnsupportedAppUsage private static final char[] pem_array;
 
     static {
         pem_array = new char[0];
diff --git a/ojluni/annotations/hiddenapi/sun/misc/CEFormatException.java b/ojluni/annotations/hiddenapi/sun/misc/CEFormatException.java
index d351479..d52e699 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/CEFormatException.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/CEFormatException.java
@@ -28,7 +28,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CEFormatException extends java.io.IOException {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CEFormatException(java.lang.String s) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/CEStreamExhausted.java b/ojluni/annotations/hiddenapi/sun/misc/CEStreamExhausted.java
index e696c67..e78d20e 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/CEStreamExhausted.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/CEStreamExhausted.java
@@ -28,7 +28,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CEStreamExhausted extends java.io.IOException {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CEStreamExhausted() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/CharacterDecoder.java b/ojluni/annotations/hiddenapi/sun/misc/CharacterDecoder.java
index de6f942..1b769fa 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/CharacterDecoder.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/CharacterDecoder.java
@@ -29,7 +29,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class CharacterDecoder {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CharacterDecoder() {
         throw new RuntimeException("Stub!");
     }
@@ -78,7 +78,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] decodeBuffer(java.lang.String inputString) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/CharacterEncoder.java b/ojluni/annotations/hiddenapi/sun/misc/CharacterEncoder.java
index bbbf3f7..b254846 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/CharacterEncoder.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/CharacterEncoder.java
@@ -29,7 +29,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class CharacterEncoder {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CharacterEncoder() {
         throw new RuntimeException("Stub!");
     }
@@ -38,7 +38,7 @@
 
     protected abstract int bytesPerLine();
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     protected void encodeBufferPrefix(java.io.OutputStream aStream) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -73,7 +73,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String encode(byte[] aBuffer) {
         throw new RuntimeException("Stub!");
     }
@@ -101,7 +101,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String encodeBuffer(byte[] aBuffer) {
         throw new RuntimeException("Stub!");
     }
@@ -115,6 +115,6 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     protected java.io.PrintStream pStream;
 }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/Cleaner.java b/ojluni/annotations/hiddenapi/sun/misc/Cleaner.java
index eb21393..cdbc658 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/Cleaner.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/Cleaner.java
@@ -25,7 +25,7 @@
 
 package sun.misc;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class Cleaner extends java.lang.ref.PhantomReference<java.lang.Object> {
diff --git a/ojluni/annotations/hiddenapi/sun/misc/FloatingDecimal.java b/ojluni/annotations/hiddenapi/sun/misc/FloatingDecimal.java
index 0c210ac..fd8c668 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/FloatingDecimal.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/FloatingDecimal.java
@@ -86,17 +86,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     static java.lang.String stripLeadingZeros(java.lang.String s) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     static int getHexDigit(java.lang.String s, int position) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private static boolean $assertionsDisabled;
+    @android.compat.annotation.UnsupportedAppUsage private static boolean $assertionsDisabled;
 
     static final sun.misc.FloatingDecimal.ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY;
 
diff --git a/ojluni/annotations/hiddenapi/sun/misc/FormattedFloatingDecimal.java b/ojluni/annotations/hiddenapi/sun/misc/FormattedFloatingDecimal.java
index b6766cf..a752931 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/FormattedFloatingDecimal.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/FormattedFloatingDecimal.java
@@ -79,7 +79,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private static boolean $assertionsDisabled;
+    @android.compat.annotation.UnsupportedAppUsage private static boolean $assertionsDisabled;
 
     private int decExponentRounded;
 
@@ -95,11 +95,11 @@
 
     @SuppressWarnings({"unchecked", "deprecation", "all"})
     public static enum Form {
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         SCIENTIFIC,
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         COMPATIBLE,
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         DECIMAL_FLOAT,
         GENERAL;
 
diff --git a/ojluni/annotations/hiddenapi/sun/misc/FpUtils.java b/ojluni/annotations/hiddenapi/sun/misc/FpUtils.java
index 38347bd..16bb5b0 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/FpUtils.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/FpUtils.java
@@ -43,7 +43,7 @@
     }
 
     @Deprecated
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static double rawCopySign(double magnitude, double sign) {
         throw new RuntimeException("Stub!");
     }
@@ -165,5 +165,5 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private static boolean $assertionsDisabled;
+    @android.compat.annotation.UnsupportedAppUsage private static boolean $assertionsDisabled;
 }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/HexDumpEncoder.java b/ojluni/annotations/hiddenapi/sun/misc/HexDumpEncoder.java
index f278c74..c92af9a 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/HexDumpEncoder.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/HexDumpEncoder.java
@@ -28,7 +28,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class HexDumpEncoder extends sun.misc.CharacterEncoder {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public HexDumpEncoder() {
         throw new RuntimeException("Stub!");
     }
@@ -62,11 +62,11 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private int currentByte;
+    @android.compat.annotation.UnsupportedAppUsage private int currentByte;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private int offset;
+    @android.compat.annotation.UnsupportedAppUsage private int offset;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private byte[] thisLine;
+    @android.compat.annotation.UnsupportedAppUsage private byte[] thisLine;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private int thisLineLength;
+    @android.compat.annotation.UnsupportedAppUsage private int thisLineLength;
 }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/IOUtils.java b/ojluni/annotations/hiddenapi/sun/misc/IOUtils.java
index 90f7909..251261b 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/IOUtils.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/IOUtils.java
@@ -34,7 +34,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static byte[] readFully(java.io.InputStream is, int length, boolean readAll)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
diff --git a/ojluni/annotations/hiddenapi/sun/misc/JarIndex.java b/ojluni/annotations/hiddenapi/sun/misc/JarIndex.java
index 06187e1..a93d1de 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/JarIndex.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/JarIndex.java
@@ -41,7 +41,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public JarIndex(java.lang.String[] files) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -83,7 +83,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void write(java.io.OutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/MessageUtils.java b/ojluni/annotations/hiddenapi/sun/misc/MessageUtils.java
index bd61419..9fe08e4 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/MessageUtils.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/MessageUtils.java
@@ -29,7 +29,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class MessageUtils {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public MessageUtils() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/MetaIndex.java b/ojluni/annotations/hiddenapi/sun/misc/MetaIndex.java
index b3ae0cc..4c38d41 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/MetaIndex.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/MetaIndex.java
@@ -33,12 +33,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.misc.MetaIndex forJar(java.io.File jar) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static synchronized void registerDirectory(java.io.File dir) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/misc/URLClassPath.java b/ojluni/annotations/hiddenapi/sun/misc/URLClassPath.java
index 7ca8bd9..561a21c 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/URLClassPath.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/URLClassPath.java
@@ -26,7 +26,7 @@
 
 package sun.misc;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class URLClassPath {
diff --git a/ojluni/annotations/hiddenapi/sun/misc/Unsafe.java b/ojluni/annotations/hiddenapi/sun/misc/Unsafe.java
index 54308e4..c6dad00 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/Unsafe.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/Unsafe.java
@@ -25,8 +25,9 @@
 
 package sun.misc;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
-import dalvik.system.VersionCodes;
+import android.compat.annotation.UnsupportedAppUsage;
+
+import dalvik.annotation.compat.VersionCodes;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Unsafe {
diff --git a/ojluni/annotations/hiddenapi/sun/misc/VM.java b/ojluni/annotations/hiddenapi/sun/misc/VM.java
index 979818c..a043c57 100644
--- a/ojluni/annotations/hiddenapi/sun/misc/VM.java
+++ b/ojluni/annotations/hiddenapi/sun/misc/VM.java
@@ -83,7 +83,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static long maxDirectMemory() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/net/ftp/FtpClient.java b/ojluni/annotations/hiddenapi/sun/net/ftp/FtpClient.java
index c60accd..0a54520 100644
--- a/ojluni/annotations/hiddenapi/sun/net/ftp/FtpClient.java
+++ b/ojluni/annotations/hiddenapi/sun/net/ftp/FtpClient.java
@@ -31,7 +31,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class FtpClient implements java.io.Closeable {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     protected FtpClient() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/net/util/IPAddressUtil.java b/ojluni/annotations/hiddenapi/sun/net/util/IPAddressUtil.java
index 710e3a8..0134b09 100644
--- a/ojluni/annotations/hiddenapi/sun/net/util/IPAddressUtil.java
+++ b/ojluni/annotations/hiddenapi/sun/net/util/IPAddressUtil.java
@@ -40,12 +40,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static boolean isIPv4LiteralAddress(java.lang.String src) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static boolean isIPv6LiteralAddress(java.lang.String src) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/net/www/MessageHeader.java b/ojluni/annotations/hiddenapi/sun/net/www/MessageHeader.java
index c63d115..4afd134 100644
--- a/ojluni/annotations/hiddenapi/sun/net/www/MessageHeader.java
+++ b/ojluni/annotations/hiddenapi/sun/net/www/MessageHeader.java
@@ -35,12 +35,12 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class MessageHeader {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public MessageHeader() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public MessageHeader(java.io.InputStream is) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -53,7 +53,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public synchronized java.lang.String findValue(java.lang.String k) {
         throw new RuntimeException("Stub!");
     }
@@ -99,17 +99,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public synchronized void print(java.io.PrintStream p) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public synchronized void add(java.lang.String k, java.lang.String v) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public synchronized void prepend(java.lang.String k, java.lang.String v) {
         throw new RuntimeException("Stub!");
     }
@@ -126,7 +126,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public synchronized void set(java.lang.String k, java.lang.String v) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/net/www/ParseUtil.java b/ojluni/annotations/hiddenapi/sun/net/www/ParseUtil.java
index d439a1f..3acc9ee 100644
--- a/ojluni/annotations/hiddenapi/sun/net/www/ParseUtil.java
+++ b/ojluni/annotations/hiddenapi/sun/net/www/ParseUtil.java
@@ -37,7 +37,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.lang.String encodePath(java.lang.String path, boolean flag) {
         throw new RuntimeException("Stub!");
     }
@@ -50,7 +50,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.lang.String decode(java.lang.String s) {
         throw new RuntimeException("Stub!");
     }
@@ -59,7 +59,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.net.URL fileToEncodedURL(java.io.File file)
             throws java.net.MalformedURLException {
         throw new RuntimeException("Stub!");
diff --git a/ojluni/annotations/hiddenapi/sun/net/www/URLConnection.java b/ojluni/annotations/hiddenapi/sun/net/www/URLConnection.java
index 7669272..12b1d72 100644
--- a/ojluni/annotations/hiddenapi/sun/net/www/URLConnection.java
+++ b/ojluni/annotations/hiddenapi/sun/net/www/URLConnection.java
@@ -25,12 +25,10 @@
 
 package sun.net.www;
 
-import java.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class URLConnection extends java.net.URLConnection {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public URLConnection(java.net.URL u) {
         super(null);
         throw new RuntimeException("Stub!");
@@ -40,7 +38,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void setProperties(sun.net.www.MessageHeader properties) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/nio/ch/DirectBuffer.java b/ojluni/annotations/hiddenapi/sun/nio/ch/DirectBuffer.java
index e755c28..87a2447 100644
--- a/ojluni/annotations/hiddenapi/sun/nio/ch/DirectBuffer.java
+++ b/ojluni/annotations/hiddenapi/sun/nio/ch/DirectBuffer.java
@@ -25,7 +25,7 @@
 
 package sun.nio.ch;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public interface DirectBuffer {
diff --git a/ojluni/annotations/hiddenapi/sun/nio/ch/FileChannelImpl.java b/ojluni/annotations/hiddenapi/sun/nio/ch/FileChannelImpl.java
index ca3f145..7ab1dc2 100644
--- a/ojluni/annotations/hiddenapi/sun/nio/ch/FileChannelImpl.java
+++ b/ojluni/annotations/hiddenapi/sun/nio/ch/FileChannelImpl.java
@@ -207,7 +207,7 @@
 
     private native long map0(int prot, long position, long length) throws java.io.IOException;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static native int unmap0(long address, long length);
 
     private native long transferTo0(
diff --git a/ojluni/annotations/hiddenapi/sun/nio/ch/SelectorImpl.java b/ojluni/annotations/hiddenapi/sun/nio/ch/SelectorImpl.java
index 294cdee..41c9dd3 100644
--- a/ojluni/annotations/hiddenapi/sun/nio/ch/SelectorImpl.java
+++ b/ojluni/annotations/hiddenapi/sun/nio/ch/SelectorImpl.java
@@ -94,9 +94,9 @@
 
     private java.util.Set<java.nio.channels.SelectionKey> publicKeys;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private java.util.Set<java.nio.channels.SelectionKey> publicSelectedKeys;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     protected java.util.Set<java.nio.channels.SelectionKey> selectedKeys;
 }
diff --git a/ojluni/annotations/hiddenapi/sun/nio/cs/HistoricallyNamedCharset.java b/ojluni/annotations/hiddenapi/sun/nio/cs/HistoricallyNamedCharset.java
index ed066b4..b0c71f4 100644
--- a/ojluni/annotations/hiddenapi/sun/nio/cs/HistoricallyNamedCharset.java
+++ b/ojluni/annotations/hiddenapi/sun/nio/cs/HistoricallyNamedCharset.java
@@ -28,6 +28,6 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public interface HistoricallyNamedCharset {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String historicalName();
 }
diff --git a/ojluni/annotations/hiddenapi/sun/nio/cs/ThreadLocalCoders.java b/ojluni/annotations/hiddenapi/sun/nio/cs/ThreadLocalCoders.java
index ef03631..3357f41 100644
--- a/ojluni/annotations/hiddenapi/sun/nio/cs/ThreadLocalCoders.java
+++ b/ojluni/annotations/hiddenapi/sun/nio/cs/ThreadLocalCoders.java
@@ -25,8 +25,6 @@
 
 package sun.nio.cs;
 
-import java.nio.charset.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ThreadLocalCoders {
 
@@ -34,7 +32,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.nio.charset.CharsetDecoder decoderFor(java.lang.Object name) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/nio/fs/BasicFileAttributesHolder.java b/ojluni/annotations/hiddenapi/sun/nio/fs/BasicFileAttributesHolder.java
index 78cf143..3d6c0e8 100644
--- a/ojluni/annotations/hiddenapi/sun/nio/fs/BasicFileAttributesHolder.java
+++ b/ojluni/annotations/hiddenapi/sun/nio/fs/BasicFileAttributesHolder.java
@@ -28,7 +28,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public interface BasicFileAttributesHolder {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.nio.file.attribute.BasicFileAttributes get();
 
     public void invalidate();
diff --git a/ojluni/annotations/hiddenapi/sun/reflect/Reflection.java b/ojluni/annotations/hiddenapi/sun/reflect/Reflection.java
index ab0fb2a..120ecb1 100644
--- a/ojluni/annotations/hiddenapi/sun/reflect/Reflection.java
+++ b/ojluni/annotations/hiddenapi/sun/reflect/Reflection.java
@@ -38,7 +38,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static void ensureMemberAccess(
             java.lang.Class<?> currentClass,
             java.lang.Class<?> memberClass,
@@ -68,7 +68,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     static boolean isSubclassOf(java.lang.Class<?> queryClass, java.lang.Class<?> ofClass) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/reflect/misc/ReflectUtil.java b/ojluni/annotations/hiddenapi/sun/reflect/misc/ReflectUtil.java
index 3200def..014d613 100644
--- a/ojluni/annotations/hiddenapi/sun/reflect/misc/ReflectUtil.java
+++ b/ojluni/annotations/hiddenapi/sun/reflect/misc/ReflectUtil.java
@@ -53,22 +53,22 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static boolean isSubclassOf(java.lang.Class<?> queryClass, java.lang.Class<?> ofClass) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static void checkPackageAccess(java.lang.Class<?> clazz) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static void checkPackageAccess(java.lang.String name) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static boolean isPackageAccessible(java.lang.Class<?> clazz) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/action/GetBooleanAction.java b/ojluni/annotations/hiddenapi/sun/security/action/GetBooleanAction.java
index 36355d7..a9e37e4 100644
--- a/ojluni/annotations/hiddenapi/sun/security/action/GetBooleanAction.java
+++ b/ojluni/annotations/hiddenapi/sun/security/action/GetBooleanAction.java
@@ -28,7 +28,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class GetBooleanAction implements java.security.PrivilegedAction<java.lang.Boolean> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public GetBooleanAction(java.lang.String theProp) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/action/GetIntegerAction.java b/ojluni/annotations/hiddenapi/sun/security/action/GetIntegerAction.java
index a0bc736..223563c 100644
--- a/ojluni/annotations/hiddenapi/sun/security/action/GetIntegerAction.java
+++ b/ojluni/annotations/hiddenapi/sun/security/action/GetIntegerAction.java
@@ -32,7 +32,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public GetIntegerAction(java.lang.String theProp, int defaultVal) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/action/GetPropertyAction.java b/ojluni/annotations/hiddenapi/sun/security/action/GetPropertyAction.java
index b83e1cd..ee83f58 100644
--- a/ojluni/annotations/hiddenapi/sun/security/action/GetPropertyAction.java
+++ b/ojluni/annotations/hiddenapi/sun/security/action/GetPropertyAction.java
@@ -28,12 +28,12 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class GetPropertyAction implements java.security.PrivilegedAction<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public GetPropertyAction(java.lang.String theProp) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public GetPropertyAction(java.lang.String theProp, java.lang.String defaultVal) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/jca/GetInstance.java b/ojluni/annotations/hiddenapi/sun/security/jca/GetInstance.java
index e046dae..92756f9 100644
--- a/ojluni/annotations/hiddenapi/sun/security/jca/GetInstance.java
+++ b/ojluni/annotations/hiddenapi/sun/security/jca/GetInstance.java
@@ -75,7 +75,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.security.jca.GetInstance.Instance getInstance(
             java.lang.String type,
             java.lang.Class<?> clazz,
@@ -94,7 +94,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.security.jca.GetInstance.Instance getInstance(
             java.lang.String type,
             java.lang.Class<?> clazz,
@@ -114,7 +114,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.security.jca.GetInstance.Instance getInstance(
             java.lang.String type,
             java.lang.Class<?> clazz,
@@ -156,13 +156,13 @@
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage public final java.lang.Object impl;
+        @android.compat.annotation.UnsupportedAppUsage public final java.lang.Object impl;
 
         {
             impl = null;
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage public final java.security.Provider provider;
+        @android.compat.annotation.UnsupportedAppUsage public final java.security.Provider provider;
 
         {
             provider = null;
diff --git a/ojluni/annotations/hiddenapi/sun/security/jca/JCAUtil.java b/ojluni/annotations/hiddenapi/sun/security/jca/JCAUtil.java
index 26d767f..ca703f2 100644
--- a/ojluni/annotations/hiddenapi/sun/security/jca/JCAUtil.java
+++ b/ojluni/annotations/hiddenapi/sun/security/jca/JCAUtil.java
@@ -39,7 +39,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.security.SecureRandom getSecureRandom() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/jca/ProviderConfig.java b/ojluni/annotations/hiddenapi/sun/security/jca/ProviderConfig.java
index 60ed61e..f6abd8b 100644
--- a/ojluni/annotations/hiddenapi/sun/security/jca/ProviderConfig.java
+++ b/ojluni/annotations/hiddenapi/sun/security/jca/ProviderConfig.java
@@ -47,7 +47,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private boolean hasArgument() {
         throw new RuntimeException("Stub!");
     }
@@ -56,7 +56,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void disableLoad() {
         throw new RuntimeException("Stub!");
     }
@@ -94,7 +94,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private static final java.lang.Class[] CL_STRING;
+    @android.compat.annotation.UnsupportedAppUsage private static final java.lang.Class[] CL_STRING;
 
     static {
         CL_STRING = new java.lang.Class[0];
@@ -107,7 +107,7 @@
 
     private static final java.lang.String P11_SOL_NAME = "sun.security.pkcs11.SunPKCS11";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private final java.lang.String argument;
+    @android.compat.annotation.UnsupportedAppUsage private final java.lang.String argument;
 
     {
         argument = null;
diff --git a/ojluni/annotations/hiddenapi/sun/security/jca/ProviderList.java b/ojluni/annotations/hiddenapi/sun/security/jca/ProviderList.java
index 7cd3d4e..e823f317 100644
--- a/ojluni/annotations/hiddenapi/sun/security/jca/ProviderList.java
+++ b/ojluni/annotations/hiddenapi/sun/security/jca/ProviderList.java
@@ -106,7 +106,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.security.Provider.Service getService(java.lang.String type, java.lang.String name) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/jca/Providers.java b/ojluni/annotations/hiddenapi/sun/security/jca/Providers.java
index da37d94..4e116fc 100644
--- a/ojluni/annotations/hiddenapi/sun/security/jca/Providers.java
+++ b/ojluni/annotations/hiddenapi/sun/security/jca/Providers.java
@@ -38,17 +38,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.lang.Object startJarVerification() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static void stopJarVerification(java.lang.Object obj) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.security.jca.ProviderList getProviderList() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/pkcs/ContentInfo.java b/ojluni/annotations/hiddenapi/sun/security/pkcs/ContentInfo.java
index 98a0a85..4340ab5 100644
--- a/ojluni/annotations/hiddenapi/sun/security/pkcs/ContentInfo.java
+++ b/ojluni/annotations/hiddenapi/sun/security/pkcs/ContentInfo.java
@@ -31,13 +31,13 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ContentInfo {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public ContentInfo(
             sun.security.util.ObjectIdentifier contentType, sun.security.util.DerValue content) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public ContentInfo(byte[] bytes) {
         throw new RuntimeException("Stub!");
     }
@@ -60,12 +60,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getData() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encode(sun.security.util.DerOutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -78,7 +78,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.security.util.ObjectIdentifier DATA_OID;
 
     public static sun.security.util.ObjectIdentifier DIGESTED_DATA_OID;
diff --git a/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS7.java b/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS7.java
index 0292827..48a4c3c 100644
--- a/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS7.java
+++ b/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS7.java
@@ -44,12 +44,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS7(byte[] bytes) throws sun.security.pkcs.ParsingException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS7(
             sun.security.x509.AlgorithmId[] digestAlgorithmIds,
             sun.security.pkcs.ContentInfo contentInfo,
@@ -59,7 +59,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS7(
             sun.security.x509.AlgorithmId[] digestAlgorithmIds,
             sun.security.pkcs.ContentInfo contentInfo,
@@ -93,7 +93,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encodeSignedData(java.io.OutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -102,7 +102,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.pkcs.SignerInfo verify(sun.security.pkcs.SignerInfo info, byte[] bytes)
             throws java.security.NoSuchAlgorithmException, java.security.SignatureException {
         throw new RuntimeException("Stub!");
@@ -115,7 +115,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.pkcs.SignerInfo[] verify(byte[] bytes)
             throws java.security.NoSuchAlgorithmException, java.security.SignatureException {
         throw new RuntimeException("Stub!");
@@ -134,12 +134,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.pkcs.ContentInfo getContentInfo() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.security.cert.X509Certificate[] getCertificates() {
         throw new RuntimeException("Stub!");
     }
@@ -148,7 +148,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.pkcs.SignerInfo[] getSignerInfos() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS8Key.java b/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS8Key.java
index fa84ed9..e8bb5a1 100644
--- a/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS8Key.java
+++ b/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS8Key.java
@@ -32,7 +32,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class PKCS8Key implements java.security.PrivateKey {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS8Key() {
         throw new RuntimeException("Stub!");
     }
@@ -115,11 +115,11 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage protected sun.security.x509.AlgorithmId algid;
+    @android.compat.annotation.UnsupportedAppUsage protected sun.security.x509.AlgorithmId algid;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage protected byte[] encodedKey;
+    @android.compat.annotation.UnsupportedAppUsage protected byte[] encodedKey;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage protected byte[] key;
+    @android.compat.annotation.UnsupportedAppUsage protected byte[] key;
 
     private static final long serialVersionUID = -3836890099307167124L; // 0xcac0a0c88c95426cL
 
diff --git a/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS9Attribute.java b/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS9Attribute.java
index 40718c2..4413f4e 100644
--- a/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS9Attribute.java
+++ b/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS9Attribute.java
@@ -29,19 +29,19 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class PKCS9Attribute implements sun.security.util.DerEncoder {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS9Attribute(sun.security.util.ObjectIdentifier oid, java.lang.Object value)
             throws java.lang.IllegalArgumentException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS9Attribute(java.lang.String name, java.lang.Object value)
             throws java.lang.IllegalArgumentException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS9Attribute(sun.security.util.DerValue derVal) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -51,7 +51,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void derEncode(java.io.OutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -60,7 +60,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.Object getValue() {
         throw new RuntimeException("Stub!");
     }
@@ -69,7 +69,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.ObjectIdentifier getOID() {
         throw new RuntimeException("Stub!");
     }
@@ -116,7 +116,7 @@
 
     public static final java.lang.String CHALLENGE_PASSWORD_STR = "ChallengePassword";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier CONTENT_TYPE_OID;
 
     static {
@@ -133,7 +133,7 @@
 
     public static final java.lang.String COUNTERSIGNATURE_STR = "Countersignature";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier EMAIL_ADDRESS_OID;
 
     static {
@@ -167,7 +167,7 @@
 
     public static final java.lang.String ISSUER_SERIALNUMBER_STR = "IssuerAndSerialNumber";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier MESSAGE_DIGEST_OID;
 
     static {
@@ -220,7 +220,7 @@
 
     public static final java.lang.String SIGNING_CERTIFICATE_STR = "SigningCertificate";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier SIGNING_TIME_OID;
 
     static {
diff --git a/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS9Attributes.java b/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS9Attributes.java
index ac9faba..a5e9019 100644
--- a/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS9Attributes.java
+++ b/ojluni/annotations/hiddenapi/sun/security/pkcs/PKCS9Attributes.java
@@ -36,18 +36,18 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS9Attributes(sun.security.util.DerInputStream in) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS9Attributes(sun.security.util.DerInputStream in, boolean ignoreUnsupportedAttributes)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public PKCS9Attributes(sun.security.pkcs.PKCS9Attribute[] attribs)
             throws java.io.IOException, java.lang.IllegalArgumentException {
         throw new RuntimeException("Stub!");
@@ -57,7 +57,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encode(byte tag, java.io.OutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -66,7 +66,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getDerEncoding() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -75,7 +75,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.pkcs.PKCS9Attribute getAttribute(java.lang.String name) {
         throw new RuntimeException("Stub!");
     }
@@ -84,7 +84,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.Object getAttributeValue(sun.security.util.ObjectIdentifier oid)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
diff --git a/ojluni/annotations/hiddenapi/sun/security/pkcs/ParsingException.java b/ojluni/annotations/hiddenapi/sun/security/pkcs/ParsingException.java
index 7b10115..1f012cb 100644
--- a/ojluni/annotations/hiddenapi/sun/security/pkcs/ParsingException.java
+++ b/ojluni/annotations/hiddenapi/sun/security/pkcs/ParsingException.java
@@ -37,7 +37,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public ParsingException(java.lang.String s) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/pkcs/SignerInfo.java b/ojluni/annotations/hiddenapi/sun/security/pkcs/SignerInfo.java
index 03ebf6f..162b420 100644
--- a/ojluni/annotations/hiddenapi/sun/security/pkcs/SignerInfo.java
+++ b/ojluni/annotations/hiddenapi/sun/security/pkcs/SignerInfo.java
@@ -34,7 +34,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public SignerInfo(
             sun.security.x509.X500Name issuerName,
             java.math.BigInteger serial,
@@ -44,7 +44,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public SignerInfo(
             sun.security.x509.X500Name issuerName,
             java.math.BigInteger serial,
@@ -74,13 +74,13 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.security.cert.X509Certificate getCertificate(sun.security.pkcs.PKCS7 block)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.util.ArrayList<java.security.cert.X509Certificate> getCertificateChain(
             sun.security.pkcs.PKCS7 block) throws java.io.IOException {
         throw new RuntimeException("Stub!");
@@ -115,7 +115,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.AlgorithmId getDigestAlgorithmId() {
         throw new RuntimeException("Stub!");
     }
@@ -124,12 +124,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.AlgorithmId getDigestEncryptionAlgorithmId() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getEncryptedDigest() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/provider/X509Factory.java b/ojluni/annotations/hiddenapi/sun/security/provider/X509Factory.java
index 499dddc..5f23765 100644
--- a/ojluni/annotations/hiddenapi/sun/security/provider/X509Factory.java
+++ b/ojluni/annotations/hiddenapi/sun/security/provider/X509Factory.java
@@ -25,8 +25,6 @@
 
 package sun.security.provider;
 
-import java.security.cert.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class X509Factory {
 
@@ -34,25 +32,25 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static synchronized sun.security.x509.X509CertImpl intern(
             java.security.cert.X509Certificate c) throws java.security.cert.CertificateException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static synchronized sun.security.x509.X509CRLImpl intern(java.security.cert.X509CRL c)
             throws java.security.cert.CRLException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static synchronized <K, V> V getFromCache(
             sun.security.util.Cache<K, V> cache, byte[] encoding) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static synchronized <V> void addToCache(
             sun.security.util.Cache<java.lang.Object, V> cache, byte[] encoding, V value) {
         throw new RuntimeException("Stub!");
@@ -60,7 +58,7 @@
 
     private static final int ENC_MAX_LENGTH = 4194304; // 0x400000
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static final sun.security.util.Cache<java.lang.Object, sun.security.x509.X509CertImpl>
             certCache;
 
@@ -68,7 +66,7 @@
         certCache = null;
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static final sun.security.util.Cache<java.lang.Object, sun.security.x509.X509CRLImpl>
             crlCache;
 
diff --git a/ojluni/annotations/hiddenapi/sun/security/provider/certpath/X509CertPath.java b/ojluni/annotations/hiddenapi/sun/security/provider/certpath/X509CertPath.java
index f3d432a..71cc57f 100644
--- a/ojluni/annotations/hiddenapi/sun/security/provider/certpath/X509CertPath.java
+++ b/ojluni/annotations/hiddenapi/sun/security/provider/certpath/X509CertPath.java
@@ -25,25 +25,23 @@
 
 package sun.security.provider.certpath;
 
-import java.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class X509CertPath extends java.security.cert.CertPath {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CertPath(java.util.List<? extends java.security.cert.Certificate> certs)
             throws java.security.cert.CertificateException {
         super(null);
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CertPath(java.io.InputStream is) throws java.security.cert.CertificateException {
         super(null);
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CertPath(java.io.InputStream is, java.lang.String encoding)
             throws java.security.cert.CertificateException {
         super(null);
@@ -81,7 +79,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.util.Iterator<java.lang.String> getEncodingsStatic() {
         throw new RuntimeException("Stub!");
     }
@@ -100,7 +98,7 @@
 
     private static final java.lang.String PKIPATH_ENCODING = "PkiPath";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private java.util.List<java.security.cert.X509Certificate> certs;
 
     private static final java.util.Collection<java.lang.String> encodingList;
diff --git a/ojluni/annotations/hiddenapi/sun/security/provider/certpath/X509CertificatePair.java b/ojluni/annotations/hiddenapi/sun/security/provider/certpath/X509CertificatePair.java
index 3d5b410..fa9fb60 100644
--- a/ojluni/annotations/hiddenapi/sun/security/provider/certpath/X509CertificatePair.java
+++ b/ojluni/annotations/hiddenapi/sun/security/provider/certpath/X509CertificatePair.java
@@ -43,7 +43,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static synchronized void clearCache() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/timestamp/TimestampToken.java b/ojluni/annotations/hiddenapi/sun/security/timestamp/TimestampToken.java
index 241935e..1c2d115 100644
--- a/ojluni/annotations/hiddenapi/sun/security/timestamp/TimestampToken.java
+++ b/ojluni/annotations/hiddenapi/sun/security/timestamp/TimestampToken.java
@@ -28,27 +28,27 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class TimestampToken {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public TimestampToken(byte[] timestampTokenInfo) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.util.Date getDate() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.AlgorithmId getHashAlgorithm() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getHashedMessage() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.math.BigInteger getNonce() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/BitArray.java b/ojluni/annotations/hiddenapi/sun/security/util/BitArray.java
index 2eb98fe..a27ab65 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/BitArray.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/BitArray.java
@@ -32,7 +32,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public BitArray(int length, byte[] a) throws java.lang.IllegalArgumentException {
         throw new RuntimeException("Stub!");
     }
@@ -65,7 +65,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] toByteArray() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/Cache.java b/ojluni/annotations/hiddenapi/sun/security/util/Cache.java
index f5077e1..1520e12 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/Cache.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/Cache.java
@@ -31,20 +31,20 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public abstract class Cache<K, V> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     protected Cache() {
         throw new RuntimeException("Stub!");
     }
 
     public abstract int size();
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public abstract void clear();
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public abstract void put(K key, V value);
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public abstract V get(java.lang.Object key);
 
     public abstract void remove(java.lang.Object key);
@@ -63,7 +63,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static <K, V> sun.security.util.Cache<K, V> newHardMemoryCache(int size) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/Debug.java b/ojluni/annotations/hiddenapi/sun/security/util/Debug.java
index e511d0d..5421d20 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/Debug.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/Debug.java
@@ -33,7 +33,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.security.util.Debug getInstance(java.lang.String option) {
         throw new RuntimeException("Stub!");
     }
@@ -47,17 +47,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void println(java.lang.String message) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void println() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.lang.String toHexString(java.math.BigInteger b) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/DerIndefLenConverter.java b/ojluni/annotations/hiddenapi/sun/security/util/DerIndefLenConverter.java
index af6e282..6ac25a9 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/DerIndefLenConverter.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/DerIndefLenConverter.java
@@ -29,7 +29,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 class DerIndefLenConverter {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     DerIndefLenConverter() {
         throw new RuntimeException("Stub!");
     }
@@ -42,27 +42,27 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     static boolean isIndefinite(int lengthByte) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void parseTag() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void writeTag() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private int parseLength() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void writeLengthAndValue() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -79,7 +79,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void parseValue(int curLen) {
         throw new RuntimeException("Stub!");
     }
@@ -88,7 +88,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     byte[] convert(byte[] indefData) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -105,21 +105,21 @@
 
     private static final int TAG_MASK = 31; // 0x1f
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private byte[] data;
+    @android.compat.annotation.UnsupportedAppUsage private byte[] data;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private int dataPos;
+    @android.compat.annotation.UnsupportedAppUsage private int dataPos;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private int dataSize;
+    @android.compat.annotation.UnsupportedAppUsage private int dataSize;
 
     private int index;
 
     private java.util.ArrayList<java.lang.Object> ndefsList;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private byte[] newData;
+    @android.compat.annotation.UnsupportedAppUsage private byte[] newData;
 
     private int newDataPos;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private int numOfTotalLenBytes = 0; // 0x0
+    @android.compat.annotation.UnsupportedAppUsage private int numOfTotalLenBytes = 0; // 0x0
 
     private int unresolved = 0; // 0x0
 }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/DerInputStream.java b/ojluni/annotations/hiddenapi/sun/security/util/DerInputStream.java
index a8348e3..fefcd08 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/DerInputStream.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/DerInputStream.java
@@ -29,7 +29,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class DerInputStream {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public DerInputStream(byte[] data) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -52,7 +52,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.DerInputStream subStream(int len, boolean do_skip)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
@@ -62,12 +62,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public int getInteger() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.math.BigInteger getBigInteger() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -80,7 +80,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getBitString() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -89,7 +89,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getOctetString() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -102,7 +102,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.ObjectIdentifier getOID() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -112,17 +112,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.DerValue[] getSequence(int startLen) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.DerValue[] getSet(int startLen) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.DerValue[] getSet(int startLen, boolean implicit)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
@@ -143,12 +143,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.DerValue getDerValue() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String getUTF8String() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -179,7 +179,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.util.Date getUTCTime() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -192,7 +192,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public int peekByte() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -209,22 +209,22 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void mark(int value) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void reset() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public int available() {
         throw new RuntimeException("Stub!");
     }
 
     sun.security.util.DerInputBuffer buffer;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage public byte tag;
+    @android.compat.annotation.UnsupportedAppUsage public byte tag;
 }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/DerOutputStream.java b/ojluni/annotations/hiddenapi/sun/security/util/DerOutputStream.java
index 77e5e05..772018d 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/DerOutputStream.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/DerOutputStream.java
@@ -30,22 +30,22 @@
 public class DerOutputStream extends java.io.ByteArrayOutputStream
         implements sun.security.util.DerEncoder {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public DerOutputStream(int size) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public DerOutputStream() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void write(byte tag, byte[] buf) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void write(byte tag, sun.security.util.DerOutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -55,12 +55,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putDerValue(sun.security.util.DerValue val) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putBoolean(boolean val) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -69,7 +69,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putInteger(java.math.BigInteger i) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -78,7 +78,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putInteger(int i) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -87,7 +87,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putBitString(byte[] bits) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -101,22 +101,22 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putOctetString(byte[] octets) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putNull() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putOID(sun.security.util.ObjectIdentifier oid) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putSequence(sun.security.util.DerValue[] seq) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -125,7 +125,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putOrderedSetOf(byte tag, sun.security.util.DerEncoder[] set)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
@@ -142,12 +142,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putUTF8String(java.lang.String s) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putPrintableString(java.lang.String s) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -156,7 +156,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putIA5String(java.lang.String s) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -174,7 +174,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void putUTCTime(java.util.Date d) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/DerValue.java b/ojluni/annotations/hiddenapi/sun/security/util/DerValue.java
index d034f44..42825d3 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/DerValue.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/DerValue.java
@@ -30,7 +30,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class DerValue {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public DerValue(java.lang.String value) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -39,7 +39,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public DerValue(byte tag, byte[] data) {
         throw new RuntimeException("Stub!");
     }
@@ -49,17 +49,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public DerValue(byte[] buf) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public DerValue(byte[] buf, int offset, int len) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public DerValue(java.io.InputStream in) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -72,12 +72,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public boolean isContextSpecific() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public boolean isContextSpecific(byte cntxtTag) {
         throw new RuntimeException("Stub!");
     }
@@ -86,7 +86,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public boolean isConstructed() {
         throw new RuntimeException("Stub!");
     }
@@ -105,12 +105,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encode(sun.security.util.DerOutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public final sun.security.util.DerInputStream getData() {
         throw new RuntimeException("Stub!");
     }
@@ -123,7 +123,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.ObjectIdentifier getOID() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -132,7 +132,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getOctetString() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -141,12 +141,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.math.BigInteger getBigInteger() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.math.BigInteger getPositiveBigInteger() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -155,17 +155,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getBitString() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.BitArray getUnalignedBitString() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String getAsString() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -179,7 +179,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getDataBytes() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -236,12 +236,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] toByteArray() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.DerInputStream toDerInputStream() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -250,17 +250,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static boolean isPrintableStringChar(char ch) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static byte createTag(byte tagClass, boolean form, byte val) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void resetTag(byte tag) {
         throw new RuntimeException("Stub!");
     }
@@ -277,9 +277,9 @@
 
     public static final byte TAG_UNIVERSAL = 0; // 0x0
 
-    @dalvik.annotation.compat.UnsupportedAppUsage protected sun.security.util.DerInputBuffer buffer;
+    @android.compat.annotation.UnsupportedAppUsage protected sun.security.util.DerInputBuffer buffer;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public final sun.security.util.DerInputStream data;
 
     {
@@ -290,7 +290,7 @@
 
     private byte[] originalEncodedForm;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage public byte tag;
+    @android.compat.annotation.UnsupportedAppUsage public byte tag;
 
     public static final byte tag_BMPString = 30; // 0x1e
 
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/ManifestDigester.java b/ojluni/annotations/hiddenapi/sun/security/util/ManifestDigester.java
index ff473fb..b8d89f8 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/ManifestDigester.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/ManifestDigester.java
@@ -30,7 +30,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class ManifestDigester {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public ManifestDigester(byte[] bytes) {
         throw new RuntimeException("Stub!");
     }
@@ -43,12 +43,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.ManifestDigester.Entry get(java.lang.String name, boolean oldStyle) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] manifestDigest(java.security.MessageDigest md) {
         throw new RuntimeException("Stub!");
     }
@@ -66,7 +66,7 @@
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public byte[] digest(java.security.MessageDigest md) {
             throw new RuntimeException("Stub!");
         }
@@ -76,7 +76,7 @@
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public byte[] digestWorkaround(java.security.MessageDigest md) {
             throw new RuntimeException("Stub!");
         }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/MemoryCache.java b/ojluni/annotations/hiddenapi/sun/security/util/MemoryCache.java
index 0bea0a2..5a7d646 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/MemoryCache.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/MemoryCache.java
@@ -16,7 +16,7 @@
 
 package sun.security.util;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 class MemoryCache<K, V> extends sun.security.util.Cache<K, V> {
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/ObjectIdentifier.java b/ojluni/annotations/hiddenapi/sun/security/util/ObjectIdentifier.java
index 1c17bed..7b536f4 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/ObjectIdentifier.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/ObjectIdentifier.java
@@ -30,12 +30,12 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class ObjectIdentifier implements java.io.Serializable {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public ObjectIdentifier(java.lang.String oid) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public ObjectIdentifier(int[] values) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -61,7 +61,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.security.util.ObjectIdentifier newInternal(int[] values) {
         throw new RuntimeException("Stub!");
     }
@@ -71,7 +71,7 @@
     }
 
     @Deprecated
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public boolean equals(sun.security.util.ObjectIdentifier other) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/PropertyExpander.java b/ojluni/annotations/hiddenapi/sun/security/util/PropertyExpander.java
index f763de7..9a86630 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/PropertyExpander.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/PropertyExpander.java
@@ -33,7 +33,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.lang.String expand(java.lang.String value)
             throws sun.security.util.PropertyExpander.ExpandException {
         throw new RuntimeException("Stub!");
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/ResourcesMgr.java b/ojluni/annotations/hiddenapi/sun/security/util/ResourcesMgr.java
index eef01dc..0a66cae 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/ResourcesMgr.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/ResourcesMgr.java
@@ -32,7 +32,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.lang.String getString(java.lang.String s) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/SecurityConstants.java b/ojluni/annotations/hiddenapi/sun/security/util/SecurityConstants.java
index 33d67c6..4a89da6 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/SecurityConstants.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/SecurityConstants.java
@@ -51,7 +51,7 @@
         CREATE_ACC_PERMISSION = null;
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final java.lang.RuntimePermission CREATE_CLASSLOADER_PERMISSION;
 
     static {
@@ -68,7 +68,7 @@
 
     public static final java.lang.String FILE_WRITE_ACTION = "write";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final java.lang.RuntimePermission GET_CLASSLOADER_PERMISSION;
 
     static {
@@ -123,14 +123,14 @@
         LOCAL_LISTEN_PERMISSION = null;
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final java.lang.RuntimePermission MODIFY_THREADGROUP_PERMISSION;
 
     static {
         MODIFY_THREADGROUP_PERMISSION = null;
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final java.lang.RuntimePermission MODIFY_THREAD_PERMISSION;
 
     static {
diff --git a/ojluni/annotations/hiddenapi/sun/security/util/SignatureFileVerifier.java b/ojluni/annotations/hiddenapi/sun/security/util/SignatureFileVerifier.java
index bce34ad..0d9c770 100644
--- a/ojluni/annotations/hiddenapi/sun/security/util/SignatureFileVerifier.java
+++ b/ojluni/annotations/hiddenapi/sun/security/util/SignatureFileVerifier.java
@@ -50,7 +50,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static boolean isBlockOrSF(java.lang.String s) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/AVA.java b/ojluni/annotations/hiddenapi/sun/security/x509/AVA.java
index e2e18ca..d4018bf 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/AVA.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/AVA.java
@@ -26,7 +26,7 @@
 
 package sun.security.x509;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class AVA implements sun.security.util.DerEncoder {
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/AVAComparator.java b/ojluni/annotations/hiddenapi/sun/security/x509/AVAComparator.java
index 21494c3..3643d60 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/AVAComparator.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/AVAComparator.java
@@ -16,7 +16,7 @@
 
 package sun.security.x509;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 class AVAComparator implements java.util.Comparator<sun.security.x509.AVA> {
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/AVAKeyword.java b/ojluni/annotations/hiddenapi/sun/security/x509/AVAKeyword.java
index 78d379f..adadd59 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/AVAKeyword.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/AVAKeyword.java
@@ -17,7 +17,7 @@
 package sun.security.x509;
 
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 class AVAKeyword {
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/AccessDescription.java b/ojluni/annotations/hiddenapi/sun/security/x509/AccessDescription.java
index 5f3d77f..d6f5e1d 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/AccessDescription.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/AccessDescription.java
@@ -36,17 +36,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public AccessDescription(sun.security.util.DerValue derValue) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.ObjectIdentifier getAccessMethod() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.GeneralName getAccessLocation() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/AlgorithmId.java b/ojluni/annotations/hiddenapi/sun/security/x509/AlgorithmId.java
index 3f9214b..7948de8 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/AlgorithmId.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/AlgorithmId.java
@@ -26,7 +26,7 @@
 
 package sun.security.x509;
 
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class AlgorithmId implements java.io.Serializable, sun.security.util.DerEncoder {
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/AttributeNameEnumeration.java b/ojluni/annotations/hiddenapi/sun/security/x509/AttributeNameEnumeration.java
index c3728d7..6bda58e 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/AttributeNameEnumeration.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/AttributeNameEnumeration.java
@@ -29,7 +29,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class AttributeNameEnumeration extends java.util.Vector<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public AttributeNameEnumeration() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CRLDistributionPointsExtension.java b/ojluni/annotations/hiddenapi/sun/security/x509/CRLDistributionPointsExtension.java
index 84063ed..2e8439f 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CRLDistributionPointsExtension.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CRLDistributionPointsExtension.java
@@ -100,7 +100,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void encodeThis() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CRLNumberExtension.java b/ojluni/annotations/hiddenapi/sun/security/x509/CRLNumberExtension.java
index 00d0ee0..40eb1b8 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CRLNumberExtension.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CRLNumberExtension.java
@@ -49,7 +49,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CRLNumberExtension(java.lang.Boolean critical, java.lang.Object value)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
@@ -65,7 +65,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void encodeThis() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -74,7 +74,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.math.BigInteger get(java.lang.String name) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateAlgorithmId.java b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateAlgorithmId.java
index 5a3bc38..4a8f963 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateAlgorithmId.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateAlgorithmId.java
@@ -30,7 +30,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CertificateAlgorithmId implements sun.security.x509.CertAttrSet<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateAlgorithmId(sun.security.x509.AlgorithmId algId) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateExtensions.java b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateExtensions.java
index cad6f74..da41fbd 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateExtensions.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateExtensions.java
@@ -32,12 +32,12 @@
 public class CertificateExtensions
         implements sun.security.x509.CertAttrSet<sun.security.x509.Extension> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateExtensions() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateExtensions(sun.security.util.DerInputStream in) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -55,18 +55,18 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encode(java.io.OutputStream out, boolean isCertReq)
             throws java.security.cert.CertificateException, java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void set(java.lang.String name, java.lang.Object obj) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.Extension get(java.lang.String name) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateIssuerName.java b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateIssuerName.java
index 22380db..c6736ff 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateIssuerName.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateIssuerName.java
@@ -30,7 +30,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CertificateIssuerName implements sun.security.x509.CertAttrSet<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateIssuerName(sun.security.x509.X500Name name) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateSerialNumber.java b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateSerialNumber.java
index 131b445..1a0cb81 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateSerialNumber.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateSerialNumber.java
@@ -30,12 +30,12 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CertificateSerialNumber implements sun.security.x509.CertAttrSet<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateSerialNumber(java.math.BigInteger num) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateSerialNumber(int num) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateSubjectName.java b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateSubjectName.java
index f5ff910..87842ca 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateSubjectName.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateSubjectName.java
@@ -30,7 +30,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CertificateSubjectName implements sun.security.x509.CertAttrSet<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateSubjectName(sun.security.x509.X500Name name) {
         throw new RuntimeException("Stub!");
     }
@@ -55,7 +55,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.Object get(java.lang.String name) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateValidity.java b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateValidity.java
index bb5d599..db96a7a 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateValidity.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateValidity.java
@@ -35,7 +35,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateValidity(java.util.Date notBefore, java.util.Date notAfter) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateVersion.java b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateVersion.java
index 85ad759..3b3c180 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateVersion.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateVersion.java
@@ -34,7 +34,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateVersion(int version) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateX509Key.java b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateX509Key.java
index 6f45057..ff5cc1d 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/CertificateX509Key.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/CertificateX509Key.java
@@ -30,7 +30,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class CertificateX509Key implements sun.security.x509.CertAttrSet<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public CertificateX509Key(java.security.PublicKey key) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/Extension.java b/ojluni/annotations/hiddenapi/sun/security/x509/Extension.java
index f4acc6c..60cd779 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/Extension.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/Extension.java
@@ -44,7 +44,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public Extension(sun.security.x509.Extension ext) {
         throw new RuntimeException("Stub!");
     }
@@ -61,7 +61,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encode(sun.security.util.DerOutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -70,7 +70,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.util.ObjectIdentifier getExtensionId() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/GeneralName.java b/ojluni/annotations/hiddenapi/sun/security/x509/GeneralName.java
index c7eb02e..9fa401c 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/GeneralName.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/GeneralName.java
@@ -30,7 +30,7 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class GeneralName {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public GeneralName(sun.security.x509.GeneralNameInterface name) {
         throw new RuntimeException("Stub!");
     }
@@ -44,12 +44,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public int getType() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.GeneralNameInterface getName() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/GeneralNames.java b/ojluni/annotations/hiddenapi/sun/security/x509/GeneralNames.java
index fdac69f..df5f5ee 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/GeneralNames.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/GeneralNames.java
@@ -31,17 +31,17 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class GeneralNames {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public GeneralNames(sun.security.util.DerValue derVal) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public GeneralNames() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.GeneralNames add(sun.security.x509.GeneralName name) {
         throw new RuntimeException("Stub!");
     }
@@ -50,7 +50,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public boolean isEmpty() {
         throw new RuntimeException("Stub!");
     }
@@ -67,7 +67,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encode(sun.security.util.DerOutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/KeyIdentifier.java b/ojluni/annotations/hiddenapi/sun/security/x509/KeyIdentifier.java
index 8faa83a..427b133 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/KeyIdentifier.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/KeyIdentifier.java
@@ -38,12 +38,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public KeyIdentifier(java.security.PublicKey pubKey) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getIdentifier() {
         throw new RuntimeException("Stub!");
     }
@@ -64,5 +64,5 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private byte[] octetString;
+    @android.compat.annotation.UnsupportedAppUsage private byte[] octetString;
 }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/KeyUsageExtension.java b/ojluni/annotations/hiddenapi/sun/security/x509/KeyUsageExtension.java
index e9addc9..cd2ff3e 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/KeyUsageExtension.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/KeyUsageExtension.java
@@ -35,7 +35,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public KeyUsageExtension(boolean[] bitString) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -69,7 +69,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.Boolean get(java.lang.String name) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/NetscapeCertTypeExtension.java b/ojluni/annotations/hiddenapi/sun/security/x509/NetscapeCertTypeExtension.java
index 88e4f11..2db2b55 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/NetscapeCertTypeExtension.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/NetscapeCertTypeExtension.java
@@ -32,7 +32,7 @@
 public class NetscapeCertTypeExtension extends sun.security.x509.Extension
         implements sun.security.x509.CertAttrSet<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public NetscapeCertTypeExtension(byte[] bitString) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -70,7 +70,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.Boolean get(java.lang.String name) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/OIDMap.java b/ojluni/annotations/hiddenapi/sun/security/x509/OIDMap.java
index 8186c23..12be25a 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/OIDMap.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/OIDMap.java
@@ -60,7 +60,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.lang.Class<?> getClass(sun.security.util.ObjectIdentifier oid)
             throws java.security.cert.CertificateException {
         throw new RuntimeException("Stub!");
@@ -136,14 +136,14 @@
     private static final java.lang.String SUB_KEY_IDENTIFIER =
             "x509.info.extensions.SubjectKeyIdentifier";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static final java.util.Map<java.lang.String, sun.security.x509.OIDMap.OIDInfo> nameMap;
 
     static {
         nameMap = null;
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private static final java.util.Map<
                     sun.security.util.ObjectIdentifier, sun.security.x509.OIDMap.OIDInfo>
             oidMap;
@@ -166,7 +166,7 @@
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage private volatile java.lang.Class<?> clazz;
+        @android.compat.annotation.UnsupportedAppUsage private volatile java.lang.Class<?> clazz;
 
         final java.lang.String name;
 
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/PKIXExtensions.java b/ojluni/annotations/hiddenapi/sun/security/x509/PKIXExtensions.java
index de3027a..105172c 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/PKIXExtensions.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/PKIXExtensions.java
@@ -95,7 +95,7 @@
         CRLNumber_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier CertificateIssuer_Id;
 
     static {
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/SerialNumber.java b/ojluni/annotations/hiddenapi/sun/security/x509/SerialNumber.java
index 1c14ef3..f6b1663 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/SerialNumber.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/SerialNumber.java
@@ -42,7 +42,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public SerialNumber(sun.security.util.DerValue val) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/SubjectAlternativeNameExtension.java b/ojluni/annotations/hiddenapi/sun/security/x509/SubjectAlternativeNameExtension.java
index 44aa6ab..9b1ed0b 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/SubjectAlternativeNameExtension.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/SubjectAlternativeNameExtension.java
@@ -67,7 +67,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.GeneralNames get(java.lang.String name) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/SubjectKeyIdentifierExtension.java b/ojluni/annotations/hiddenapi/sun/security/x509/SubjectKeyIdentifierExtension.java
index 2a85bd5..a9c323d 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/SubjectKeyIdentifierExtension.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/SubjectKeyIdentifierExtension.java
@@ -25,13 +25,11 @@
 
 package sun.security.x509;
 
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class SubjectKeyIdentifierExtension extends sun.security.x509.Extension
         implements sun.security.x509.CertAttrSet<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public SubjectKeyIdentifierExtension(byte[] octetString) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/URIName.java b/ojluni/annotations/hiddenapi/sun/security/x509/URIName.java
index 5030158..5b8ee8f 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/URIName.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/URIName.java
@@ -25,8 +25,6 @@
 
 package sun.security.x509;
 
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class URIName implements sun.security.x509.GeneralNameInterface {
 
@@ -67,12 +65,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String getName() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String getScheme() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/UniqueIdentity.java b/ojluni/annotations/hiddenapi/sun/security/x509/UniqueIdentity.java
index b43e762..c5b0995 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/UniqueIdentity.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/UniqueIdentity.java
@@ -25,8 +25,6 @@
 
 package sun.security.x509;
 
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class UniqueIdentity {
 
@@ -38,12 +36,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public UniqueIdentity(sun.security.util.DerInputStream in) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public UniqueIdentity(sun.security.util.DerValue derVal) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -52,7 +50,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encode(sun.security.util.DerOutputStream out, byte tag) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/X500Name.java b/ojluni/annotations/hiddenapi/sun/security/x509/X500Name.java
index 4c697ab..fd8e9b6 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/X500Name.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/X500Name.java
@@ -26,14 +26,10 @@
 
 package sun.security.x509;
 
-import java.lang.reflect.*;
-import java.util.*;
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class X500Name implements sun.security.x509.GeneralNameInterface, java.security.Principal {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X500Name(java.lang.String dname) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -44,12 +40,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X500Name(java.lang.String dname, java.lang.String format) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X500Name(
             java.lang.String commonName,
             java.lang.String organizationUnit,
@@ -59,7 +55,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X500Name(
             java.lang.String commonName,
             java.lang.String organizationUnit,
@@ -75,17 +71,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X500Name(sun.security.util.DerValue value) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X500Name(sun.security.util.DerInputStream in) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X500Name(byte[] name) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -98,7 +94,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.util.List<sun.security.x509.AVA> allAvas() {
         throw new RuntimeException("Stub!");
     }
@@ -107,7 +103,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public boolean isEmpty() {
         throw new RuntimeException("Stub!");
     }
@@ -141,7 +137,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String getCommonName() throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -235,7 +231,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void encode(sun.security.util.DerOutputStream out) throws java.io.IOException {
         throw new RuntimeException("Stub!");
     }
@@ -300,12 +296,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public javax.security.auth.x500.X500Principal asX500Principal() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.security.x509.X500Name asX500Name(javax.security.auth.x500.X500Principal p) {
         throw new RuntimeException("Stub!");
     }
@@ -316,7 +312,7 @@
         DNQUALIFIER_DATA = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier DNQUALIFIER_OID;
 
     static {
@@ -329,7 +325,7 @@
         DOMAIN_COMPONENT_DATA = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier DOMAIN_COMPONENT_OID;
 
     static {
@@ -342,7 +338,7 @@
         GENERATIONQUALIFIER_DATA = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier GENERATIONQUALIFIER_OID;
 
     static {
@@ -355,7 +351,7 @@
         GIVENNAME_DATA = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier GIVENNAME_OID;
 
     static {
@@ -368,7 +364,7 @@
         INITIALS_DATA = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier INITIALS_OID;
 
     static {
@@ -381,7 +377,7 @@
         SERIALNUMBER_DATA = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier SERIALNUMBER_OID;
 
     static {
@@ -394,7 +390,7 @@
         SURNAME_DATA = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier SURNAME_OID;
 
     static {
@@ -411,7 +407,7 @@
         commonName_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier commonName_oid;
 
     static {
@@ -424,7 +420,7 @@
         countryName_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier countryName_oid;
 
     static {
@@ -449,7 +445,7 @@
         ipAddress_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier ipAddress_oid;
 
     static {
@@ -462,7 +458,7 @@
         localityName_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier localityName_oid;
 
     static {
@@ -477,7 +473,7 @@
         orgName_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier orgName_oid;
 
     static {
@@ -490,7 +486,7 @@
         orgUnitName_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier orgUnitName_oid;
 
     static {
@@ -522,7 +518,7 @@
         stateName_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier stateName_oid;
 
     static {
@@ -535,7 +531,7 @@
         streetAddress_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier streetAddress_oid;
 
     static {
@@ -548,7 +544,7 @@
         title_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier title_oid;
 
     static {
@@ -561,7 +557,7 @@
         userid_data = new int[0];
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final sun.security.util.ObjectIdentifier userid_oid;
 
     static {
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/X509CRLEntryImpl.java b/ojluni/annotations/hiddenapi/sun/security/x509/X509CRLEntryImpl.java
index 066a4ad..5684afa 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/X509CRLEntryImpl.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/X509CRLEntryImpl.java
@@ -25,9 +25,6 @@
 
 package sun.security.x509;
 
-import java.util.*;
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class X509CRLEntryImpl extends java.security.cert.X509CRLEntry
         implements java.lang.Comparable<sun.security.x509.X509CRLEntryImpl> {
@@ -120,7 +117,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.security.x509.Extension getExtension(sun.security.util.ObjectIdentifier oid) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/X509CRLImpl.java b/ojluni/annotations/hiddenapi/sun/security/x509/X509CRLImpl.java
index 7f353de..64cf8db 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/X509CRLImpl.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/X509CRLImpl.java
@@ -25,9 +25,6 @@
 
 package sun.security.x509;
 
-import java.util.*;
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class X509CRLImpl extends java.security.cert.X509CRL
         implements sun.security.util.DerEncoder {
@@ -36,17 +33,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CRLImpl(byte[] crlData) throws java.security.cert.CRLException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CRLImpl(sun.security.util.DerValue val) throws java.security.cert.CRLException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CRLImpl(java.io.InputStream inStrm) throws java.security.cert.CRLException {
         throw new RuntimeException("Stub!");
     }
@@ -75,7 +72,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getEncodedInternal() throws java.security.cert.CRLException {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/X509CertImpl.java b/ojluni/annotations/hiddenapi/sun/security/x509/X509CertImpl.java
index 9333689..5188e10 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/X509CertImpl.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/X509CertImpl.java
@@ -25,11 +25,6 @@
 
 package sun.security.x509;
 
-import java.security.*;
-import java.security.cert.*;
-import java.util.*;
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class X509CertImpl extends java.security.cert.X509Certificate
         implements sun.security.util.DerEncoder {
@@ -38,17 +33,17 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CertImpl(byte[] certData) throws java.security.cert.CertificateException {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CertImpl(sun.security.x509.X509CertInfo certInfo) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CertImpl(sun.security.util.DerValue derVal)
             throws java.security.cert.CertificateException {
         throw new RuntimeException("Stub!");
@@ -72,7 +67,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public byte[] getEncodedInternal() throws java.security.cert.CertificateEncodingException {
         throw new RuntimeException("Stub!");
     }
@@ -106,7 +101,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void sign(java.security.PrivateKey key, java.lang.String algorithm)
             throws java.security.cert.CertificateException, java.security.InvalidKeyException,
                     java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException,
@@ -134,7 +129,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.Object get(java.lang.String name)
             throws java.security.cert.CertificateParsingException {
         throw new RuntimeException("Stub!");
@@ -366,7 +361,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void parse(sun.security.util.DerValue val)
             throws java.security.cert.CertificateException, java.io.IOException {
         throw new RuntimeException("Stub!");
@@ -460,7 +455,7 @@
 
     public static final java.lang.String VERSION = "x509.info.version.number";
 
-    @dalvik.annotation.compat.UnsupportedAppUsage protected sun.security.x509.AlgorithmId algId;
+    @android.compat.annotation.UnsupportedAppUsage protected sun.security.x509.AlgorithmId algId;
 
     private java.util.Set<sun.security.x509.AccessDescription> authInfoAccess;
 
@@ -472,13 +467,13 @@
 
     private java.util.Collection<java.util.List<?>> issuerAlternativeNames;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private boolean readOnly = false;
+    @android.compat.annotation.UnsupportedAppUsage private boolean readOnly = false;
 
     private static final long serialVersionUID = -3457612960190864406L; // 0xd0041754f90963eaL
 
-    @dalvik.annotation.compat.UnsupportedAppUsage protected byte[] signature;
+    @android.compat.annotation.UnsupportedAppUsage protected byte[] signature;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage private byte[] signedCert;
+    @android.compat.annotation.UnsupportedAppUsage private byte[] signedCert;
 
     private java.util.Collection<java.util.List<?>> subjectAlternativeNames;
 
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/X509CertInfo.java b/ojluni/annotations/hiddenapi/sun/security/x509/X509CertInfo.java
index 21b4d61..2309a50 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/X509CertInfo.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/X509CertInfo.java
@@ -25,19 +25,15 @@
 
 package sun.security.x509;
 
-import java.security.cert.*;
-import java.util.*;
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class X509CertInfo implements sun.security.x509.CertAttrSet<java.lang.String> {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CertInfo() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509CertInfo(byte[] cert) throws java.security.cert.CertificateParsingException {
         throw new RuntimeException("Stub!");
     }
@@ -80,7 +76,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public void set(java.lang.String name, java.lang.Object val)
             throws java.security.cert.CertificateException, java.io.IOException {
         throw new RuntimeException("Stub!");
@@ -91,7 +87,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.Object get(java.lang.String name)
             throws java.security.cert.CertificateException, java.io.IOException {
         throw new RuntimeException("Stub!");
diff --git a/ojluni/annotations/hiddenapi/sun/security/x509/X509Key.java b/ojluni/annotations/hiddenapi/sun/security/x509/X509Key.java
index 2a830d7..8c4924f 100644
--- a/ojluni/annotations/hiddenapi/sun/security/x509/X509Key.java
+++ b/ojluni/annotations/hiddenapi/sun/security/x509/X509Key.java
@@ -25,13 +25,10 @@
 
 package sun.security.x509;
 
-import java.io.*;
-import sun.security.util.*;
-
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public class X509Key implements java.security.PublicKey {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public X509Key() {
         throw new RuntimeException("Stub!");
     }
@@ -49,7 +46,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static java.security.PublicKey parse(sun.security.util.DerValue in)
             throws java.io.IOException {
         throw new RuntimeException("Stub!");
@@ -129,15 +126,15 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage protected sun.security.x509.AlgorithmId algid;
+    @android.compat.annotation.UnsupportedAppUsage protected sun.security.x509.AlgorithmId algid;
 
     private sun.security.util.BitArray bitStringKey;
 
-    @dalvik.annotation.compat.UnsupportedAppUsage protected byte[] encodedKey;
+    @android.compat.annotation.UnsupportedAppUsage protected byte[] encodedKey;
 
-    @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage protected byte[] key;
+    @Deprecated @android.compat.annotation.UnsupportedAppUsage protected byte[] key;
 
     private static final long serialVersionUID = -5359250853002055002L; // 0xb5a01dbe649a72a6L
 
-    @Deprecated @dalvik.annotation.compat.UnsupportedAppUsage private int unusedBits = 0; // 0x0
+    @Deprecated @android.compat.annotation.UnsupportedAppUsage private int unusedBits = 0; // 0x0
 }
diff --git a/ojluni/annotations/hiddenapi/sun/util/calendar/AbstractCalendar.java b/ojluni/annotations/hiddenapi/sun/util/calendar/AbstractCalendar.java
index dd8fd2b..3e1be5e 100644
--- a/ojluni/annotations/hiddenapi/sun/util/calendar/AbstractCalendar.java
+++ b/ojluni/annotations/hiddenapi/sun/util/calendar/AbstractCalendar.java
@@ -37,7 +37,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.Era[] getEras() {
         throw new RuntimeException("Stub!");
     }
@@ -75,7 +75,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public long getTimeOfDayValue(sun.util.calendar.CalendarDate date) {
         throw new RuntimeException("Stub!");
     }
@@ -104,7 +104,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static long getDayOfWeekDateOnOrBefore(long fixedDate, int dayOfWeek) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/util/calendar/BaseCalendar.java b/ojluni/annotations/hiddenapi/sun/util/calendar/BaseCalendar.java
index 8c8f122..660ba87 100644
--- a/ojluni/annotations/hiddenapi/sun/util/calendar/BaseCalendar.java
+++ b/ojluni/annotations/hiddenapi/sun/util/calendar/BaseCalendar.java
@@ -185,10 +185,10 @@
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public abstract int getNormalizedYear();
 
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public abstract void setNormalizedYear(int normalizedYear);
 
         protected final boolean hit(int year) {
diff --git a/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarDate.java b/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarDate.java
index f63c574..165920c 100644
--- a/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarDate.java
+++ b/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarDate.java
@@ -45,7 +45,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public int getYear() {
         throw new RuntimeException("Stub!");
     }
@@ -66,7 +66,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public int getMonth() {
         throw new RuntimeException("Stub!");
     }
@@ -79,12 +79,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public int getDayOfMonth() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.CalendarDate setDayOfMonth(int date) {
         throw new RuntimeException("Stub!");
     }
@@ -101,7 +101,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.CalendarDate setHours(int hours) {
         throw new RuntimeException("Stub!");
     }
@@ -114,7 +114,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.CalendarDate setMinutes(int minutes) {
         throw new RuntimeException("Stub!");
     }
@@ -127,7 +127,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.CalendarDate setSeconds(int seconds) {
         throw new RuntimeException("Stub!");
     }
@@ -140,7 +140,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.CalendarDate setMillis(int millis) {
         throw new RuntimeException("Stub!");
     }
@@ -149,12 +149,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public long getTimeOfDay() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.CalendarDate setDate(int year, int month, int dayOfMonth) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarSystem.java b/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarSystem.java
index bddd682..c847641 100644
--- a/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarSystem.java
+++ b/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarSystem.java
@@ -34,12 +34,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.util.calendar.Gregorian getGregorianCalendar() {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static sun.util.calendar.CalendarSystem forName(java.lang.String calendarName) {
         throw new RuntimeException("Stub!");
     }
@@ -62,10 +62,10 @@
 
     public abstract sun.util.calendar.CalendarDate newCalendarDate();
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public abstract sun.util.calendar.CalendarDate newCalendarDate(java.util.TimeZone zone);
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public abstract long getTime(sun.util.calendar.CalendarDate date);
 
     public abstract int getYearLength(sun.util.calendar.CalendarDate date);
@@ -88,7 +88,7 @@
     public abstract sun.util.calendar.CalendarDate setTimeOfDay(
             sun.util.calendar.CalendarDate date, int timeOfDay);
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public abstract boolean validate(sun.util.calendar.CalendarDate date);
 
     public abstract boolean normalize(sun.util.calendar.CalendarDate date);
diff --git a/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarUtils.java b/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarUtils.java
index 9ecd8dc..2a05603 100644
--- a/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarUtils.java
+++ b/ojluni/annotations/hiddenapi/sun/util/calendar/CalendarUtils.java
@@ -40,12 +40,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final long floorDivide(long n, long d) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final int floorDivide(int n, int d) {
         throw new RuntimeException("Stub!");
     }
@@ -58,12 +58,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final long mod(long x, long y) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public static final int mod(int x, int y) {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/util/calendar/Era.java b/ojluni/annotations/hiddenapi/sun/util/calendar/Era.java
index 28e5095..49aa034 100644
--- a/ojluni/annotations/hiddenapi/sun/util/calendar/Era.java
+++ b/ojluni/annotations/hiddenapi/sun/util/calendar/Era.java
@@ -28,12 +28,12 @@
 @SuppressWarnings({"unchecked", "deprecation", "all"})
 public final class Era {
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public Era(java.lang.String name, java.lang.String abbr, long since, boolean localTime) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String getName() {
         throw new RuntimeException("Stub!");
     }
@@ -42,7 +42,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public java.lang.String getAbbreviation() {
         throw new RuntimeException("Stub!");
     }
@@ -55,7 +55,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.CalendarDate getSinceDate() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/util/calendar/ImmutableGregorianDate.java b/ojluni/annotations/hiddenapi/sun/util/calendar/ImmutableGregorianDate.java
index 825e9d6..aa92656 100644
--- a/ojluni/annotations/hiddenapi/sun/util/calendar/ImmutableGregorianDate.java
+++ b/ojluni/annotations/hiddenapi/sun/util/calendar/ImmutableGregorianDate.java
@@ -242,7 +242,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     private void unsupported() {
         throw new RuntimeException("Stub!");
     }
diff --git a/ojluni/annotations/hiddenapi/sun/util/calendar/LocalGregorianCalendar.java b/ojluni/annotations/hiddenapi/sun/util/calendar/LocalGregorianCalendar.java
index 95267d0..b1320c5 100644
--- a/ojluni/annotations/hiddenapi/sun/util/calendar/LocalGregorianCalendar.java
+++ b/ojluni/annotations/hiddenapi/sun/util/calendar/LocalGregorianCalendar.java
@@ -68,12 +68,12 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public sun.util.calendar.LocalGregorianCalendar.Date newCalendarDate(java.util.TimeZone zone) {
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public boolean validate(sun.util.calendar.CalendarDate date) {
         throw new RuntimeException("Stub!");
     }
@@ -82,7 +82,7 @@
         throw new RuntimeException("Stub!");
     }
 
-    @dalvik.annotation.compat.UnsupportedAppUsage
+    @android.compat.annotation.UnsupportedAppUsage
     public boolean normalize(sun.util.calendar.CalendarDate date) {
         throw new RuntimeException("Stub!");
     }
@@ -122,7 +122,7 @@
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public sun.util.calendar.LocalGregorianCalendar.Date setEra(sun.util.calendar.Era era) {
             throw new RuntimeException("Stub!");
         }
@@ -131,17 +131,17 @@
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public sun.util.calendar.LocalGregorianCalendar.Date setYear(int localYear) {
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public int getNormalizedYear() {
             throw new RuntimeException("Stub!");
         }
 
-        @dalvik.annotation.compat.UnsupportedAppUsage
+        @android.compat.annotation.UnsupportedAppUsage
         public void setNormalizedYear(int normalizedYear) {
             throw new RuntimeException("Stub!");
         }
diff --git a/ojluni/annotations/mmodule/java/lang/Byte.annotated.java b/ojluni/annotations/mmodule/java/lang/Byte.annotated.java
deleted file mode 100644
index 2d61598..0000000
--- a/ojluni/annotations/mmodule/java/lang/Byte.annotated.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 1996, 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 java.lang;
-
-
-@SuppressWarnings({"unchecked", "deprecation", "all"})
-public final class Byte extends java.lang.Number implements java.lang.Comparable<java.lang.Byte> {
-
-public Byte(byte value) { throw new RuntimeException("Stub!"); }
-
-public Byte(java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
-
-public static java.lang.String toString(byte b) { throw new RuntimeException("Stub!"); }
-
-public static java.lang.Byte valueOf(byte b) { throw new RuntimeException("Stub!"); }
-
-public static byte parseByte(java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
-
-public static byte parseByte(java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
-
-public static java.lang.Byte valueOf(java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
-
-public static java.lang.Byte valueOf(java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
-
-public static java.lang.Byte decode(java.lang.String nm) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
-
-public byte byteValue() { throw new RuntimeException("Stub!"); }
-
-public short shortValue() { throw new RuntimeException("Stub!"); }
-
-public int intValue() { throw new RuntimeException("Stub!"); }
-
-public long longValue() { throw new RuntimeException("Stub!"); }
-
-public float floatValue() { throw new RuntimeException("Stub!"); }
-
-public double doubleValue() { throw new RuntimeException("Stub!"); }
-
-public java.lang.String toString() { throw new RuntimeException("Stub!"); }
-
-public int hashCode() { throw new RuntimeException("Stub!"); }
-
-public static int hashCode(byte value) { throw new RuntimeException("Stub!"); }
-
-public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
-
-public int compareTo(java.lang.Byte anotherByte) { throw new RuntimeException("Stub!"); }
-
-public static int compare(byte x, byte y) { throw new RuntimeException("Stub!"); }
-
-public static int toUnsignedInt(byte x) { throw new RuntimeException("Stub!"); }
-
-public static long toUnsignedLong(byte x) { throw new RuntimeException("Stub!"); }
-
-@libcore.api.CorePlatformApi
-public static java.lang.String toHexString(byte b, boolean upperCase) { throw new RuntimeException("Stub!"); }
-
-public static final int BYTES = 1; // 0x1
-
-public static final byte MAX_VALUE = 127; // 0x7f
-
-public static final byte MIN_VALUE = -128; // 0xffffff80
-
-public static final int SIZE = 8; // 0x8
-
-public static final java.lang.Class<java.lang.Byte> TYPE;
-static { TYPE = null; }
-}
-
diff --git a/ojluni/annotations/mmodule/java/net/SocketImpl.annotated.java b/ojluni/annotations/mmodule/java/net/SocketImpl.annotated.java
index ab1f94e..2146d2f 100644
--- a/ojluni/annotations/mmodule/java/net/SocketImpl.annotated.java
+++ b/ojluni/annotations/mmodule/java/net/SocketImpl.annotated.java
@@ -63,7 +63,7 @@
 protected java.io.FileDescriptor getFileDescriptor() { throw new RuntimeException("Stub!"); }
 
 @libcore.api.CorePlatformApi
-public FileDescriptor getFD$() { throw new RuntimeException("Stub!"); }
+public java.io.FileDescriptor getFD$() { throw new RuntimeException("Stub!"); }
 
 protected java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
 
diff --git a/ojluni/annotations/mmodule/java/nio/charset/CharsetDecoder.annotated.java b/ojluni/annotations/mmodule/java/nio/charset/CharsetDecoder.annotated.java
new file mode 100644
index 0000000..ed0f378
--- /dev/null
+++ b/ojluni/annotations/mmodule/java/nio/charset/CharsetDecoder.annotated.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+
+package java.nio.charset;
+
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+import java.nio.Buffer;
+import java.nio.charset.CoderMalfunctionError;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class CharsetDecoder {
+
+@libcore.api.IntraCoreApi
+protected CharsetDecoder(java.nio.charset.Charset cs, float averageCharsPerByte, float maxCharsPerByte) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.Charset charset() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String replacement() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder replaceWith(java.lang.String newReplacement) { throw new RuntimeException("Stub!"); }
+
+protected void implReplaceWith(java.lang.String newReplacement) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction malformedInputAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder onMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction unmappableCharacterAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder onUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public final float averageCharsPerByte() { throw new RuntimeException("Stub!"); }
+
+public final float maxCharsPerByte() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult decode(java.nio.ByteBuffer in, java.nio.CharBuffer out, boolean endOfInput) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult flush(java.nio.CharBuffer out) { throw new RuntimeException("Stub!"); }
+
+protected java.nio.charset.CoderResult implFlush(java.nio.CharBuffer out) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder reset() { throw new RuntimeException("Stub!"); }
+
+protected void implReset() { throw new RuntimeException("Stub!"); }
+
+protected abstract java.nio.charset.CoderResult decodeLoop(java.nio.ByteBuffer in, java.nio.CharBuffer out);
+
+public final java.nio.CharBuffer decode(java.nio.ByteBuffer in) throws java.nio.charset.CharacterCodingException { throw new RuntimeException("Stub!"); }
+
+public boolean isAutoDetecting() { throw new RuntimeException("Stub!"); }
+
+public boolean isCharsetDetected() { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.Charset detectedCharset() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/ojluni/annotations/mmodule/java/nio/charset/CharsetEncoder.annotated.java b/ojluni/annotations/mmodule/java/nio/charset/CharsetEncoder.annotated.java
new file mode 100644
index 0000000..ceb323e
--- /dev/null
+++ b/ojluni/annotations/mmodule/java/nio/charset/CharsetEncoder.annotated.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+
+package java.nio.charset;
+
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+import java.nio.Buffer;
+import java.nio.charset.CoderMalfunctionError;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class CharsetEncoder {
+
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement) { throw new RuntimeException("Stub!"); }
+
+@libcore.api.IntraCoreApi
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, boolean trusted) { throw new RuntimeException("Stub!"); }
+
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.Charset charset() { throw new RuntimeException("Stub!"); }
+
+public final byte[] replacement() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder replaceWith(byte[] newReplacement) { throw new RuntimeException("Stub!"); }
+
+protected void implReplaceWith(byte[] newReplacement) { throw new RuntimeException("Stub!"); }
+
+public boolean isLegalReplacement(byte[] repl) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction malformedInputAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder onMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction unmappableCharacterAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder onUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public final float averageBytesPerChar() { throw new RuntimeException("Stub!"); }
+
+public final float maxBytesPerChar() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult encode(java.nio.CharBuffer in, java.nio.ByteBuffer out, boolean endOfInput) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult flush(java.nio.ByteBuffer out) { throw new RuntimeException("Stub!"); }
+
+protected java.nio.charset.CoderResult implFlush(java.nio.ByteBuffer out) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder reset() { throw new RuntimeException("Stub!"); }
+
+protected void implReset() { throw new RuntimeException("Stub!"); }
+
+protected abstract java.nio.charset.CoderResult encodeLoop(java.nio.CharBuffer in, java.nio.ByteBuffer out);
+
+public final java.nio.ByteBuffer encode(java.nio.CharBuffer in) throws java.nio.charset.CharacterCodingException { throw new RuntimeException("Stub!"); }
+
+public boolean canEncode(char c) { throw new RuntimeException("Stub!"); }
+
+public boolean canEncode(java.lang.CharSequence cs) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/ojluni/annotations/mmodule/sun/misc/Unsafe.annotated.java b/ojluni/annotations/mmodule/sun/misc/Unsafe.annotated.java
index f272a9a..a6711e0 100644
--- a/ojluni/annotations/mmodule/sun/misc/Unsafe.annotated.java
+++ b/ojluni/annotations/mmodule/sun/misc/Unsafe.annotated.java
@@ -25,6 +25,8 @@
 
 package sun.misc;
 
+// sun.misc.Unsafe is part of the Core Platform API as platform uses protobuf and protobuf uses
+// this API for fast structure updates from native code (b/144502743).
 @libcore.api.CorePlatformApi
 @libcore.api.Hide
 @SuppressWarnings({"unchecked", "deprecation", "all"})
@@ -40,30 +42,80 @@
     }
 
     @libcore.api.CorePlatformApi
-    public long objectFieldOffset(java.lang.reflect.Field field) {
+    public int arrayBaseOffset(Class clazz) {
         throw new RuntimeException("Stub!");
     }
 
     @libcore.api.CorePlatformApi
-    public int arrayBaseOffset(java.lang.Class clazz) {
+    public int arrayIndexScale(Class clazz) {
         throw new RuntimeException("Stub!");
     }
 
     @libcore.api.CorePlatformApi
-    public native byte getByte(java.lang.Object obj, long offset);
+    public native void copyMemory(long srcAddr, long destAddr, long bytes);
+
+    @libcore.api.CorePlatformApi
+    public native boolean getBoolean(Object obj, long offset);
 
     @libcore.api.CorePlatformApi
     public native byte getByte(long address);
 
     @libcore.api.CorePlatformApi
-    public native long getLong(java.lang.Object obj, long offset);
+    public native byte getByte(Object obj, long offset);
+
+    @libcore.api.CorePlatformApi
+    public native double getDouble(Object obj, long offset);
+
+    @libcore.api.CorePlatformApi
+    public native float getFloat(Object obj, long offset);
+
+    @libcore.api.CorePlatformApi
+    public native int getInt(long address);
+
+    @libcore.api.CorePlatformApi
+    public native int getInt(Object obj, long offset);
 
     @libcore.api.CorePlatformApi
     public native long getLong(long address);
 
     @libcore.api.CorePlatformApi
-    public native void putByte(java.lang.Object obj, long offset, byte newValue);
+    public native long getLong(Object obj, long offset);
 
     @libcore.api.CorePlatformApi
-    public native void putByte(long address, byte x);
+    public native Object getObject(Object obj, long offset);
+
+    @libcore.api.CorePlatformApi
+    public long objectFieldOffset(java.lang.reflect.Field field) {
+        throw new RuntimeException("Stub!");
+    }
+
+    @libcore.api.CorePlatformApi
+    public native void putBoolean(Object obj, long offset, boolean newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putByte(long address, byte newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putByte(Object obj, long offset, byte newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putDouble(Object obj, long offset, double newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putFloat(Object obj, long offset, float newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putInt(long address, int newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putInt(Object obj, long offset, int newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putLong(long address, long newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putLong(Object obj, long offset, long newValue);
+
+    @libcore.api.CorePlatformApi
+    public native void putObject(Object obj, long offset, Object newValue);
 }
diff --git a/ojluni/annotations/sdk/nullability/java/lang/Class.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/Class.annotated.java
index 5cbfa49..cb99f54 100644
--- a/ojluni/annotations/sdk/nullability/java/lang/Class.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/lang/Class.annotated.java
@@ -141,9 +141,9 @@
 
 @libcore.util.Nullable public java.io.InputStream getResourceAsStream(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
 
-public java.net.URL getResource(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+@libcore.util.Nullable public java.net.URL getResource(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
 
-public java.security.ProtectionDomain getProtectionDomain() { throw new RuntimeException("Stub!"); }
+@libcore.util.Nullable public java.security.ProtectionDomain getProtectionDomain() { throw new RuntimeException("Stub!"); }
 
 public boolean desiredAssertionStatus() { throw new RuntimeException("Stub!"); }
 
@@ -156,7 +156,7 @@
 
 @libcore.util.NonNull public <U> java.lang.Class<? extends U> asSubclass(@libcore.util.NonNull java.lang.Class<U> clazz) { throw new RuntimeException("Stub!"); }
 
-public <A extends java.lang.annotation.Annotation> A getAnnotation(@libcore.util.NonNull java.lang.Class<A> annotationClass) { throw new RuntimeException("Stub!"); }
+@libcore.util.Nullable public <A extends java.lang.annotation.Annotation> A getAnnotation(@libcore.util.NonNull java.lang.Class<A> annotationClass) { throw new RuntimeException("Stub!"); }
 
 public boolean isAnnotationPresent(@libcore.util.NonNull java.lang.Class<? extends java.lang.annotation.Annotation> annotationClass) { throw new RuntimeException("Stub!"); }
 
diff --git a/ojluni/annotations/sdk/nullability/java/lang/StringBuilder.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/StringBuilder.annotated.java
index 9ec4039..6fdde8a 100644
--- a/ojluni/annotations/sdk/nullability/java/lang/StringBuilder.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/lang/StringBuilder.annotated.java
@@ -119,11 +119,11 @@
 
 public void setCharAt(int index, char ch) { throw new RuntimeException("Stub!"); }
 
-public java.lang.CharSequence subSequence(int start, int end) { throw new RuntimeException("Stub!"); }
+@libcore.util.NonNull public java.lang.CharSequence subSequence(int start, int end) { throw new RuntimeException("Stub!"); }
 
-public java.lang.String substring(int start) { throw new RuntimeException("Stub!"); }
+@libcore.util.NonNull public java.lang.String substring(int start) { throw new RuntimeException("Stub!"); }
 
-public java.lang.String substring(int start, int end) { throw new RuntimeException("Stub!"); }
+@libcore.util.NonNull public java.lang.String substring(int start, int end) { throw new RuntimeException("Stub!"); }
 
 public int capacity() { throw new RuntimeException("Stub!"); }
 
diff --git a/ojluni/annotations/sdk/nullability/java/lang/System.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/System.annotated.java
index b39f09a..4cd1c31 100644
--- a/ojluni/annotations/sdk/nullability/java/lang/System.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/lang/System.annotated.java
@@ -76,7 +76,7 @@
 
 @libcore.util.Nullable public static java.lang.String getenv(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
 
-public static java.util.Map<java.lang.String,java.lang.String> getenv() { throw new RuntimeException("Stub!"); }
+@libcore.util.NonNull public static java.util.Map<java.lang.String,java.lang.String> getenv() { throw new RuntimeException("Stub!"); }
 
 public static void exit(int status) { throw new RuntimeException("Stub!"); }
 
diff --git a/ojluni/annotations/sdk/nullability/java/lang/ThreadLocal.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/ThreadLocal.annotated.java
index 3b7e93a..b8cf527 100644
--- a/ojluni/annotations/sdk/nullability/java/lang/ThreadLocal.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/lang/ThreadLocal.annotated.java
@@ -37,7 +37,7 @@
 
 @libcore.util.Nullable protected T initialValue() { throw new RuntimeException("Stub!"); }
 
-public static <S> java.lang.ThreadLocal<S> withInitial(@libcore.util.NonNull java.util.function.Supplier<? extends S> supplier) { throw new RuntimeException("Stub!"); }
+@libcore.util.NonNull public static <S> java.lang.ThreadLocal<S> withInitial(@libcore.util.NonNull java.util.function.Supplier<? extends S> supplier) { throw new RuntimeException("Stub!"); }
 
 @libcore.util.Nullable public T get() { throw new RuntimeException("Stub!"); }
 
@@ -45,4 +45,3 @@
 
 public void remove() { throw new RuntimeException("Stub!"); }
 }
-
diff --git a/ojluni/annotations/sdk/nullability/java/lang/reflect/Executable.annotated.java b/ojluni/annotations/sdk/nullability/java/lang/reflect/Executable.annotated.java
index 4b5b841..d964aad 100644
--- a/ojluni/annotations/sdk/nullability/java/lang/reflect/Executable.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/lang/reflect/Executable.annotated.java
@@ -61,7 +61,7 @@
 
 public abstract java.lang.annotation.@libcore.util.NonNull Annotation @libcore.util.NonNull [] @libcore.util.NonNull [] getParameterAnnotations();
 
-@libcore.util.Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull getjava.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+@libcore.util.Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
 
 public <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
 
diff --git a/ojluni/annotations/sdk/nullability/java/util/HashMap.annotated.java b/ojluni/annotations/sdk/nullability/java/util/HashMap.annotated.java
index 567354a..3bcc489 100644
--- a/ojluni/annotations/sdk/nullability/java/util/HashMap.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/HashMap.annotated.java
@@ -74,11 +74,11 @@
 
 @libcore.util.Nullable public V computeIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NullFromTypeParam K,? extends @libcore.util.Nullable V> mappingFunction) { throw new RuntimeException("Stub!"); }
 
-@libcore.util.Nullable public V computeIfPresent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NonNull V,? extends Nu V> remappingFunction) { throw new RuntimeException("Stub!"); }
+@libcore.util.Nullable public V computeIfPresent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
 
 @libcore.util.Nullable public 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 V merge(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super Nn V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+@libcore.util.Nullable public 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!"); }
 
 public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
 
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/annotations/sdk/nullability/java/util/logging/Logger.annotated.java b/ojluni/annotations/sdk/nullability/java/util/logging/Logger.annotated.java
index 2ad4bfb..f3a25cb 100644
--- a/ojluni/annotations/sdk/nullability/java/util/logging/Logger.annotated.java
+++ b/ojluni/annotations/sdk/nullability/java/util/logging/Logger.annotated.java
@@ -75,7 +75,7 @@
 
 public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
 
-public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, java.lang.@libcore.util.Nullable Object @Nu [] params) { throw new RuntimeException("Stub!"); }
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, java.lang.@libcore.util.Nullable Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
 
 public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
 
diff --git a/ojluni/src/generated-annotation/java/javax/annotation/processing/Generated.java b/ojluni/src/generated-annotation/java/javax/annotation/processing/Generated.java
new file mode 100644
index 0000000..cd3e666
--- /dev/null
+++ b/ojluni/src/generated-annotation/java/javax/annotation/processing/Generated.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005, 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 javax.annotation.processing;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+// Android-changed: Javadoc removed (this is just a stub).
+
+@Documented
+@Retention(SOURCE)
+@Target({PACKAGE, TYPE, METHOD, CONSTRUCTOR, FIELD,
+    LOCAL_VARIABLE, PARAMETER})
+public @interface Generated {
+
+    String[] value();
+
+    String date() default "";
+
+    String comments() default "";
+}
diff --git a/ojluni/src/lambda/java/java/lang/invoke/TEST_MAPPING b/ojluni/src/lambda/java/java/lang/invoke/TEST_MAPPING
new file mode 100644
index 0000000..e321f0b
--- /dev/null
+++ b/ojluni/src/lambda/java/java/lang/invoke/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/libart/src/main/java/java/lang/invoke"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/awt/font/TEST_MAPPING b/ojluni/src/main/java/java/awt/font/TEST_MAPPING
new file mode 100644
index 0000000..a23d298
--- /dev/null
+++ b/ojluni/src/main/java/java/awt/font/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.awt.font"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/beans/TEST_MAPPING b/ojluni/src/main/java/java/beans/TEST_MAPPING
new file mode 100644
index 0000000..0e669a8
--- /dev/null
+++ b/ojluni/src/main/java/java/beans/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.beans.tests.java.beans"
+        },
+        {
+          "include-filter": "libcore.java.util.beans"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/io/FileDescriptor.java b/ojluni/src/main/java/java/io/FileDescriptor.java
index a2c833d..98db443 100644
--- a/ojluni/src/main/java/java/io/FileDescriptor.java
+++ b/ojluni/src/main/java/java/io/FileDescriptor.java
@@ -46,9 +46,9 @@
  * @see     java.io.FileOutputStream
  * @since   JDK1.0
  */
-// Android-changed: Removed parent reference counting. Creator is responsible for closing
-// the file descriptor.
 public final class FileDescriptor {
+    // Android-changed: Removed parent reference counting. Creator is responsible for closing
+    // the file descriptor.
 
     // Android-changed: Renamed fd to descriptor to avoid issues with JNI/reflection
     // fetching the descriptor value.
@@ -82,8 +82,7 @@
      *
      * @see     java.lang.System#in
      */
-    // Android-changed: Duplicates of FDs needed for RuntimeInit#redirectLogStreams
-    public static final FileDescriptor in = dupFd(0);
+    public static final FileDescriptor in = new FileDescriptor(0);
 
     /**
      * A handle to the standard output stream. Usually, this file
@@ -91,8 +90,7 @@
      * known as <code>System.out</code>.
      * @see     java.lang.System#out
      */
-    // Android-changed: Duplicates of FDs needed for RuntimeInit#redirectLogStreams
-    public static final FileDescriptor out = dupFd(1);
+    public static final FileDescriptor out = new FileDescriptor(1);
 
     /**
      * A handle to the standard error stream. Usually, this file
@@ -101,8 +99,7 @@
      *
      * @see     java.lang.System#err
      */
-    // Android-changed: Duplicates of FDs needed for RuntimeInit#redirectLogStreams
-    public static final FileDescriptor err = dupFd(2);
+    public static final FileDescriptor err = new FileDescriptor(2);
 
     /**
      * Tests if this file descriptor object is valid.
@@ -169,6 +166,26 @@
         this.descriptor = fd;
     }
 
+    // BEGIN Android-added: Method to clone standard file descriptors.
+    // Required as a consequence of RuntimeInit#redirectLogStreams. Cloning is used in
+    // ZygoteHooks.onEndPreload().
+    /**
+     * Clones the current native file descriptor and uses this for this FileDescriptor instance.
+     *
+     * This method does not close the current native file descriptor.
+     *
+     * @hide internal use only
+     */
+    public void cloneForFork() {
+        try {
+            int newDescriptor = Os.fcntlInt(this, F_DUPFD_CLOEXEC, 0);
+            this.descriptor = newDescriptor;
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    // END Android-added: Method to clone standard file descriptors.
+
     // BEGIN Android-added: Methods to enable ownership enforcement of Unix file descriptors.
     /**
      * Returns the owner ID of this FileDescriptor. It's highly unlikely you should be calling this.
@@ -206,23 +223,14 @@
     }
     // END Android-added: Methods to enable ownership enforcement of Unix file descriptors.
 
+    // Android-added: Needed for framework to test if it's a socket
     /**
      * @hide internal use only
      */
-    // Android-added: Needed for framework to test if it's a socket
     public boolean isSocket$() {
         return isSocket(descriptor);
     }
 
-    // Android-added: Needed for RuntimeInit#redirectLogStreams.
-    private static FileDescriptor dupFd(int fd) {
-        try {
-            return new FileDescriptor(Os.fcntlInt(new FileDescriptor(fd), F_DUPFD_CLOEXEC, 0));
-        } catch (ErrnoException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     private static native boolean isSocket(int descriptor);
     // Set up JavaIOFileDescriptorAccess in SharedSecrets
     static {
diff --git a/ojluni/src/main/java/java/io/FileInputStream.java b/ojluni/src/main/java/java/io/FileInputStream.java
index 74ee3aa..38230bb 100755
--- a/ojluni/src/main/java/java/io/FileInputStream.java
+++ b/ojluni/src/main/java/java/io/FileInputStream.java
@@ -154,9 +154,11 @@
         if (file.isInvalid()) {
             throw new FileNotFoundException("Invalid file path");
         }
-        // Android-changed: Open files through common bridge code.
+        // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+        // http://b/112107427
         // fd = new FileDescriptor();
         fd = IoBridge.open(name, O_RDONLY);
+        // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
 
         // Android-changed: Tracking mechanism for FileDescriptor sharing.
         // fd.attach(this);
@@ -164,7 +166,7 @@
 
         path = name;
 
-        // Android-removed: Open files through common bridge code.
+        // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
         // open(name);
 
         // Android-added: File descriptor ownership tracking.
@@ -222,20 +224,25 @@
         this.isFdOwner = isFdOwner;
     }
 
+    // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+    // http://b/112107427
+    /*
     /**
      * Opens the specified file for reading.
      * @param name the name of the file
-     */
+     *
     private native void open0(String name) throws FileNotFoundException;
 
     // wrap native call to allow instrumentation
     /**
      * Opens the specified file for reading.
      * @param name the name of the file
-     */
+     *
     private void open(String name) throws FileNotFoundException {
         open0(name);
     }
+    */
+    // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
 
     /**
      * Reads a byte of data from this input stream. This method blocks
diff --git a/ojluni/src/main/java/java/io/FileOutputStream.java b/ojluni/src/main/java/java/io/FileOutputStream.java
index 95ad1be..d0d0d40 100755
--- a/ojluni/src/main/java/java/io/FileOutputStream.java
+++ b/ojluni/src/main/java/java/io/FileOutputStream.java
@@ -229,11 +229,12 @@
         if (file.isInvalid()) {
             throw new FileNotFoundException("Invalid file path");
         }
-        // BEGIN Android-changed: Open files through common bridge code.
+        // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+        // http://b/111268862
         // this.fd = new FileDescriptor();
         int flags = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC);
         this.fd = IoBridge.open(name, flags);
-        // END Android-changed: Open files through common bridge code.
+        // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
 
         // Android-changed: Tracking mechanism for FileDescriptor sharing.
         // fd.attach(this);
@@ -242,7 +243,7 @@
         this.append = append;
         this.path = name;
 
-        // Android-removed: Open files through common bridge code.
+        // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
         // open(name, append);
 
         // Android-added: File descriptor ownership tracking.
@@ -300,11 +301,14 @@
         this.isFdOwner = isFdOwner;
     }
 
+    // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+    // http://b/112107427
+    /*
     /**
      * Opens a file, with the specified name, for overwriting or appending.
      * @param name name of file to be opened
      * @param append whether the file is to be opened in append mode
-     */
+     *
     private native void open0(String name, boolean append)
         throws FileNotFoundException;
 
@@ -313,11 +317,13 @@
      * Opens a file, with the specified name, for overwriting or appending.
      * @param name name of file to be opened
      * @param append whether the file is to be opened in append mode
-     */
+     *
     private void open(String name, boolean append)
         throws FileNotFoundException {
         open0(name, append);
     }
+    */
+    // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
 
     // Android-removed: write(int, boolean), use IoBridge instead.
     /*
diff --git a/ojluni/src/main/java/java/io/FilterOutputStream.java b/ojluni/src/main/java/java/io/FilterOutputStream.java
index 209e63b..89f5ef5 100644
--- a/ojluni/src/main/java/java/io/FilterOutputStream.java
+++ b/ojluni/src/main/java/java/io/FilterOutputStream.java
@@ -48,6 +48,12 @@
      */
     protected OutputStream out;
 
+    // Android-added: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
+    /**
+     * Whether the stream is closed; implicitly initialized to false.
+     */
+    private boolean closed;
+
     /**
      * Creates an output stream filter built on top of the specified
      * underlying output stream.
@@ -144,18 +150,58 @@
      * Closes this output stream and releases any system resources
      * associated with the stream.
      * <p>
-     * The <code>close</code> method of <code>FilterOutputStream</code>
-     * calls its <code>flush</code> method, and then calls the
-     * <code>close</code> method of its underlying output stream.
+     * When not already closed, the {@code close} method of {@code
+     * FilterOutputStream} calls its {@code flush} method, and then
+     * calls the {@code close} method of its underlying output stream.
      *
      * @exception  IOException  if an I/O error occurs.
      * @see        java.io.FilterOutputStream#flush()
      * @see        java.io.FilterOutputStream#out
      */
+    // BEGIN Android-changed: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
+    /*
     @SuppressWarnings("try")
     public void close() throws IOException {
         try (OutputStream ostream = out) {
             flush();
         }
     }
+    */
+    @Override
+    public void close() throws IOException {
+        if (closed) {
+            return;
+        }
+        closed = true;
+
+        Throwable flushException = null;
+        try {
+            flush();
+        } catch (Throwable e) {
+            flushException = e;
+            throw e;
+        } finally {
+            if (flushException == null) {
+                out.close();
+            } else {
+                try {
+                    out.close();
+                } catch (Throwable closeException) {
+                   // evaluate possible precedence of flushException over closeException
+                   if ((flushException instanceof ThreadDeath) &&
+                       !(closeException instanceof ThreadDeath)) {
+                       flushException.addSuppressed(closeException);
+                       throw (ThreadDeath) flushException;
+                   }
+
+                    if (flushException != closeException) {
+                        closeException.addSuppressed(flushException);
+                    }
+
+                    throw closeException;
+                }
+            }
+        }
+    }
+    // END Android-changed: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
 }
diff --git a/ojluni/src/main/java/java/io/InterruptedIOException.java b/ojluni/src/main/java/java/io/InterruptedIOException.java
index 25569dd..29b7c29 100644
--- a/ojluni/src/main/java/java/io/InterruptedIOException.java
+++ b/ojluni/src/main/java/java/io/InterruptedIOException.java
@@ -73,18 +73,18 @@
      */
     public int bytesTransferred = 0;
 
-    /** @hide */
     // Android-added: Additional constructor for internal use.
+    /** @hide */
     public InterruptedIOException(Throwable cause) {
         super(cause);
     }
 
+    // Android-added: Additional constructor for internal use.
     /**
      * Constructs a new instance with given detail message and cause.
      *
      * @hide internal use only
      */
-    // Android-added: Additional constructor for internal use.
     public InterruptedIOException(String detailMessage, Throwable cause) {
         super(detailMessage, cause);
     }
diff --git a/ojluni/src/main/java/java/io/ObjectInputStream.java b/ojluni/src/main/java/java/io/ObjectInputStream.java
index 56b5abe..8369a59 100644
--- a/ojluni/src/main/java/java/io/ObjectInputStream.java
+++ b/ojluni/src/main/java/java/io/ObjectInputStream.java
@@ -202,7 +202,7 @@
  * @see java.io.DataInput
  * @see java.io.ObjectOutputStream
  * @see java.io.Serializable
- * @see <a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
+ * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
  * @since   JDK1.1
  */
 public class ObjectInputStream
diff --git a/ojluni/src/main/java/java/io/ObjectOutputStream.java b/ojluni/src/main/java/java/io/ObjectOutputStream.java
index fa8a658..ccec944 100644
--- a/ojluni/src/main/java/java/io/ObjectOutputStream.java
+++ b/ojluni/src/main/java/java/io/ObjectOutputStream.java
@@ -157,7 +157,7 @@
  * @see java.io.ObjectInputStream
  * @see java.io.Serializable
  * @see java.io.Externalizable
- * @see <a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
+ * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
  * @since       JDK1.1
  */
 public class ObjectOutputStream
diff --git a/ojluni/src/main/java/java/io/ObjectStreamClass.java b/ojluni/src/main/java/java/io/ObjectStreamClass.java
index 7d2efd2..a88ad63 100644
--- a/ojluni/src/main/java/java/io/ObjectStreamClass.java
+++ b/ojluni/src/main/java/java/io/ObjectStreamClass.java
@@ -60,13 +60,13 @@
  * loaded in this Java VM can be found/created using the lookup method.
  *
  * <p>The algorithm to compute the SerialVersionUID is described in
- * <a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html#4100">Object
+ * <a href="../../../platform/serialization/spec/class.html#4100">Object
  * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
  *
  * @author      Mike Warres
  * @author      Roger Riggs
  * @see ObjectStreamField
- * @see <a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
+ * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
  * @since   JDK1.1
  */
 public class ObjectStreamClass implements Serializable {
diff --git a/ojluni/src/main/java/java/io/TEST_MAPPING b/ojluni/src/main/java/java/io/TEST_MAPPING
new file mode 100644
index 0000000..6eb3bd7
--- /dev/null
+++ b/ojluni/src/main/java/java/io/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.io"
+        },
+        {
+          "include-filter": "org.apache.harmony.luni.tests.java.io"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.io"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/io/package.html b/ojluni/src/main/java/java/io/package.html
index db1c8a5..1b909ad 100644
--- a/ojluni/src/main/java/java/io/package.html
+++ b/ojluni/src/main/java/java/io/package.html
@@ -36,7 +36,7 @@
 
 <h2>Package Specification</h2>
 <ul>
-  <li><a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html"> Java Object Serialization Specification </a>
+  <li><a href="../../../platform/serialization/spec/serialTOC.html"> Java Object Serialization Specification </a>
 </ul>
 
 <h2>Related Documentation</h2>
@@ -44,7 +44,7 @@
 For overviews, tutorials, examples, guides, and tool documentation,
 please see:
 <ul>
-  <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/serialization">Serialization Enhancements</a>
+  <li><a href="../../../technotes/guides/serialization">Serialization Enhancements</a>
 </ul>
 
 @since JDK1.0
diff --git a/ojluni/src/main/java/java/lang/Byte.java b/ojluni/src/main/java/java/lang/Byte.java
index e53899c..deb4ecb 100644
--- a/ojluni/src/main/java/java/lang/Byte.java
+++ b/ojluni/src/main/java/java/lang/Byte.java
@@ -25,6 +25,8 @@
 
 package java.lang;
 
+import libcore.util.HexEncoding;
+
 /**
  *
  * The {@code Byte} class wraps a value of primitive type {@code byte}
@@ -523,24 +525,8 @@
      * @hide
      */
     public static String toHexString(byte b, boolean upperCase) {
-        char[] digits = upperCase ? UPPER_CASE_DIGITS : DIGITS;
-        char[] buf = new char[2]; // We always want two digits.
-        buf[0] = digits[(b >> 4) & 0xf];
-        buf[1] = digits[b & 0xf];
-        return new String(0, 2, buf);
+        // This method currently retained because it is marked @UnsupportedAppUsage.
+        return HexEncoding.encodeToString(b, upperCase);
     }
-    private static final char[] DIGITS = {
-        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
-        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
-        'u', 'v', 'w', 'x', 'y', 'z'
-    };
-
-    private static final char[] UPPER_CASE_DIGITS = {
-        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
-        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
-        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
-        'U', 'V', 'W', 'X', 'Y', 'Z'
-    };
     // END Android-added: toHexString() for internal use.
 }
diff --git a/ojluni/src/main/java/java/lang/Comparable.java b/ojluni/src/main/java/java/lang/Comparable.java
index f0e4b38..a88cf16 100644
--- a/ojluni/src/main/java/java/lang/Comparable.java
+++ b/ojluni/src/main/java/java/lang/Comparable.java
@@ -84,7 +84,7 @@
  *     {(x, y) such that x.equals(y)}. </pre><p>
  *
  * This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <T> the type of objects that this object may be compared to
diff --git a/ojluni/src/main/java/java/lang/Iterable.java b/ojluni/src/main/java/java/lang/Iterable.java
index db0e767..eed3938 100644
--- a/ojluni/src/main/java/java/lang/Iterable.java
+++ b/ojluni/src/main/java/java/lang/Iterable.java
@@ -30,12 +30,11 @@
 import java.util.Spliterators;
 import java.util.function.Consumer;
 
-// Android-changed: href changed in javadoc for redirection.
 /**
  * Implementing this interface allows an object to be the target of
  * the "for-each loop" statement. See
  * <strong>
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/language/foreach.html">For-each Loop</a>
+ * <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>
  * </strong>
  *
  * @param <T> the type of elements returned by the iterator
diff --git a/ojluni/src/main/java/java/lang/Math.java b/ojluni/src/main/java/java/lang/Math.java
index bb84b81..17cbf6d 100644
--- a/ojluni/src/main/java/java/lang/Math.java
+++ b/ojluni/src/main/java/java/lang/Math.java
@@ -31,6 +31,10 @@
 import sun.misc.FloatConsts;
 import sun.misc.DoubleConsts;
 
+// Android-note: Document that the results from Math are based on libm's behavior.
+// For performance, Android implements many of the methods in this class in terms of the underlying
+// OS's libm functions. libm has well-defined behavior for special cases. Where known these are
+// marked with the tag above and the documentation has been modified as needed.
 /**
  * The class {@code Math} contains methods for performing basic
  * numeric operations such as the elementary exponential, logarithm,
@@ -502,6 +506,11 @@
     @CriticalNative
     public static native double atan2(double y, double x);
 
+    // Android-changed: Document that the results from Math are based on libm's behavior.
+    // The cases known to differ with libm's pow():
+    //   If the first argument is 1.0 then result is always 1.0 (not NaN).
+    //   If the first argument is -1.0 and the second argument is infinite, the result is 1.0 (not
+    //   NaN).
     /**
      * Returns the value of the first argument raised to the power of the
      * second argument. Special cases:
@@ -510,7 +519,9 @@
      * result is 1.0.
      * <li>If the second argument is 1.0, then the result is the same as the
      * first argument.
-     * <li>If the second argument is NaN, then the result is NaN.
+     * <li>If the first argument is 1.0, then the result is 1.0.
+     * <li>If the second argument is NaN, then the result is NaN except where the first argument is
+     * 1.0.
      * <li>If the first argument is NaN and the second argument is nonzero,
      * then the result is NaN.
      *
@@ -534,7 +545,7 @@
      * then the result is positive zero.
      *
      * <li>If the absolute value of the first argument equals 1 and the
-     * second argument is infinite, then the result is NaN.
+     * second argument is infinite, then the result is 1.0.
      *
      * <li>If
      * <ul>
diff --git a/ojluni/src/main/java/java/lang/Runtime.java b/ojluni/src/main/java/java/lang/Runtime.java
index bb0bcb4..f5c52e7 100644
--- a/ojluni/src/main/java/java/lang/Runtime.java
+++ b/ojluni/src/main/java/java/lang/Runtime.java
@@ -35,7 +35,8 @@
 import java.lang.ref.FinalizerReference;
 import java.util.ArrayList;
 import java.util.List;
-import dalvik.system.BaseDexClassLoader;
+import dalvik.system.DelegateLastClassLoader;
+import dalvik.system.PathClassLoader;
 import dalvik.system.VMDebug;
 import dalvik.system.VMRuntime;
 import sun.reflect.Reflection;
@@ -1058,6 +1059,21 @@
         // have returned null; therefore we treat BootClassLoader the same as null here.
         if (loader != null && !(loader instanceof BootClassLoader)) {
             String filename = loader.findLibrary(libraryName);
+            if (filename == null &&
+                    (loader.getClass() == PathClassLoader.class ||
+                     loader.getClass() == DelegateLastClassLoader.class)) {
+                // Don't give up even if we failed to find the library in the native lib paths.
+                // The underlying dynamic linker might be able to find the lib in one of the linker
+                // namespaces associated with the current linker namespace. In order to give the
+                // dynamic linker a chance, proceed to load the library with its soname, which
+                // is the fileName.
+                // Note that we do this only for PathClassLoader  and DelegateLastClassLoader to
+                // minimize the scope of this behavioral change as much as possible, which might
+                // cause problem like b/143649498. These two class loaders are the only
+                // platform-provided class loaders that can load apps. See the classLoader attribute
+                // of the application tag in app manifest.
+                filename = System.mapLibraryName(libraryName);
+            }
             if (filename == null) {
                 // It's not necessarily true that the ClassLoader used
                 // System.mapLibraryName, but the default setup does, and it's
diff --git a/ojluni/src/main/java/java/lang/String.java b/ojluni/src/main/java/java/lang/String.java
index 58207eb..2ba7b1f 100644
--- a/ojluni/src/main/java/java/lang/String.java
+++ b/ojluni/src/main/java/java/lang/String.java
@@ -144,7 +144,7 @@
      * Class String is special cased within the Serialization Stream Protocol.
      *
      * A String instance is written into an ObjectOutputStream according to
-     * <a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/output.html">
+     * <a href="{@docRoot}/../platform/serialization/spec/output.html">
      * Object Serialization Specification, Section 6.2, "Stream Elements"</a>
      */
     private static final ObjectStreamField[] serialPersistentFields =
diff --git a/ojluni/src/main/java/java/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index 8235bf7..352d9ec 100644
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -25,20 +25,19 @@
  */
 package java.lang;
 
+import com.android.icu.util.Icu4cMetadata;
+import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 import android.system.ErrnoException;
 import android.system.StructPasswd;
 import android.system.StructUtsname;
 import dalvik.system.VMRuntime;
 import java.io.*;
-import java.lang.annotation.Annotation;
 import java.nio.channels.Channel;
 import java.nio.channels.spi.SelectorProvider;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Properties;
 import java.util.PropertyPermission;
-import libcore.icu.ICU;
 import libcore.io.Libcore;
 import libcore.timezone.TimeZoneDataFiles;
 
@@ -296,6 +295,7 @@
      *          the current time and midnight, January 1, 1970 UTC.
      * @see     java.util.Date
      */
+    @CriticalNative
     public static native long currentTimeMillis();
 
     /**
@@ -342,6 +342,7 @@
      *         high-resolution time source, in nanoseconds
      * @since 1.5
      */
+    @CriticalNative
     public static native long nanoTime();
 
     /**
@@ -509,13 +510,9 @@
      * The byte[] specialized version of arraycopy().
      * Note: This method is required for runtime ART compiler optimizations.
      * Do not remove or change the signature.
-     * Note: Unlike the others, this variant is public due to a dependency we
-     * are working on removing. b/74103559
-     *
-     * @hide
      */
     @SuppressWarnings("unused")
-    public static void arraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) {
+    private static void arraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) {
         if (src == null) {
             throw new NullPointerException("src == null");
         }
@@ -1000,9 +997,9 @@
         p.put("os.version", info.release);
 
         // Android-added: Undocumented properties that exist only on Android.
-        p.put("android.icu.library.version", ICU.getIcuVersion());
-        p.put("android.icu.unicode.version", ICU.getUnicodeVersion());
-        p.put("android.icu.cldr.version", ICU.getCldrVersion());
+        p.put("android.icu.library.version", Icu4cMetadata.getIcuVersion());
+        p.put("android.icu.unicode.version", Icu4cMetadata.getUnicodeVersion());
+        p.put("android.icu.cldr.version", Icu4cMetadata.getCldrVersion());
 
         // Property override for ICU4J : this is the location of the ICU4C data. This
         // is prioritized over the properties in ICUConfig.properties. The issue with using
diff --git a/ojluni/src/main/java/java/lang/TEST_MAPPING b/ojluni/src/main/java/java/lang/TEST_MAPPING
new file mode 100644
index 0000000..9374f92
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/libart/src/main/java/java/lang"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index 54fd49a..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;
 
@@ -282,11 +284,11 @@
     private volatile Interruptible blocker;
     private final Object blockerLock = new Object();
 
-    /** Set the blocker field
-     * @hide
-     */
     // Android-changed: Make blockedOn() @hide public, for internal use.
-    // Used by java.nio.channels.spi.AbstractInterruptibleChannel.
+    // Changed comment to reflect usage on Android
+    /* Set the blocker field; used by java.nio.channels.spi.AbstractInterruptibleChannel
+     */
+    /** @hide */
     public void blockedOn(Interruptible b) {
         synchronized (blockerLock) {
             blocker = b;
@@ -662,8 +664,8 @@
         init(group, null, name, 0);
     }
 
+    // BEGIN Android-added: Private constructor - used by the runtime.
     /** @hide */
-    // Android-added: Private constructor - used by the runtime.
     Thread(ThreadGroup group, String name, int priority, boolean daemon) {
         this.group = group;
         this.group.addUnstarted();
@@ -692,6 +694,8 @@
                     parent.inheritableThreadLocals);
         }
     }
+    // END Android-added: Private constructor - used by the runtime.
+
 
     /**
      * Allocates a new {@code Thread} object. This constructor has the same
@@ -961,7 +965,7 @@
      *       for example), the <code>interrupt</code> method should be used to
      *       interrupt the wait.
      *       For more information, see
-     *       <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
+     *       <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
      *       are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
      */
     @Deprecated
@@ -997,7 +1001,7 @@
      *        could be used to generate exceptions that the target thread was
      *        not prepared to handle.
      *        For more information, see
-     *        <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
+     *        <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
      *        are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
      */
     @Deprecated
@@ -1122,7 +1126,7 @@
     private native boolean isInterrupted(boolean ClearInterrupted);
     */
 
-    // Android-changed: Throw UnsupportedOperationException instead of NoSuchMethodError.
+    // BEGIN Android-changed: Throw UnsupportedOperationException instead of NoSuchMethodError.
     /**
      * Throws {@link UnsupportedOperationException}.
      *
@@ -1136,7 +1140,7 @@
      *     If another thread ever attempted to lock this resource, deadlock
      *     would result. Such deadlocks typically manifest themselves as
      *     "frozen" processes. For more information, see
-     *     <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html">
+     *     <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
      *     Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
      * @throws UnsupportedOperationException always
      */
@@ -1144,6 +1148,7 @@
     public void destroy() {
         throw new UnsupportedOperationException();
     }
+    // END Android-changed: Throw UnsupportedOperationException instead of NoSuchMethodError.
 
     /**
      * Tests if this thread is alive. A thread is alive if it has
@@ -1169,7 +1174,7 @@
      *   monitor prior to calling <code>resume</code>, deadlock results.  Such
      *   deadlocks typically manifest themselves as "frozen" processes.
      *   For more information, see
-     *   <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
+     *   <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
      *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
      * @throws UnsupportedOperationException always
      */
@@ -1189,7 +1194,7 @@
      * @deprecated This method exists solely for use with {@link #suspend},
      *     which has been deprecated because it is deadlock-prone.
      *     For more information, see
-     *     <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
+     *     <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
      *     are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
      * @throws UnsupportedOperationException always
      */
@@ -1241,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().
                 }
             }
         }
@@ -2106,7 +2122,7 @@
         return defaultUncaughtExceptionHandler;
     }
 
-    // BEGIN Android-added: uncaughtExceptionPreHandler for use by platform.
+    // BEGIN Android-added: The concept of an uncaughtExceptionPreHandler for use by platform.
     // See http://b/29624607 for background information.
     // null unless explicitly set
     private static volatile UncaughtExceptionHandler uncaughtExceptionPreHandler;
@@ -2129,7 +2145,7 @@
     public static UncaughtExceptionHandler getUncaughtExceptionPreHandler() {
         return uncaughtExceptionPreHandler;
     }
-    // END Android-added: uncaughtExceptionPreHandler for use by platform.
+    // END Android-added: The concept of an uncaughtExceptionPreHandler for use by platform.
 
     /**
      * Returns the handler invoked when this thread abruptly terminates
@@ -2324,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/lang/UnsupportedOperationException.java b/ojluni/src/main/java/java/lang/UnsupportedOperationException.java
index 1de2508..fcb355c 100644
--- a/ojluni/src/main/java/java/lang/UnsupportedOperationException.java
+++ b/ojluni/src/main/java/java/lang/UnsupportedOperationException.java
@@ -29,7 +29,7 @@
  * Thrown to indicate that the requested operation is not supported.<p>
  *
  * This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author  Josh Bloch
diff --git a/ojluni/src/main/java/java/lang/annotation/TEST_MAPPING b/ojluni/src/main/java/java/lang/annotation/TEST_MAPPING
new file mode 100644
index 0000000..f5f6365
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/annotation/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.lang.reflect.annotations"
+        },
+        {
+          "include-filter": "libcore.java.lang.annotation"
+        },
+        {
+          "include-filter": "org.apache.harmony.annotation.tests.java.lang.annotation"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
index 17c5f57..1188ac6 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
@@ -1129,7 +1129,8 @@
 
             // Make sure that the special caller is identical to the lookup class or that we have
             // private access.
-            checkSpecialCaller(specialCaller);
+            // Android-changed: Also allow access to any interface methods.
+            checkSpecialCaller(specialCaller, refc);
 
             // Even though constructors are invoked using a "special" invoke, handles to them can't
             // be created using findSpecial. Callers must use findConstructor instead. Similarly,
@@ -1655,7 +1656,9 @@
             }
 
             if (!m.isAccessible()) {
-                checkSpecialCaller(specialCaller);
+                // Android-changed: Match Java language 9 behavior where unreflectSpecial continues
+                // to require exact caller lookupClass match.
+                checkSpecialCaller(specialCaller, null);
             }
 
             final MethodType methodType = MethodType.methodType(m.getReturnType(),
@@ -1937,13 +1940,19 @@
         //
         // private static final boolean ALLOW_NESTMATE_ACCESS = false;
 
-        private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
+        // Android-changed: Match java language 9 behavior allowing special access if the reflected
+        // class (called 'refc', the class from which the method is being accessed) is an interface
+        // and is implemented by the caller.
+        private void checkSpecialCaller(Class<?> specialCaller, Class<?> refc) throws IllegalAccessException {
             // Android-changed: No support for TRUSTED lookups. Also construct the
             // IllegalAccessException by hand because the upstream code implicitly assumes
             // that the lookupClass == specialCaller.
             //
             // if (allowedModes == TRUSTED)  return;
-            if (!hasPrivateAccess() || (specialCaller != lookupClass())) {
+            boolean isInterfaceLookup = (refc != null &&
+                                         refc.isInterface() &&
+                                         refc.isAssignableFrom(specialCaller));
+            if (!hasPrivateAccess() || (specialCaller != lookupClass() && !isInterfaceLookup)) {
                 throw new IllegalAccessException("no private access for invokespecial : "
                         + specialCaller + ", from" + this);
             }
@@ -2588,15 +2597,24 @@
         MethodType oldType = target.type();
         if (oldType == newType) return target;
         if (oldType.explicitCastEquivalentToAsType(newType)) {
-            return target.asFixedArity().asType(newType);
+            if (Transformers.Transformer.class.isAssignableFrom(target.getClass())) {
+                // The StackFrameReader and StackFrameWriter used to perform transforms on
+                // EmulatedStackFrames (in Transformers.java) do not how to perform asType()
+                // conversions, but we know here that an explicit cast transform is the same as
+                // having called asType() on the method handle.
+                return new Transformers.ExplicitCastArguments(target.asFixedArity(), newType);
+            } else {
+                // Runtime will perform asType() conversion during invocation.
+                return target.asFixedArity().asType(newType);
+            }
         }
-
         return new Transformers.ExplicitCastArguments(target, newType);
     }
 
     private static void explicitCastArgumentsChecks(MethodHandle target, MethodType newType) {
         if (target.type().parameterCount() != newType.parameterCount()) {
-            throw new WrongMethodTypeException("cannot explicitly cast " + target + " to " + newType);
+            throw new WrongMethodTypeException("cannot explicitly cast " + target +
+                                               " to " + newType);
         }
     }
 
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodType.java b/ojluni/src/main/java/java/lang/invoke/MethodType.java
index b2ff6e7..4652c93 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodType.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodType.java
@@ -894,9 +894,6 @@
         return true;
     }
 
-    // Android-changed: Temporary workaround for bug in MethodHandle.asType(MethodType).
-    // See http://b/113855305 for more details
-    // Update documentation to describe new behavior.
     /** Reports true if the src can be converted to the dst, by both asType and MHs.eCE,
      *  and with the same effect.
      *  MHs.eCA has the following "upgrades" to MH.asType:
@@ -914,9 +911,7 @@
      */
     private static boolean explicitCastEquivalentToAsType(Class<?> src, Class<?> dst) {
         if (src == dst || dst == Object.class || dst == void.class)  return true;
-        // Android-changed: Temporary workaround for bug in MethodHandle.asType(MethodType).
-        // if (src.isPrimitive()) {
-        if (src.isPrimitive() && src != void.class) {
+        if (src.isPrimitive()) {
             // Could be a prim/prim conversion, where casting is a strict superset.
             // Or a boxing conversion, which is always to an exact wrapper class.
             return canConvert(src, dst);
diff --git a/ojluni/src/main/java/java/lang/invoke/TEST_MAPPING b/ojluni/src/main/java/java/lang/invoke/TEST_MAPPING
new file mode 100644
index 0000000..e321f0b
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/libart/src/main/java/java/lang/invoke"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/lang/invoke/Transformers.java b/ojluni/src/main/java/java/lang/invoke/Transformers.java
index fc8727a..15546a8 100644
--- a/ojluni/src/main/java/java/lang/invoke/Transformers.java
+++ b/ojluni/src/main/java/java/lang/invoke/Transformers.java
@@ -417,7 +417,7 @@
 
         @Override
         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
-            final Class<?> receiverType = type().rtype();
+            final Class<?> receiverType = constructorHandle.type().parameterType(0);
             checkInstantiable(receiverType);
 
             // Allocate memory for receiver.
@@ -1827,27 +1827,9 @@
             throw new InternalError("Unexpected type: " + unexpectedType);
         }
 
-        private static void explicitCastFromBoolean(boolean fromValue,
-                                                    final StackFrameWriter writer,
-                                                    final Class<?> to) {
-            int value = fromValue ? 1 : 0;
-            if (to == byte.class) {
-                writer.putNextByte((byte) value);
-            } else if (to == char.class) {
-                writer.putNextChar((char) value);
-            } else if (to == short.class) {
-                writer.putNextShort((short) value);
-            } else if (to == int.class) {
-                writer.putNextInt(value);
-            } else if (to == long.class) {
-                writer.putNextLong(value);
-            } else if (to == float.class) {
-                writer.putNextFloat(value);
-            } else if (to == double.class) {
-                writer.putNextDouble(value);
-            } else {
-                throwUnexpectedType(to);
-            }
+        @SuppressWarnings("unchecked")
+        private static void badCast(final Class<?> from, final Class<?> to) {
+            throw new ClassCastException("Cannot cast " + from.getName() + " to " + to.getName());
         }
 
         /**
@@ -1874,6 +1856,8 @@
                 return (byte) reader.nextFloat();
             } else if (from == double.class) {
                 return (byte) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? (byte) 1 : (byte) 0;
             } else {
                 throwUnexpectedType(from);
                 return 0;
@@ -1896,6 +1880,8 @@
                 return (char) reader.nextFloat();
             } else if (from == double.class) {
                 return (char) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? (char) 1 : (char) 0;
             } else {
                 throwUnexpectedType(from);
                 return 0;
@@ -1918,6 +1904,8 @@
                 return (short) reader.nextFloat();
             } else if (from == double.class) {
                 return (short) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? (short) 1 : (short) 0;
             } else {
                 throwUnexpectedType(from);
                 return 0;
@@ -1940,6 +1928,8 @@
                 return (int) reader.nextFloat();
             } else if (from == double.class) {
                 return (int) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? 1 : 0;
             } else {
                 throwUnexpectedType(from);
                 return 0;
@@ -1962,6 +1952,8 @@
                 return (long) reader.nextFloat();
             } else if (from == double.class) {
                 return (long) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? 1L : 0L;
             } else {
                 throwUnexpectedType(from);
                 return 0;
@@ -1984,6 +1976,8 @@
                 return (float) reader.nextFloat();
             } else if (from == double.class) {
                 return (float) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? 1.0f : 0.0f;
             } else {
                 throwUnexpectedType(from);
                 return 0;
@@ -2006,19 +2000,14 @@
                 return (double) reader.nextFloat();
             } else if (from == double.class) {
                 return (double) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? 1.0 : 0.0;
             } else {
                 throwUnexpectedType(from);
                 return 0;
             }
         }
 
-        private static void explicitCastToBoolean(final StackFrameReader reader,
-                                                  final Class<?> from,
-                                                  final StackFrameWriter writer) {
-            byte byteValue = readPrimitiveAsByte(reader, from);
-            writer.putNextBoolean(toBoolean(byteValue));
-        }
-
         private static void explicitCastPrimitives(final StackFrameReader reader,
                                                    final Class<?> from,
                                                    final StackFrameWriter writer,
@@ -2044,6 +2033,9 @@
             } else if (to == double.class) {
                 double value = readPrimitiveAsDouble(reader, from);
                 writer.putNextDouble(value);
+            } else if (to == boolean.class) {
+                byte byteValue = readPrimitiveAsByte(reader, from);
+                writer.putNextBoolean(toBoolean(byteValue));
             } else {
                 throwUnexpectedType(to);
             }
@@ -2073,32 +2065,176 @@
 
         private static void unboxNonNull(final Object ref, final Class<?> from,
                                          final StackFrameWriter writer, final Class<?> to) {
-            if (to == boolean.class) {
-                if (from == Boolean.class) {
-                    writer.putNextBoolean((boolean) ref);
-                } else if (from == Float.class || from == Double.class) {
-                    byte b = (byte) ((double) ref);
-                    writer.putNextBoolean(toBoolean(b));
+            if (from == Boolean.class) {
+                boolean z = (boolean) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean(z);
+                } else if (to == byte.class) {
+                    writer.putNextByte(z ? (byte) 1 : (byte) 0);
+                } else if (to == short.class) {
+                    writer.putNextShort(z ? (short) 1 : (short) 0);
+                } else if (to == char.class) {
+                    writer.putNextChar(z ? (char) 1 : (char) 0);
+                } else if (to == int.class) {
+                    writer.putNextInt(z ? 1 : 0);
+                } else if (to == long.class) {
+                    writer.putNextLong(z ? 1l : 0l);
+                } else if (to == float.class) {
+                    writer.putNextFloat(z ? 1.0f : 0.0f);
+                } else if (to == double.class) {
+                    writer.putNextDouble(z ? 1.0 : 0.0);
                 } else {
-                    byte b = (byte) ((long) ref);
-                    writer.putNextBoolean(toBoolean(b));
+                    badCast(from, to);
                 }
-            } else if (to == byte.class) {
-                writer.putNextByte((byte) ref);
-            } else if (to == char.class) {
-                writer.putNextChar((char) ref);
-            } else if (to == short.class) {
-                writer.putNextShort((short) ref);
-            } else if (to == int.class) {
-                writer.putNextInt((int) ref);
-            } else if (to == long.class) {
-                writer.putNextLong((long) ref);
-            } else if (to == float.class) {
-                writer.putNextFloat((float) ref);
-            } else if (to == double.class) {
-                writer.putNextDouble((double) ref);
+            } else if (from == Byte.class) {
+                byte b = (byte) ref;
+                if (to == byte.class) {
+                    writer.putNextByte(b);
+                } else if (to == boolean.class) {
+                    writer.putNextBoolean(toBoolean(b));
+                } else if (to == short.class) {
+                    writer.putNextShort((short) b);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) b);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) b);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) b);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) b);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) b);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Short.class) {
+                short s = (short) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean((s & 1) == 1);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) s);
+                } else if (to == short.class) {
+                    writer.putNextShort(s);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) s);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) s);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) s);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) s);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) s);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Character.class) {
+                char c = (char) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean((c & (char) 1) == (char) 1);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) c);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) c);
+                } else if (to == char.class) {
+                    writer.putNextChar(c);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) c);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) c);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) c);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) c);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Integer.class) {
+                int i = (int) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean((i & 1) == 1);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) i);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) i);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) i);
+                } else if (to == int.class) {
+                    writer.putNextInt(i);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) i);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) i);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) i);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Long.class) {
+                long j = (long) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean((j & 1l) == 1l);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) j);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) j);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) j);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) j);
+                } else if (to == long.class) {
+                    writer.putNextLong(j);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) j);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) j);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Float.class) {
+                float f = (float) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean(((byte) f & 1) != 0);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) f);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) f);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) f);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) f);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) f);
+                } else if (to == float.class) {
+                    writer.putNextFloat(f);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) f);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Double.class) {
+                double d = (double) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean(((byte) d & 1) != 0);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) d);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) d);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) d);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) d);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) d);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) d);
+                } else if (to == double.class) {
+                    writer.putNextDouble(d);
+                } else {
+                    badCast(from, to);
+                }
             } else {
-                throwUnexpectedType(to);
+                badCast(from, to);
             }
         }
 
@@ -2140,31 +2276,31 @@
                                          final StackFrameWriter writer, final Class<?> to) {
             if (from.equals(to)) {
                 StackFrameAccessor.copyNext(reader, writer, from);
-            } else if (!from.isPrimitive()) {
+                return;
+            }
+
+            if (from.isPrimitive()) {
+                if (to.isPrimitive()) {
+                    // |from| and |to| are primitive types.
+                    explicitCastPrimitives(reader, from, writer, to);
+                } else {
+                    // |from| is a primitive type, |to| is a reference type.
+                    box(reader, from, writer, to);
+                }
+            } else {
+                // |from| is a reference type.
                 Object ref = reader.nextReference(from);
-                if (to.isInterface()) {
+                if (to.isPrimitive()) {
+                    // |from| is a reference type, |to| is a primitive type,
+                    unbox(ref, from, writer, to);
+                } else if (to.isInterface()) {
                     // Pass from without a cast according to description for
                     // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}.
                     writer.putNextReference(ref, to);
-                } else if (!to.isPrimitive()) {
-                    // |to| is a reference type, perform class cast check.
+                } else {
+                    // |to| and from |from| are reference types, perform class cast check.
                     writer.putNextReference(to.cast(ref), to);
-                } else {
-                    // |from| is a reference type, |to| is a primitive type,
-                    unbox(ref, from, writer, to);
                 }
-            } else if (to.isPrimitive()) {
-                // |from| and |to| are primitive types.
-                if (from == boolean.class) {
-                    explicitCastFromBoolean(reader.nextBoolean(), writer, to);
-                } else if (to == boolean.class) {
-                    explicitCastToBoolean(reader, from, writer);
-                } else {
-                    explicitCastPrimitives(reader, from, writer, to);
-                }
-            } else {
-                // |from| is a primitive type, |to| is a reference type.
-                box(reader, from, writer, to);
             }
         }
     }
diff --git a/ojluni/src/main/java/java/lang/ref/Reference.java b/ojluni/src/main/java/java/lang/ref/Reference.java
index cf8c8b5..e5126b5 100644
--- a/ojluni/src/main/java/java/lang/ref/Reference.java
+++ b/ojluni/src/main/java/java/lang/ref/Reference.java
@@ -38,10 +38,11 @@
  * @author   Mark Reinhold
  * @since    1.2
  */
-// BEGIN Android-changed: Reimplemented to accommodate a different GC and compiler.
-// ClassLinker knows about the fields of this class.
 
 public abstract class Reference<T> {
+    // BEGIN Android-changed: Reimplemented to accommodate a different GC and compiler.
+    // ClassLinker knows about the fields of this class.
+
     /**
      * Forces JNI path.
      * If GC is not in progress (ie: not going through slow path), the referent
diff --git a/ojluni/src/main/java/java/lang/ref/TEST_MAPPING b/ojluni/src/main/java/java/lang/ref/TEST_MAPPING
new file mode 100644
index 0000000..c90a051
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/ref/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/luni/src/main/java/java/lang/ref"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/lang/reflect/Field.java b/ojluni/src/main/java/java/lang/reflect/Field.java
index 2bcf9e9..ca5857a 100644
--- a/ojluni/src/main/java/java/lang/reflect/Field.java
+++ b/ojluni/src/main/java/java/lang/reflect/Field.java
@@ -61,7 +61,7 @@
 
     private int accessFlags;
     private Class<?> declaringClass;
-    private int dexFieldIndex;
+    private int artFieldIndex;
     private int offset;
     private Class<?> type;
 
@@ -82,12 +82,17 @@
      */
     public String getName() {
         // Android-changed: getName() implemented differently.
-        if (dexFieldIndex == -1) {
+        if (declaringClass.isProxy()) {
             // Proxy classes have 1 synthesized static field with no valid dex index.
-            if (!declaringClass.isProxy()) {
-                throw new AssertionError();
+            if ((getModifiers() & Modifier.STATIC) == 0) {
+                throw new AssertionError("Invalid modifiers for proxy field: " + getModifiers());
             }
-            return "throws";
+            // Only 2 fields are present on proxy classes.
+            switch (artFieldIndex) {
+                case 0: return "interfaces";
+                case 1: return "throws";
+                default: throw new AssertionError("Invalid index for proxy: " + artFieldIndex);
+            }
         }
 
         return getNameInternal();
@@ -928,15 +933,6 @@
 
     // BEGIN Android-added: Methods for use by Android-specific code.
     /**
-     * Returns the index of this field's ID in its dex file.
-     *
-     * @hide
-     */
-    public int getDexFieldIndex() {
-        return dexFieldIndex;
-    }
-
-    /**
      * Returns the offset of the field within an instance, or for static fields, the class.
      *
      * @hide
diff --git a/ojluni/src/main/java/java/lang/reflect/TEST_MAPPING b/ojluni/src/main/java/java/lang/reflect/TEST_MAPPING
new file mode 100644
index 0000000..2d13e0a
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/reflect/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.lang.reflect"
+        },
+        {
+          "include-filter": "libcore.java.lang.reflect.annotations"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.lang.reflect"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/net/Inet6AddressImpl.java b/ojluni/src/main/java/java/net/Inet6AddressImpl.java
index bb722f3..84bcf17 100644
--- a/ojluni/src/main/java/java/net/Inet6AddressImpl.java
+++ b/ojluni/src/main/java/java/net/Inet6AddressImpl.java
@@ -27,7 +27,7 @@
 import android.system.ErrnoException;
 import android.system.GaiException;
 import android.system.StructAddrinfo;
-import android.system.StructIcmpHdr;
+import android.system.IcmpHeaders;
 
 import dalvik.system.BlockGuard;
 
@@ -258,12 +258,12 @@
             byte[] packet;
 
             // ICMP is unreliable, try sending requests every second until timeout.
-            for (int to = timeout, seq = 0; to > 0; ++seq) {
+            for (int to = timeout, seq = 1; to > 0; ++seq) {
                 int sockTo = to >= 1000 ? 1000 : to;
 
                 IoBridge.setSocketOption(fd, SocketOptions.SO_TIMEOUT, sockTo);
 
-                packet = StructIcmpHdr.IcmpEchoHdr(isIPv4, seq).getBytes();
+                packet = IcmpHeaders.createIcmpEchoHdr(isIPv4, seq);
                 IoBridge.sendto(fd, packet, 0, packet.length, 0, addr, 0);
                 final int icmpId = IoBridge.getLocalInetSocketAddress(fd).getPort();
 
@@ -277,11 +277,11 @@
                     if (receivedPacket.getAddress().equals(addr)
                             && received[0] == expectedType
                             && received[4] == (byte) (icmpId >> 8)
-                            && received[5] == (byte) icmpId
-                            && received[6] == (byte) (seq >> 8)
-                            && received[7] == (byte) seq) {
-                        // This is the packet we're expecting.
-                        return true;
+                            && received[5] == (byte) icmpId) {
+                        int receivedSequence = ((received[6] & 0xff) << 8) + (received[7] & 0xff);
+                        if (receivedSequence <= seq) {
+                            return true;
+                        }
                     }
                 }
                 to -= sockTo;
diff --git a/ojluni/src/main/java/java/net/NetworkInterface.java b/ojluni/src/main/java/java/net/NetworkInterface.java
index 673a1d2..a30b6bf 100644
--- a/ojluni/src/main/java/java/net/NetworkInterface.java
+++ b/ojluni/src/main/java/java/net/NetworkInterface.java
@@ -47,6 +47,7 @@
 
 // Android-note: NetworkInterface has been rewritten to avoid native code.
 // Fix upstream bug not returning link-down interfaces. http://b/26238832
+// Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
 /**
  * This class represents a Network Interface made up of a name,
  * and a list of IP addresses assigned to this interface.
@@ -54,6 +55,12 @@
  * is joined.
  *
  * Interfaces are normally known by names such as "le0".
+ * <p>
+ * <a name="access-restrictions"></a>Note that information about
+ * {@link NetworkInterface}s may be restricted. For example, non-system apps
+ * with {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R} will only
+ * have access to information about {@link NetworkInterface}s that are
+ * associated with an {@link InetAddress}.
  *
  * @since 1.4
  */
@@ -265,6 +272,7 @@
         return "".equals(displayName) ? null : displayName;
     }
 
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
     /**
      * Searches for the network interface with the specified name.
      *
@@ -272,8 +280,9 @@
      *          The name of the network interface.
      *
      * @return  A {@code NetworkInterface} with the specified name,
-     *          or {@code null} if there is no network interface
-     *          with the specified name.
+     *          or {@code null} if the network interface with the specified
+     *          name does not exist or <a href="#access-restrictions">can't be
+     *          accessed</a>.
      *
      * @throws  SocketException
      *          If an I/O error occurs.
@@ -295,12 +304,14 @@
         return null;
     }
 
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
     /**
      * Get a network interface given its index.
      *
      * @param index an integer, the index of the interface
      * @return the NetworkInterface obtained from its index, or {@code null} if
-     *         there is no interface with such an index on the system
+     *         an interface with the specified index does not exist or
+     *         <a href="#access-restrictions">can't be accessed</a>.
      * @throws  SocketException  if an I/O error occurs.
      * @throws  IllegalArgumentException if index has a negative value
      * @see #getIndex()
@@ -362,6 +373,7 @@
         return null;
     }
 
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
     /**
      * Returns all the interfaces on this machine. The {@code Enumeration}
      * contains at least one element, possibly representing a loopback
@@ -370,20 +382,44 @@
      *
      * NOTE: can use getNetworkInterfaces()+getInetAddresses()
      *       to obtain all IP addresses for this node
+     * <p>
+     * For non-system apps with
+     * {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R}, this
+     * method will only return information for {@link NetworkInterface}s that
+     * are associated with an {@link InetAddress}.
      *
      * @return an Enumeration of NetworkInterfaces found on this machine
+     *         that <a href="#access-restrictions">are accessible</a>.
      * @exception  SocketException  if an I/O error occurs.
      */
 
     public static Enumeration<NetworkInterface> getNetworkInterfaces()
         throws SocketException {
         final NetworkInterface[] netifs = getAll();
-
         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
-        // specified to return null if no network interfaces
+        // // specified to return null if no network interfaces
+        // if (netifs == null)
         if (netifs.length == 0)
             return null;
 
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        /*
+        return new Enumeration<NetworkInterface>() {
+            private int i = 0;
+            public NetworkInterface nextElement() {
+                if (netifs != null && i < netifs.length) {
+                    NetworkInterface netif = netifs[i++];
+                    return netif;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            public boolean hasMoreElements() {
+                return (netifs != null && i < netifs.length);
+            }
+        };
+        */
         return Collections.enumeration(Arrays.asList(netifs));
     }
 
@@ -523,6 +559,7 @@
         return (getFlags() & IFF_MULTICAST) != 0;
     }
 
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
     /**
      * Returns the hardware address (usually MAC) of the interface if it
      * has one and if it can be accessed given the current privileges.
@@ -532,7 +569,10 @@
      * @return  a byte array containing the address, or {@code null} if
      *          the address doesn't exist, is not accessible or a security
      *          manager is set and the caller does not have the permission
-     *          NetPermission("getNetworkInformation")
+     *          NetPermission("getNetworkInformation"). For example, this
+     *          method will generally return {@code null} when called by
+     *          non-system apps having
+     *          {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R}.
      *
      * @exception       SocketException if an I/O error occurs.
      * @since 1.6
diff --git a/ojluni/src/main/java/java/net/ServerSocket.java b/ojluni/src/main/java/java/net/ServerSocket.java
index bb495e6..444a84d 100644
--- a/ojluni/src/main/java/java/net/ServerSocket.java
+++ b/ojluni/src/main/java/java/net/ServerSocket.java
@@ -244,6 +244,7 @@
         }
     }
 
+    // Android-changed: Made getImpl() public and @hide, for internal use.
     /**
      * Get the {@code SocketImpl} attached to this socket, creating
      * it if necessary.
@@ -253,7 +254,6 @@
      * @since 1.4
      * @hide
      */
-    // Android-changed: Make ctor public and @hide, for internal use.
     public SocketImpl getImpl() throws SocketException {
         if (!created)
             createImpl();
diff --git a/ojluni/src/main/java/java/net/Socket.java b/ojluni/src/main/java/java/net/Socket.java
index e36d15b..bae1d1c 100644
--- a/ojluni/src/main/java/java/net/Socket.java
+++ b/ojluni/src/main/java/java/net/Socket.java
@@ -139,7 +139,7 @@
                     security.checkConnect(epoint.getAddress().getHostAddress(),
                                   epoint.getPort());
             }
-            // Android-changed: Removed HTTP proxy suppport.
+            // Android-changed: Removed HTTP proxy support.
             // impl = type == Proxy.Type.SOCKS ? new SocksSocketImpl(p)
             //                                : new HttpConnectSocketImpl(p);
             impl = new SocksSocketImpl(p);
diff --git a/ojluni/src/main/java/java/net/TEST_MAPPING b/ojluni/src/main/java/java/net/TEST_MAPPING
new file mode 100644
index 0000000..9149b15
--- /dev/null
+++ b/ojluni/src/main/java/java/net/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/luni/src/main/java/java/net"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/net/URI.java b/ojluni/src/main/java/java/net/URI.java
index f5a5112..ebba41b 100644
--- a/ojluni/src/main/java/java/net/URI.java
+++ b/ojluni/src/main/java/java/net/URI.java
@@ -44,6 +44,7 @@
 import java.lang.NullPointerException;  // for javadoc
 
 
+// Android-changed: Reformat @see links.
 /**
  * Represents a Uniform Resource Identifier (URI) reference.
  *
@@ -455,7 +456,7 @@
  * @see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396: Uniform Resource Identifiers (URI): Generic Syntax</a>
  * @see <a href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732: Format for Literal IPv6 Addresses in URLs</a>
  */
-// Android-changed: Reformat @see links.
+
 public final class URI
     implements Comparable<URI>, Serializable
 {
diff --git a/ojluni/src/main/java/java/net/URLConnection.java b/ojluni/src/main/java/java/net/URLConnection.java
index 1de7b3c..55ec26d 100644
--- a/ojluni/src/main/java/java/net/URLConnection.java
+++ b/ojluni/src/main/java/java/net/URLConnection.java
@@ -288,13 +288,13 @@
     */
     private static FileNameMap fileNameMap;
 
-    // BEGIN Android-removed: Android has its own mime table.
+    // BEGIN Android-changed: Android has its own mime table.
     /*
+    /**
      * @since 1.2.2
      *
     private static boolean fileNameMapLoaded = false;
-    */
-    // END Android-removed: Android has its own mime table.
+
     /**
      * Loads filename map (a mimetable) from a data file. It will
      * first try to load the user-specific table, defined
@@ -304,14 +304,36 @@
      * @return the FileNameMap
      * @since 1.2
      * @see #setFileNameMap(java.net.FileNameMap)
+     *
+    public static synchronized FileNameMap getFileNameMap() {
+        if ((fileNameMap == null) && !fileNameMapLoaded) {
+            fileNameMap = sun.net.www.MimeTable.loadTable();
+            fileNameMapLoaded = true;
+        }
+
+        return new FileNameMap() {
+            private FileNameMap map = fileNameMap;
+            public String getContentTypeFor(String fileName) {
+                return map.getContentTypeFor(fileName);
+            }
+        };
+    }
+    */
+    /**
+     * Returns a {@link FileNameMap} implementation suitable for guessing a
+     * content type based on a URL's "file" component.
+     *
+     * @see #guessContentTypeFromName(String)
+     * @see #setFileNameMap(java.net.FileNameMap)
+     *
      */
     public static synchronized FileNameMap getFileNameMap() {
-        // Android-changed: Android has its own mime table.
         if (fileNameMap == null) {
             fileNameMap = new DefaultFileNameMap();
         }
         return fileNameMap;
     }
+    // END Android-changed: Android has its own mime table.
 
     /**
      * Sets the FileNameMap.
diff --git a/ojluni/src/main/java/java/nio/TEST_MAPPING b/ojluni/src/main/java/java/nio/TEST_MAPPING
new file mode 100644
index 0000000..8a8180b
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/luni/src/main/java/java/nio"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/nio/channels/TEST_MAPPING b/ojluni/src/main/java/java/nio/channels/TEST_MAPPING
new file mode 100644
index 0000000..dfb741c
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.nio.channels"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.nio.channels"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/nio/channels/spi/TEST_MAPPING b/ojluni/src/main/java/java/nio/channels/spi/TEST_MAPPING
new file mode 100644
index 0000000..7974b9a
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/spi/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.nio.channels.spi"
+        },
+        {
+          "include-filter": "org.apache.harmony.nio.tests.java.nio.channels.spi"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.nio.channels.spi"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/nio/charset/Charset.java b/ojluni/src/main/java/java/nio/charset/Charset.java
index 31543f0..5a3b35a 100755
--- a/ojluni/src/main/java/java/nio/charset/Charset.java
+++ b/ojluni/src/main/java/java/nio/charset/Charset.java
@@ -26,13 +26,12 @@
 
 package java.nio.charset;
 
+import com.android.icu.charset.CharsetICU;
 import java.io.UnsupportedEncodingException;
-import libcore.icu.NativeConverter;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.spi.CharsetProvider;
 import java.security.AccessController;
-import java.security.AccessControlException;
 import java.security.PrivilegedAction;
 import java.util.AbstractMap;
 import java.util.Collections;
@@ -52,6 +51,7 @@
 import sun.security.action.GetPropertyAction;
 
 
+// Android-changed: Docs to say UTF-8 is always the platform default charset.
 /**
  * A named mapping between sequences of sixteen-bit Unicode <a
  * href="../../lang/Character.html#unicode">code units</a> and sequences of
@@ -318,8 +318,8 @@
         }
     }
 
-    /* The standard set of charsets */
     // Android-removed: We use ICU's list of standard charsets.
+    /* The standard set of charsets */
     // private static CharsetProvider standardProvider = new StandardCharsets();
 
     // Cache of the most-recently-returned charsets,
@@ -508,7 +508,7 @@
 
         // Android-changed: Drop support for "standard" and "extended"
         // providers.
-        if ((cs = NativeConverter.charsetForName(charsetName))  != null ||
+        if ((cs = CharsetICU.charsetForName(charsetName))  != null ||
             (cs = lookupViaProviders(charsetName))              != null)
         {
             cache(charsetName, cs);
@@ -566,7 +566,7 @@
         throw new UnsupportedCharsetException(charsetName);
     }
 
-
+    // BEGIN Android-added: forNameUEE(String) method.
     /**
      * Equivalent to {@code forName} but only throws {@code UnsupportedEncodingException},
      * which is all pre-nio code claims to throw.
@@ -582,7 +582,7 @@
             throw ex;
         }
     }
-
+    // END Android-added: forNameUEE(String) method.
 
     // Fold charsets from the given iterator into the given map, ignoring
     // charsets whose names already have entries in the map.
@@ -628,8 +628,8 @@
                     TreeMap<String,Charset> m =
                         new TreeMap<String,Charset>(
                             ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
-                    for (String charsetName : NativeConverter.getAvailableCharsetNames()) {
-                        Charset charset = NativeConverter.charsetForName(charsetName);
+                    for (String charsetName : CharsetICU.getAvailableCharsetNames()) {
+                        Charset charset = CharsetICU.charsetForName(charsetName);
                         m.put(charset.name(), charset);
                     }
                     // Android-changed: No more "standard" provider.
@@ -685,6 +685,7 @@
      * @throws IllegalCharsetNameException
      *         If the canonical name or any of the aliases are illegal
      */
+    @libcore.api.IntraCoreApi
     protected Charset(String canonicalName, String[] aliases) {
         checkName(canonicalName);
         String[] as = (aliases == null) ? new String[0] : aliases;
diff --git a/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java b/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
index 540199e..98b4dea 100644
--- a/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
+++ b/ojluni/src/main/java/java/nio/charset/CharsetEncoder.java
@@ -197,8 +197,9 @@
      * This constructor is for subclasses to specify whether {@code replacement} can be used as it
      * is ("trusted"). If it is trusted, {@link #replaceWith(byte[])} and
      * {@link #implReplaceWith(byte[])} will not be called.
+     * @hide
      */
-    CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement,
+    protected CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement,
             boolean trusted)
     {
         // END Android-added: A hidden constructor for the CharsetEncoderICU subclass.
diff --git a/ojluni/src/main/java/java/nio/charset/TEST_MAPPING b/ojluni/src/main/java/java/nio/charset/TEST_MAPPING
new file mode 100644
index 0000000..5fa13f1
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/charset/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "libcore/luni/src/main/java/java/nio/charset"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/nio/file/TEST_MAPPING b/ojluni/src/main/java/java/nio/file/TEST_MAPPING
new file mode 100644
index 0000000..24bd29a
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/file/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.nio.file"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/nio/file/attribute/TEST_MAPPING b/ojluni/src/main/java/java/nio/file/attribute/TEST_MAPPING
new file mode 100644
index 0000000..b6c90d4
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/file/attribute/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.nio.file.attribute"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "test.java.nio.file.attribute"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/nio/file/spi/TEST_MAPPING b/ojluni/src/main/java/java/nio/file/spi/TEST_MAPPING
new file mode 100644
index 0000000..632f30c
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/file/spi/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.nio.file.spi"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/security/AlgorithmParameterGenerator.java b/ojluni/src/main/java/java/security/AlgorithmParameterGenerator.java
index 4cab0c3..7222b44 100644
--- a/ojluni/src/main/java/java/security/AlgorithmParameterGenerator.java
+++ b/ojluni/src/main/java/java/security/AlgorithmParameterGenerator.java
@@ -99,7 +99,7 @@
  * </table>
  *
  * These algorithms are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
  * AlgorithmParameterGenerator section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -164,7 +164,7 @@
      * @param algorithm the name of the algorithm this
      * parameter generator is associated with.
      * See the AlgorithmParameterGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -206,7 +206,7 @@
      * @param algorithm the name of the algorithm this
      * parameter generator is associated with.
      * See the AlgorithmParameterGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -252,7 +252,7 @@
      * @param algorithm the string name of the algorithm this
      * parameter generator is associated with.
      * See the AlgorithmParameterGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/AlgorithmParameters.java b/ojluni/src/main/java/java/security/AlgorithmParameters.java
index 989159e..fd1966f1 100644
--- a/ojluni/src/main/java/java/security/AlgorithmParameters.java
+++ b/ojluni/src/main/java/java/security/AlgorithmParameters.java
@@ -153,7 +153,7 @@
  * </table>
  *
  * These algorithms are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#AlgorithmParameters">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameters">
  * AlgorithmParameters section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -223,7 +223,7 @@
      *
      * @param algorithm the name of the algorithm requested.
      * See the AlgorithmParameters section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#AlgorithmParameters">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameters">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -265,7 +265,7 @@
      *
      * @param algorithm the name of the algorithm requested.
      * See the AlgorithmParameters section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#AlgorithmParameters">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameters">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -314,7 +314,7 @@
      *
      * @param algorithm the name of the algorithm requested.
      * See the AlgorithmParameters section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#AlgorithmParameters">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameters">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/Key.java b/ojluni/src/main/java/java/security/Key.java
index 37f4c84..c0c63d7 100644
--- a/ojluni/src/main/java/java/security/Key.java
+++ b/ojluni/src/main/java/java/security/Key.java
@@ -82,7 +82,7 @@
  * <p> A Key should use KeyRep as its serialized representation.
  * Note that a serialized Key may contain sensitive information
  * which should not be exposed in untrusted environments.  See the
- * <a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/security.html">
+ * <a href="../../../platform/serialization/spec/security.html">
  * Security Appendix</a>
  * of the Serialization Specification for more information.
  *
@@ -114,7 +114,7 @@
      * Returns the standard algorithm name for this key. For
      * example, "DSA" would indicate that this key is a DSA key.
      * See Appendix A in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      * Java Cryptography Architecture API Specification &amp; Reference </a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/KeyFactory.java b/ojluni/src/main/java/java/security/KeyFactory.java
index f687d61..716f62d 100644
--- a/ojluni/src/main/java/java/security/KeyFactory.java
+++ b/ojluni/src/main/java/java/security/KeyFactory.java
@@ -100,7 +100,7 @@
  * </table>
  *
  * These algorithms are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyFactory">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
  * KeyFactory section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -178,7 +178,7 @@
      *
      * @param algorithm the name of the requested key algorithm.
      * See the KeyFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -209,7 +209,7 @@
      *
      * @param algorithm the name of the requested key algorithm.
      * See the KeyFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -250,7 +250,7 @@
      *
      * @param algorithm the name of the requested key algorithm.
      * See the KeyFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/KeyPairGenerator.java b/ojluni/src/main/java/java/security/KeyPairGenerator.java
index 1c4c2cb..7c6cdb5 100644
--- a/ojluni/src/main/java/java/security/KeyPairGenerator.java
+++ b/ojluni/src/main/java/java/security/KeyPairGenerator.java
@@ -133,7 +133,7 @@
  * </table>
  *
  * These algorithms are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
  * KeyPairGenerator section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -162,7 +162,7 @@
      *
      * @param algorithm the standard string name of the algorithm.
      * See the KeyPairGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      */
@@ -173,7 +173,7 @@
     /**
      * Returns the standard name of the algorithm for this key pair generator.
      * See the KeyPairGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -220,7 +220,7 @@
      *
      * @param algorithm the standard string name of the algorithm.
      * See the KeyPairGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -276,7 +276,7 @@
      *
      * @param algorithm the standard string name of the algorithm.
      * See the KeyPairGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -317,7 +317,7 @@
      *
      * @param algorithm the standard string name of the algorithm.
      * See the KeyPairGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/KeyRep.java b/ojluni/src/main/java/java/security/KeyRep.java
index cae4c63..0b1412c 100644
--- a/ojluni/src/main/java/java/security/KeyRep.java
+++ b/ojluni/src/main/java/java/security/KeyRep.java
@@ -42,7 +42,7 @@
  *
  * Note that a serialized Key may contain sensitive information
  * which should not be exposed in untrusted environments.  See the
- * <a href="https://docs.oracle.com/javase/8/docs/platform/serialization/spec/security.html">
+ * <a href="../../../platform/serialization/spec/security.html">
  * Security Appendix</a>
  * of the Serialization Specification for more information.
  *
diff --git a/ojluni/src/main/java/java/security/KeyStore.java b/ojluni/src/main/java/java/security/KeyStore.java
index 924f14f..7781649 100644
--- a/ojluni/src/main/java/java/security/KeyStore.java
+++ b/ojluni/src/main/java/java/security/KeyStore.java
@@ -195,7 +195,7 @@
  * </table>
  *
  * These types are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyStore">
  * KeyStore section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -311,7 +311,7 @@
          * @param protectionAlgorithm the encryption algorithm name, for
          *     example, {@code PBEWithHmacSHA256AndAES_256}.
          *     See the Cipher section in the <a href=
-         * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
+         * "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
          * Java Cryptography Architecture Standard Algorithm Name
          * Documentation</a>
          *     for information about standard encryption algorithm names.
@@ -868,7 +868,7 @@
      *
      * @param type the type of keystore.
      * See the KeyStore section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyStore">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard keystore types.
      *
@@ -906,7 +906,7 @@
      *
      * @param type the type of keystore.
      * See the KeyStore section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyStore">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard keystore types.
      *
@@ -949,7 +949,7 @@
      *
      * @param type the type of keystore.
      * See the KeyStore section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyStore">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyStore">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard keystore types.
      *
diff --git a/ojluni/src/main/java/java/security/MessageDigest.java b/ojluni/src/main/java/java/security/MessageDigest.java
index 996339e..5b9359f 100644
--- a/ojluni/src/main/java/java/security/MessageDigest.java
+++ b/ojluni/src/main/java/java/security/MessageDigest.java
@@ -120,7 +120,7 @@
  * </table>
  *
  * These algorithms are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
  * MessageDigest section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -155,7 +155,7 @@
      *
      * @param algorithm the standard name of the digest algorithm.
      * See the MessageDigest section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      */
@@ -178,7 +178,7 @@
      *
      * @param algorithm the name of the algorithm requested.
      * See the MessageDigest section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -232,7 +232,7 @@
      *
      * @param algorithm the name of the algorithm requested.
      * See the MessageDigest section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -283,7 +283,7 @@
      *
      * @param algorithm the name of the algorithm requested.
      * See the MessageDigest section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -511,7 +511,7 @@
      * implementation details. The name should be a standard
      * Java Security name (such as "SHA", "MD5", and so on).
      * See the MessageDigest section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index 43bb23f..9936859 100644
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -57,7 +57,7 @@
  * in each runtime it is installed in.
  *
  * <p>See <a href =
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
+ * "../../../technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
  * in the "Java Cryptography Architecture API Specification &amp; Reference"
  * for information about how a particular type of provider, the
  * cryptographic service provider, works and is installed. However,
@@ -1125,7 +1125,7 @@
      * it is replaced by the new service.
      * This method also places information about this service
      * in the provider's Hashtable values in the format described in the
-     * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+     * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
      * Java Cryptography Architecture API Specification &amp; Reference </a>.
      *
      * <p>Also, if there is a security manager, its
@@ -1415,7 +1415,7 @@
      * suitable services and instantiates them. The valid arguments to those
      * methods depend on the type of service. For the service types defined
      * within Java SE, see the
-     * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+     * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
      * Java Cryptography Architecture API Specification &amp; Reference </a>
      * for the valid values.
      * Note that components outside of Java SE can define additional types of
@@ -1591,7 +1591,7 @@
          * instantiation in a different way.
          * For details and the values of constructorParameter that are
          * valid for the various types of services see the
-         * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+         * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
          * Java Cryptography Architecture API Specification &amp;
          * Reference</a>.
          *
@@ -1740,7 +1740,7 @@
          *
          * <p>For details and the values of parameter that are valid for the
          * various types of services see the top of this class and the
-         * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+         * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
          * Java Cryptography Architecture API Specification &amp;
          * Reference</a>.
          * Security providers can override it to implement their own test.
diff --git a/ojluni/src/main/java/java/security/SecureRandom.java b/ojluni/src/main/java/java/security/SecureRandom.java
index 4da178d..79e3840 100644
--- a/ojluni/src/main/java/java/security/SecureRandom.java
+++ b/ojluni/src/main/java/java/security/SecureRandom.java
@@ -151,7 +151,7 @@
      * the {@link Security#getProviders() Security.getProviders()} method.
      *
      * <p> See the SecureRandom section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecureRandom">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard RNG algorithm names.
      *
@@ -189,7 +189,7 @@
      * the {@link Security#getProviders() Security.getProviders()} method.
      *
      * <p> See the SecureRandom section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecureRandom">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard RNG algorithm names.
      *
@@ -278,7 +278,7 @@
      *
      * @param algorithm the name of the RNG algorithm.
      * See the SecureRandom section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecureRandom">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard RNG algorithm names.
      *
@@ -321,7 +321,7 @@
      *
      * @param algorithm the name of the RNG algorithm.
      * See the SecureRandom section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecureRandom">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard RNG algorithm names.
      *
@@ -369,7 +369,7 @@
      *
      * @param algorithm the name of the RNG algorithm.
      * See the SecureRandom section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecureRandom">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard RNG algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/Security.java b/ojluni/src/main/java/java/security/Security.java
index fda137e..bb853a6 100644
--- a/ojluni/src/main/java/java/security/Security.java
+++ b/ojluni/src/main/java/java/security/Security.java
@@ -207,7 +207,7 @@
     /**
      * Gets a specified property for an algorithm. The algorithm name
      * should be a standard name. See the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -443,7 +443,7 @@
      * </ul>
      *
      * <p> See the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard cryptographic service names, standard
      * algorithm names and standard attribute names.
@@ -514,7 +514,7 @@
      * </ul>
      *
      * <p> See the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">
+     * "../../../technotes/guides/security/StandardNames.html">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard cryptographic service names, standard
      * algorithm names and standard attribute names.
@@ -1016,7 +1016,7 @@
      * an empty Set if there is no provider that supports the
      * specified service or if serviceName is null. For a complete list
      * of Java cryptographic services, please see the
-     * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">Java
+     * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
      * Cryptography Architecture API Specification &amp; Reference</a>.
      * Note: the returned set is immutable.
      *
diff --git a/ojluni/src/main/java/java/security/Signature.java b/ojluni/src/main/java/java/security/Signature.java
index a09409f..bbe9640 100644
--- a/ojluni/src/main/java/java/security/Signature.java
+++ b/ojluni/src/main/java/java/security/Signature.java
@@ -238,7 +238,7 @@
  * </table>
  *
  * These algorithms are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Signature">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
  * Signature section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -298,7 +298,7 @@
      *
      * @param algorithm the standard string name of the algorithm.
      * See the Signature section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Signature">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      */
@@ -338,7 +338,7 @@
      *
      * @param algorithm the standard name of the algorithm requested.
      * See the Signature section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Signature">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -464,7 +464,7 @@
      *
      * @param algorithm the name of the algorithm requested.
      * See the Signature section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Signature">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -516,7 +516,7 @@
      *
      * @param algorithm the name of the algorithm requested.
      * See the Signature section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Signature">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/TEST_MAPPING b/ojluni/src/main/java/java/security/TEST_MAPPING
new file mode 100644
index 0000000..53b2818
--- /dev/null
+++ b/ojluni/src/main/java/java/security/TEST_MAPPING
@@ -0,0 +1,30 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.javax.security"
+        },
+        {
+          "include-filter": "org.apache.harmony.security.tests.java.security"
+        },
+        {
+          "include-filter": "tests.targets.security"
+        },
+        {
+          "include-filter": "com.android.org.conscrypt.java.security"
+        },
+        {
+          "include-filter": "tests.java.security"
+        },
+        {
+          "include-filter": "tests.security"
+        },
+        {
+          "include-filter": "libcore.java.security"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/security/acl/TEST_MAPPING b/ojluni/src/main/java/java/security/acl/TEST_MAPPING
new file mode 100644
index 0000000..864ca28
--- /dev/null
+++ b/ojluni/src/main/java/java/security/acl/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "tests.security.acl"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/security/cert/CRL.java b/ojluni/src/main/java/java/security/cert/CRL.java
index 67ea6ef..f8083c7 100644
--- a/ojluni/src/main/java/java/security/cert/CRL.java
+++ b/ojluni/src/main/java/java/security/cert/CRL.java
@@ -53,7 +53,7 @@
      *
      * @param type the standard name of the CRL type.
      * See Appendix A in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * "../../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      * Java Cryptography Architecture API Specification &amp; Reference </a>
      * for information about standard CRL types.
      */
diff --git a/ojluni/src/main/java/java/security/cert/CertPath.java b/ojluni/src/main/java/java/security/cert/CertPath.java
index fa88c39..8717f94 100644
--- a/ojluni/src/main/java/java/security/cert/CertPath.java
+++ b/ojluni/src/main/java/java/security/cert/CertPath.java
@@ -91,7 +91,7 @@
  * <li>{@code PkiPath}</li>
  * </ul>
  * These encodings are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathEncodings">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
  * CertPath Encodings section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  * Consult the release documentation for your implementation to see if any
diff --git a/ojluni/src/main/java/java/security/cert/CertPathBuilder.java b/ojluni/src/main/java/java/security/cert/CertPathBuilder.java
index 2d54292..891d86c 100644
--- a/ojluni/src/main/java/java/security/cert/CertPathBuilder.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathBuilder.java
@@ -83,7 +83,7 @@
  * </table>
  *
  * This algorithm is described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathBuilder">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
  * CertPathBuilder section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  * Consult the release documentation for your implementation to see if any
@@ -155,7 +155,7 @@
      *
      * @param algorithm the name of the requested {@code CertPathBuilder}
      *  algorithm.  See the CertPathBuilder section in the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathBuilder">
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -190,7 +190,7 @@
      *
      * @param algorithm the name of the requested {@code CertPathBuilder}
      *  algorithm.  See the CertPathBuilder section in the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathBuilder">
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -230,7 +230,7 @@
      *
      * @param algorithm the name of the requested {@code CertPathBuilder}
      *  algorithm.  See the CertPathBuilder section in the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathBuilder">
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/cert/CertPathValidator.java b/ojluni/src/main/java/java/security/cert/CertPathValidator.java
index bcb3488..942c5fa 100644
--- a/ojluni/src/main/java/java/security/cert/CertPathValidator.java
+++ b/ojluni/src/main/java/java/security/cert/CertPathValidator.java
@@ -85,7 +85,7 @@
  * </table>
  *
  * This algorithm is described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathValidator">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
  * CertPathValidator section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -154,7 +154,7 @@
      *
      * @param algorithm the name of the requested {@code CertPathValidator}
      *  algorithm. See the CertPathValidator section in the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathValidator">
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -189,7 +189,7 @@
      *
      * @param algorithm the name of the requested {@code CertPathValidator}
      *  algorithm. See the CertPathValidator section in the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathValidator">
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -230,7 +230,7 @@
      *
      * @param algorithm the name of the requested {@code CertPathValidator}
      * algorithm. See the CertPathValidator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathValidator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/java/security/cert/CertStore.java b/ojluni/src/main/java/java/security/cert/CertStore.java
index 7cfd0d2..6eaee5c 100644
--- a/ojluni/src/main/java/java/security/cert/CertStore.java
+++ b/ojluni/src/main/java/java/security/cert/CertStore.java
@@ -77,7 +77,7 @@
  * </table>
  *
  * This type is described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertStore">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertStore">
  * CertStore section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -212,7 +212,7 @@
      *
      * @param type the name of the requested {@code CertStore} type.
      * See the CertStore section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertStore">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertStore">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard types.
      *
@@ -272,7 +272,7 @@
      *
      * @param type the requested {@code CertStore} type.
      * See the CertStore section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertStore">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertStore">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard types.
      *
@@ -330,7 +330,7 @@
      *
      * @param type the requested {@code CertStore} type.
      * See the CertStore section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertStore">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertStore">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard types.
      *
diff --git a/ojluni/src/main/java/java/security/cert/Certificate.java b/ojluni/src/main/java/java/security/cert/Certificate.java
index 4056416..1054498 100644
--- a/ojluni/src/main/java/java/security/cert/Certificate.java
+++ b/ojluni/src/main/java/java/security/cert/Certificate.java
@@ -74,7 +74,7 @@
      *
      * @param type the standard name of the certificate type.
      * See the CertificateFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertificateFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard certificate types.
      */
diff --git a/ojluni/src/main/java/java/security/cert/CertificateFactory.java b/ojluni/src/main/java/java/security/cert/CertificateFactory.java
index e34fddd..a47b788 100644
--- a/ojluni/src/main/java/java/security/cert/CertificateFactory.java
+++ b/ojluni/src/main/java/java/security/cert/CertificateFactory.java
@@ -127,9 +127,9 @@
  * </table>
  *
  * The type and encodings are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertificateFactory">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
  * CertificateFactory section</a> and the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathEncodings">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
  * CertPath Encodings section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -188,7 +188,7 @@
      *
      * @param type the name of the requested certificate type.
      * See the CertificateFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertificateFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard certificate types.
      *
@@ -226,7 +226,7 @@
      *
      * @param type the certificate type.
      * See the CertificateFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertificateFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard certificate types.
      *
@@ -272,7 +272,7 @@
      *
      * @param type the certificate type.
      * See the CertificateFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertificateFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard certificate types.
      * @param provider the provider.
@@ -370,7 +370,7 @@
      * Returns an iteration of the {@code CertPath} encodings supported
      * by this certificate factory, with the default encoding first. See
      * the CertPath Encodings section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathEncodings">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard encoding names and their formats.
      * <p>
@@ -410,7 +410,7 @@
      * the data read from the {@code InputStream} inStream. The data
      * is assumed to be in the specified encoding. See
      * the CertPath Encodings section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathEncodings">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard encoding names and their formats.
      *
diff --git a/ojluni/src/main/java/java/security/cert/CertificateFactorySpi.java b/ojluni/src/main/java/java/security/cert/CertificateFactorySpi.java
index 691777d..35aee84 100644
--- a/ojluni/src/main/java/java/security/cert/CertificateFactorySpi.java
+++ b/ojluni/src/main/java/java/security/cert/CertificateFactorySpi.java
@@ -183,7 +183,7 @@
      * Returns an iteration of the {@code CertPath} encodings supported
      * by this certificate factory, with the default encoding first. See
      * the CertPath Encodings section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#CertPathEncodings">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard encoding names.
      * <p>
diff --git a/ojluni/src/main/java/java/security/cert/TEST_MAPPING b/ojluni/src/main/java/java/security/cert/TEST_MAPPING
new file mode 100644
index 0000000..267b914
--- /dev/null
+++ b/ojluni/src/main/java/java/security/cert/TEST_MAPPING
@@ -0,0 +1,29 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "tests.security.cert"
+        },
+        {
+          "include-filter": "tests.targets.security.cert"
+        },
+        {
+          "include-filter": "com.android.org.conscrypt.java.security.cert"
+        },
+        {
+          "include-filter": "libcore.java.security.cert"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "test.java.security.cert"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/security/cert/package-info.java b/ojluni/src/main/java/java/security/cert/package-info.java
index 4830455..58f5fb7 100644
--- a/ojluni/src/main/java/java/security/cert/package-info.java
+++ b/ojluni/src/main/java/java/security/cert/package-info.java
@@ -32,14 +32,14 @@
  * <h2>Package Specification</h2>
  *
  * <ul>
- *   <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+ *   <li><a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
  *     <b>Java&trade;
  *     Cryptography Architecture (JCA) Reference Guide</b></a>
  *   <li>RFC 5280: Internet X.509 Public Key Infrastructure Certificate and
  *     Certificate Revocation List (CRL) Profile
  *   <li>RFC 2560: X.509 Internet Public Key Infrastructure Online Certificate
  *     Status Protocol - OCSP
- *   <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">
+ *   <li><a href="{@docRoot}/../technotes/guides/security/StandardNames.html">
  *     <b>Java&trade;
  *     Cryptography Architecture Standard Algorithm Name
  *     Documentation</b></a></li>
@@ -52,10 +52,10 @@
  *   <li><a href="http://www.ietf.org/rfc/rfc5280.txt">
  *     http://www.ietf.org/rfc/rfc5280.txt</a>
  *   <li><a href=
- *     "https://docs.oracle.com/javase/8/docs/technotes/guides/security/certpath/CertPathProgGuide.html">
+ *     "{@docRoot}/../technotes/guides/security/certpath/CertPathProgGuide.html">
  *     <b>Java&trade;
  *     PKI Programmer's Guide</b></a>
- *   <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/cert3.html">
+ *   <li><a href="{@docRoot}/../technotes/guides/security/cert3.html">
  *     <b>X.509 Certificates and Certificate Revocation Lists (CRLs)</b></a>
  * </ul>
  *
diff --git a/ojluni/src/main/java/java/security/interfaces/TEST_MAPPING b/ojluni/src/main/java/java/security/interfaces/TEST_MAPPING
new file mode 100644
index 0000000..3c28d51
--- /dev/null
+++ b/ojluni/src/main/java/java/security/interfaces/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "tests.security.interfaces"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/security/interfaces/package-info.java b/ojluni/src/main/java/java/security/interfaces/package-info.java
index 8942340..54c9397 100644
--- a/ojluni/src/main/java/java/security/interfaces/package-info.java
+++ b/ojluni/src/main/java/java/security/interfaces/package-info.java
@@ -43,7 +43,7 @@
  * to these cryptographic provider developer guides:
  * <ul>
  *   <li><a href=
- *     "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
+ *     "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
  *     <b>How to Implement a Provider for the
  *     Java&trade; Cryptography Architecture
  *     </b></a></li>
@@ -63,7 +63,7 @@
  * <ul>
  *   <li>
  *     <a href=
- *       "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+ *       "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
  *       <b>Java&trade;
  *       Cryptography Architecture API Specification and Reference
  *       </b></a></li>
diff --git a/ojluni/src/main/java/java/security/package-info.java b/ojluni/src/main/java/java/security/package-info.java
index 60e9b4b..2c8205b 100644
--- a/ojluni/src/main/java/java/security/package-info.java
+++ b/ojluni/src/main/java/java/security/package-info.java
@@ -46,14 +46,14 @@
  * <h2>Package Specification</h2>
  *
  * <ul>
- *   <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+ *   <li><a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
  *     <b>Java&trade;
  *     Cryptography Architecture (JCA) Reference Guide</b></a></li>
  *
  *   <li>PKCS #8: Private-Key Information Syntax Standard, Version 1.2,
  *     November 1993</li>
  *
- *   <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">
+ *   <li><a href="{@docRoot}/../technotes/guides/security/StandardNames.html">
  *     <b>Java&trade;
  *     Cryptography Architecture Standard Algorithm Name
  *     Documentation</b></a></li>
@@ -64,44 +64,44 @@
  * For further documentation, please see:
  * <ul>
  *   <li><a href=
- *     "https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc.html">
+ *     "{@docRoot}/../technotes/guides/security/spec/security-spec.doc.html">
  *     <b>Java&trade;
  *     SE Platform Security Architecture</b></a></li>
  *
  *   <li><a href=
- *     "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
+ *     "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
  *     <b>How to Implement a Provider in the
  *     Java&trade; Cryptography Architecture
  *     </b></a></li>
  *
  *   <li><a href=
- *     "https://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html"><b>
+ *     "{@docRoot}/../technotes/guides/security/PolicyFiles.html"><b>
  *     Default Policy Implementation and Policy File Syntax
  *     </b></a></li>
  *
  *   <li><a href=
- *     "https://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html"><b>
+ *     "{@docRoot}/../technotes/guides/security/permissions.html"><b>
  *     Permissions in the
  *     Java&trade; SE Development Kit (JDK)
  *     </b></a></li>
  *
  *   <li><a href=
- *     "https://docs.oracle.com/javase/8/docs/technotes/guides/security/SecurityToolsSummary.html"><b>
+ *     "{@docRoot}/../technotes/guides/security/SecurityToolsSummary.html"><b>
  *     Summary of Tools for
  *     Java&trade; Platform Security
  *     </b></a></li>
  *
  *   <li><b>keytool</b>
- *     (<a href="https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html">
+ *     (<a href="{@docRoot}/../technotes/tools/unix/keytool.html">
  *       for Solaris/Linux</a>)
- *     (<a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/keytool.html">
+ *     (<a href="{@docRoot}/../technotes/tools/windows/keytool.html">
  *       for Windows</a>)
  *     </li>
  *
  *   <li><b>jarsigner</b>
- *     (<a href="https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jarsigner.html">
+ *     (<a href="{@docRoot}/../technotes/tools/unix/jarsigner.html">
  *       for Solaris/Linux</a>)
- *     (<a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jarsigner.html">
+ *     (<a href="{@docRoot}/../technotes/tools/windows/jarsigner.html">
  *       for Windows</a>)
  *     </li>
  *
diff --git a/ojluni/src/main/java/java/security/spec/TEST_MAPPING b/ojluni/src/main/java/java/security/spec/TEST_MAPPING
new file mode 100644
index 0000000..f54aac6
--- /dev/null
+++ b/ojluni/src/main/java/java/security/spec/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.security.spec"
+        },
+        {
+          "include-filter": "tests.security.spec"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/security/spec/package-info.java b/ojluni/src/main/java/java/security/spec/package-info.java
index 68f0b8e..cb39308 100644
--- a/ojluni/src/main/java/java/security/spec/package-info.java
+++ b/ojluni/src/main/java/java/security/spec/package-info.java
@@ -56,13 +56,13 @@
  * <ul>
  *   <li>
  *     <a href=
- *       "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+ *       "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
  *       <b>Java&trade;
  *       Cryptography Architecture API Specification and Reference
  *       </b></a></li>
  *   <li>
  *     <a href=
- *       "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
+ *       "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
  *       <b>How to Implement a Provider for the
  *       Java&trade; Cryptography Architecture
  *       </b></a></li>
diff --git a/ojluni/src/main/java/java/sql/DriverManager.java b/ojluni/src/main/java/java/sql/DriverManager.java
index 2fc6acc..08755b0 100644
--- a/ojluni/src/main/java/java/sql/DriverManager.java
+++ b/ojluni/src/main/java/java/sql/DriverManager.java
@@ -53,7 +53,7 @@
  * </pre>
  *<P> The <code>DriverManager</code> methods <code>getConnection</code> and
  * <code>getDrivers</code> have been enhanced to support the Java Standard Edition
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
+ * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
  * include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers
  * implementation of <code>java.sql.Driver</code>.  For example, to load the <code>my.sql.Driver</code> class,
  * the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:
diff --git a/ojluni/src/main/java/java/sql/TEST_MAPPING b/ojluni/src/main/java/java/sql/TEST_MAPPING
new file mode 100644
index 0000000..28cf3b3
--- /dev/null
+++ b/ojluni/src/main/java/java/sql/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.sql.tests.java.sql"
+        },
+        {
+          "include-filter": "tests.java.sql"
+        },
+        {
+          "include-filter": "libcore.java.sql"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/sql/package.html b/ojluni/src/main/java/java/sql/package.html
index 74d6225..65d906b 100644
--- a/ojluni/src/main/java/java/sql/package.html
+++ b/ojluni/src/main/java/java/sql/package.html
@@ -310,7 +310,7 @@
 <h2>Related Documentation</h2>
 
 <ul>
-  <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/getstart/GettingStartedTOC.fm.html">Getting Started</a>--overviews of the major interfaces
+  <li><a href="../../../technotes/guides/jdbc/getstart/GettingStartedTOC.fm.html">Getting Started</a>--overviews of the major interfaces
 <P>
   <li><a href="http://java.sun.com/docs/books/tutorial/jdbc">Chapters on the JDBC 
      API</a>--from the online version of <i>The Java Tutorial Continued</i>
diff --git a/ojluni/src/main/java/java/text/Collator.java b/ojluni/src/main/java/java/text/Collator.java
index ca3a220..e7fc8b7 100644
--- a/ojluni/src/main/java/java/text/Collator.java
+++ b/ojluni/src/main/java/java/text/Collator.java
@@ -226,14 +226,16 @@
      * @see java.util.Locale
      * @see java.util.ResourceBundle
      */
-    // Android-changed: Switched to ICU.
-    public static synchronized Collator getInstance(Locale desiredLocale)
-    {
-        if (desiredLocale == null) {
-            throw new NullPointerException("locale == null");
+    public static Collator getInstance(Locale desiredLocale) {
+        // BEGIN Android-changed: Switched to ICU.
+        synchronized(Collator.class) {
+            if (desiredLocale == null) {
+                throw new NullPointerException("locale == null");
+            }
+            return new RuleBasedCollator((android.icu.text.RuleBasedCollator)
+                    android.icu.text.Collator.getInstance(desiredLocale));
         }
-        return new RuleBasedCollator((android.icu.text.RuleBasedCollator)
-                android.icu.text.Collator.getInstance(desiredLocale));
+        // END Android-changed: Switched to ICU.
     }
 
     /**
@@ -386,7 +388,7 @@
         icuColl.setDecomposition(decompositionMode_Java_ICU(decompositionMode));
     }
 
-    // Android-changed: Removed references to CollatorProvider.
+    // Android-changed: Removed javadoc references to CollatorProvider.
     /**
      * Returns an array of all locales for which the
      * <code>getInstance</code> methods of this class can return
@@ -397,7 +399,7 @@
      */
     public static synchronized Locale[] getAvailableLocales() {
         // Android-changed: Removed reference to CollatorProvider. Switched to ICU.
-        return ICU.getAvailableCollatorLocales();
+        return android.icu.text.Collator.getAvailableLocales();
     }
 
     // BEGIN Android-added: conversion method for decompositionMode constants.
@@ -425,7 +427,7 @@
     }
     // END Android-added: conversion method for decompositionMode constants.
 
-    // Android-changed: improve documentation.
+    // Android-changed: improve clone() documentation.
     /**
      * Returns a new collator with the same decomposition mode and
      * strength value as this collator.
diff --git a/ojluni/src/main/java/java/text/DateFormatSymbols.java b/ojluni/src/main/java/java/text/DateFormatSymbols.java
index 97dc528..5216928 100644
--- a/ojluni/src/main/java/java/text/DateFormatSymbols.java
+++ b/ojluni/src/main/java/java/text/DateFormatSymbols.java
@@ -421,25 +421,27 @@
 
     // BEGIN Android-changed: Replace getProviderInstance() with getCachedInstance().
     // Android removed support for DateFormatSymbolsProviders, but still caches DFS.
+    // App compat change for b/159514442.
     /**
      * Returns a cached DateFormatSymbols if it's found in the
      * cache. Otherwise, this method returns a newly cached instance
      * for the given locale.
      */
     private static DateFormatSymbols getCachedInstance(Locale locale) {
-        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+        Locale cacheKey = LocaleData.getCompatibleLocaleForBug159514442(locale);
+        SoftReference<DateFormatSymbols> ref = cachedInstances.get(cacheKey);
         DateFormatSymbols dfs;
         if (ref == null || (dfs = ref.get()) == null) {
             dfs = new DateFormatSymbols(locale);
             ref = new SoftReference<>(dfs);
-            SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
+            SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(cacheKey, ref);
             if (x != null) {
                 DateFormatSymbols y = x.get();
                 if (y != null) {
                     dfs = y;
                 } else {
                     // Replace the empty SoftReference with ref.
-                    cachedInstances.put(locale, ref);
+                    cachedInstances.put(cacheKey, ref);
                 }
             }
         }
@@ -818,7 +820,9 @@
      * appropriate LocaleData object. Note: zoneStrings isn't initialized in this method.
      */
     private void initializeData(Locale locale) {
-        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+        // Android-changed: App compat change for b/159514442.
+        Locale cacheKey = LocaleData.getCompatibleLocaleForBug159514442(locale);
+        SoftReference<DateFormatSymbols> ref = cachedInstances.get(cacheKey);
         DateFormatSymbols dfs;
         // Android-changed: invert cache presence check to simplify code flow.
         if (ref != null && (dfs = ref.get()) != null) {
diff --git a/ojluni/src/main/java/java/text/DecimalFormat.java b/ojluni/src/main/java/java/text/DecimalFormat.java
index d62cb27..a2a37b1 100644
--- a/ojluni/src/main/java/java/text/DecimalFormat.java
+++ b/ojluni/src/main/java/java/text/DecimalFormat.java
@@ -39,6 +39,7 @@
 
 package java.text;
 
+import android.icu.impl.number.DecimalFormatProperties.ParseMode;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -52,7 +53,6 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import libcore.icu.LocaleData;
-
 import android.icu.math.MathContext;
 
 /**
@@ -385,8 +385,7 @@
     // to implement DecimalFormat.
 
     // Android-added: ICU DecimalFormat to delegate to.
-    // TODO(b/68143370): switch back to ICU DecimalFormat once it can reproduce ICU 58 behavior.
-    private transient android.icu.text.DecimalFormat_ICU58_Android icuDecimalFormat;
+    private transient android.icu.text.DecimalFormat icuDecimalFormat;
 
     /**
      * Creates a DecimalFormat using the default pattern and symbols
@@ -488,8 +487,10 @@
      * {@link #icuDecimalFormat} in the process. This should only be called from constructors.
      */
     private void initPattern(String pattern) {
-        this.icuDecimalFormat =  new android.icu.text.DecimalFormat_ICU58_Android(pattern,
+        this.icuDecimalFormat =  new android.icu.text.DecimalFormat(pattern,
                 symbols.getIcuDecimalFormatSymbols());
+        // Android-changed: Compatibility mode for j.t.DecimalFormat. http://b/112355520
+        icuDecimalFormat.setParseStrictMode(ParseMode.JAVA_COMPATIBILITY);
         updateFieldsFromIcu();
     }
 
@@ -3083,7 +3084,7 @@
         */
         try {
             DecimalFormat other = (DecimalFormat) super.clone();
-            other.icuDecimalFormat = (android.icu.text.DecimalFormat_ICU58_Android) icuDecimalFormat.clone();
+            other.icuDecimalFormat = (android.icu.text.DecimalFormat) icuDecimalFormat.clone();
             other.symbols = (DecimalFormatSymbols) symbols.clone();
             return other;
         } catch (Exception e) {
@@ -3149,7 +3150,7 @@
             && compareIcuRoundingIncrement(other.icuDecimalFormat);
     }
 
-    private boolean compareIcuRoundingIncrement(android.icu.text.DecimalFormat_ICU58_Android other) {
+    private boolean compareIcuRoundingIncrement(android.icu.text.DecimalFormat other) {
         BigDecimal increment = this.icuDecimalFormat.getRoundingIncrement();
         if (increment != null) {
             return (other.getRoundingIncrement() != null)
diff --git a/ojluni/src/main/java/java/text/DecimalFormatSymbols.java b/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
index 6686d8b..a65a079 100644
--- a/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -792,6 +792,15 @@
         cachedIcuDFS.setInfinity(infinity);
         cachedIcuDFS.setNaN(NaN);
         cachedIcuDFS.setExponentSeparator(exponentialSeparator);
+        // j.t.DecimalFormatSymbols doesn't insert whitespace before/after currency by default.
+        // Override ICU default value to retain historic Android behavior.
+        // http://b/112127077
+        cachedIcuDFS.setPatternForCurrencySpacing(
+            android.icu.text.DecimalFormatSymbols.CURRENCY_SPC_INSERT,
+            false /* beforeCurrency */, "");
+        cachedIcuDFS.setPatternForCurrencySpacing(
+            android.icu.text.DecimalFormatSymbols.CURRENCY_SPC_INSERT,
+            true /* beforeCurrency */, "");
 
         try {
             cachedIcuDFS.setCurrency(
diff --git a/ojluni/src/main/java/java/text/SimpleDateFormat.java b/ojluni/src/main/java/java/text/SimpleDateFormat.java
index 0f6321a..ca5a504 100644
--- a/ojluni/src/main/java/java/text/SimpleDateFormat.java
+++ b/ojluni/src/main/java/java/text/SimpleDateFormat.java
@@ -56,8 +56,10 @@
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.Set;
 import java.util.SimpleTimeZone;
+import java.util.SortedMap;
 import java.util.TimeZone;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -1911,12 +1913,16 @@
     private int matchString(String text, int start, int field,
                             Map<String,Integer> data, CalendarBuilder calb) {
         if (data != null) {
-            // BEGIN Android-removed: SortedMap instance lookup optimization in matchString().
+            // TODO: make this default when it's in the spec.
+            // BEGIN Android-changed: SortedMap instance lookup optimization in matchString().
             // RI returns not the longest match as matchString(String[]) does. http://b/119913354
             /*
-            // TODO: make this default when it's in the spec.
             if (data instanceof SortedMap) {
                 for (String name : data.keySet()) {
+            */
+            if (data instanceof NavigableMap && ((NavigableMap) data).comparator() == null) {
+                for (String name : ((NavigableMap<String, Integer>) data).descendingKeySet()) {
+            // END Android-changed: SortedMap instance lookup optimization in matchString().
                     if (text.regionMatches(true, start, name, 0, name.length())) {
                         calb.set(field, data.get(name));
                         return start + name.length();
@@ -1924,8 +1930,6 @@
                 }
                 return -start;
             }
-            */
-            // END Android-removed: SortedMap instance lookup optimization in matchString().
 
             String bestMatch = null;
 
diff --git a/ojluni/src/main/java/java/text/TEST_MAPPING b/ojluni/src/main/java/java/text/TEST_MAPPING
new file mode 100644
index 0000000..30747b2
--- /dev/null
+++ b/ojluni/src/main/java/java/text/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.java.text"
+        },
+        {
+          "include-filter": "libcore.java.text"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/time/TEST_MAPPING b/ojluni/src/main/java/java/time/TEST_MAPPING
new file mode 100644
index 0000000..5b24483
--- /dev/null
+++ b/ojluni/src/main/java/java/time/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.time"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "tck.java.time"
+        },
+        {
+          "include-filter": "tck.java.time.serial"
+        },
+        {
+          "include-filter": "test.java.time"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java b/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
index 29e503e..034a3bc 100644
--- a/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
+++ b/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
@@ -368,12 +368,12 @@
         throw new DateTimeException("Invalid yearOfEra value");
     }
 
+    // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
     /**
      * Returns the calendar system era object from the given numeric value.
      *
-     * See the description of each Era for the numeric values of:
-     * {@link JapaneseEra#HEISEI}, {@link JapaneseEra#SHOWA},{@link JapaneseEra#TAISHO},
-     * {@link JapaneseEra#MEIJI}), only Meiji and later eras are supported.
+     * The numeric values supported by this method are the same as the
+     * numeric values supported by {@link JapaneseEra#of(int)}.
      *
      * @param eraValue  the era value
      * @return the Japanese {@code Era} for the given numeric era value
diff --git a/ojluni/src/main/java/java/time/chrono/JapaneseEra.java b/ojluni/src/main/java/java/time/chrono/JapaneseEra.java
index d52f3c1..81805d0 100644
--- a/ojluni/src/main/java/java/time/chrono/JapaneseEra.java
+++ b/ojluni/src/main/java/java/time/chrono/JapaneseEra.java
@@ -150,12 +150,13 @@
      * which has the value 2.
      */
     public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
+    // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
     /**
      * The singleton instance for the 'Reiwa' era (2019-05-01 - current)
      * which has the value 3. The end date of this era is not specified, unless
      * the Japanese Government defines it.
      */
-    private static final JapaneseEra REIWA = new JapaneseEra(3, LocalDate.of(2019, 5, 1));
+    public static final JapaneseEra REIWA = new JapaneseEra(3, LocalDate.of(2019, 5, 1));
 
     // The number of predefined JapaneseEra constants.
     // There may be a supplemental era defined by the property.
diff --git a/ojluni/src/main/java/java/time/chrono/TEST_MAPPING b/ojluni/src/main/java/java/time/chrono/TEST_MAPPING
new file mode 100644
index 0000000..461c15d
--- /dev/null
+++ b/ojluni/src/main/java/java/time/chrono/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.time.chrono"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "tck.java.time.chrono.serial"
+        },
+        {
+          "include-filter": "tck.java.time.chrono"
+        },
+        {
+          "include-filter": "test.java.time.chrono"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/time/format/TEST_MAPPING b/ojluni/src/main/java/java/time/format/TEST_MAPPING
new file mode 100644
index 0000000..42286e4
--- /dev/null
+++ b/ojluni/src/main/java/java/time/format/TEST_MAPPING
@@ -0,0 +1,23 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.time.format"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "tck.java.time.format"
+        },
+        {
+          "include-filter": "test.java.time.format"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/time/temporal/TEST_MAPPING b/ojluni/src/main/java/java/time/temporal/TEST_MAPPING
new file mode 100644
index 0000000..deac48a
--- /dev/null
+++ b/ojluni/src/main/java/java/time/temporal/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.time.temporal"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "test.java.time.temporal"
+        },
+        {
+          "include-filter": "tck.java.time.temporal"
+        },
+        {
+          "include-filter": "tck.java.time.temporal.serial"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/time/zone/TEST_MAPPING b/ojluni/src/main/java/java/time/zone/TEST_MAPPING
new file mode 100644
index 0000000..1c8c89e
--- /dev/null
+++ b/ojluni/src/main/java/java/time/zone/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.time.zone"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "tck.java.time.zone"
+        },
+        {
+          "include-filter": "tck.java.time.zone.serial"
+        },
+        {
+          "include-filter": "test.java.time.zone"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/AbstractCollection.java b/ojluni/src/main/java/java/util/AbstractCollection.java
index 19c15f8..1f7cdd9 100644
--- a/ojluni/src/main/java/java/util/AbstractCollection.java
+++ b/ojluni/src/main/java/java/util/AbstractCollection.java
@@ -49,7 +49,7 @@
  * the collection being implemented admits a more efficient implementation.<p>
  *
  * This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author  Josh Bloch
diff --git a/ojluni/src/main/java/java/util/AbstractList.java b/ojluni/src/main/java/java/util/AbstractList.java
index a156ec6..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
@@ -60,7 +62,7 @@
  * collection being implemented admits a more efficient implementation.
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author  Josh Bloch
@@ -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/AbstractMap.java b/ojluni/src/main/java/java/util/AbstractMap.java
index 09c2f94..948bf51 100644
--- a/ojluni/src/main/java/java/util/AbstractMap.java
+++ b/ojluni/src/main/java/java/util/AbstractMap.java
@@ -52,7 +52,7 @@
  * map being implemented admits a more efficient implementation.
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <K> the type of keys maintained by this map
diff --git a/ojluni/src/main/java/java/util/AbstractSequentialList.java b/ojluni/src/main/java/java/util/AbstractSequentialList.java
index 37292df..36a91da 100644
--- a/ojluni/src/main/java/java/util/AbstractSequentialList.java
+++ b/ojluni/src/main/java/java/util/AbstractSequentialList.java
@@ -54,7 +54,7 @@
  * specification.<p>
  *
  * This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author  Josh Bloch
diff --git a/ojluni/src/main/java/java/util/AbstractSet.java b/ojluni/src/main/java/java/util/AbstractSet.java
index 620f672..b3fe0dc 100644
--- a/ojluni/src/main/java/java/util/AbstractSet.java
+++ b/ojluni/src/main/java/java/util/AbstractSet.java
@@ -42,7 +42,7 @@
  * for <tt>equals</tt> and <tt>hashCode</tt>.<p>
  *
  * This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <E> the type of elements maintained by this set
diff --git a/ojluni/src/main/java/java/util/ArrayList.java b/ojluni/src/main/java/java/util/ArrayList.java
index 02f9479..20c623a 100644
--- a/ojluni/src/main/java/java/util/ArrayList.java
+++ b/ojluni/src/main/java/java/util/ArrayList.java
@@ -92,7 +92,7 @@
  * should be used only to detect bugs.</i>
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author  Josh Bloch
diff --git a/ojluni/src/main/java/java/util/Arrays.java b/ojluni/src/main/java/java/util/Arrays.java
index 3f7b1bc..6da3e5d 100644
--- a/ojluni/src/main/java/java/util/Arrays.java
+++ b/ojluni/src/main/java/java/util/Arrays.java
@@ -61,7 +61,7 @@
  * a MergeSort, but it does have to be <i>stable</i>.)
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author Josh Bloch
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 3a0343b..7093533 100644
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -3376,6 +3376,7 @@
      */
     private void setWeekCountData(Locale desiredLocale)
     {
+        desiredLocale = LocaleData.getCompatibleLocaleForBug159514442(desiredLocale);
         /* try to get the Locale data from the cache */
         int[] data = cachedLocaleData.get(desiredLocale);
         if (data == null) {  /* cache miss */
diff --git a/ojluni/src/main/java/java/util/Collection.java b/ojluni/src/main/java/java/util/Collection.java
index 279ec9e..2ae8872 100644
--- a/ojluni/src/main/java/java/util/Collection.java
+++ b/ojluni/src/main/java/java/util/Collection.java
@@ -112,7 +112,7 @@
  * however most current implementations do not do so.
  *
  * <p>This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @implSpec
diff --git a/ojluni/src/main/java/java/util/Collections.java b/ojluni/src/main/java/java/util/Collections.java
index e7e8e72..58ad86f 100644
--- a/ojluni/src/main/java/java/util/Collections.java
+++ b/ojluni/src/main/java/java/util/Collections.java
@@ -70,7 +70,7 @@
  * already sorted may or may not throw <tt>UnsupportedOperationException</tt>.
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author  Josh Bloch
diff --git a/ojluni/src/main/java/java/util/Comparator.java b/ojluni/src/main/java/java/util/Comparator.java
index 27cfdd5..ecf8d64 100644
--- a/ojluni/src/main/java/java/util/Comparator.java
+++ b/ojluni/src/main/java/java/util/Comparator.java
@@ -94,7 +94,7 @@
  * an equivalence relation.
  *
  * <p>This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <T> the type of objects that may be compared by this comparator
diff --git a/ojluni/src/main/java/java/util/Deque.java b/ojluni/src/main/java/java/util/Deque.java
index dbd3d6f..3d79952 100644
--- a/ojluni/src/main/java/java/util/Deque.java
+++ b/ojluni/src/main/java/java/util/Deque.java
@@ -187,9 +187,10 @@
  * @since  1.6
  * @param <E> the type of elements held in this deque
  */
-// Android-changed: fix framework docs link to "Collection#optional-restrictions"
-// Several occurrences of the link have been fixed throughout.
 public interface Deque<E> extends Queue<E> {
+    // Android-changed: fix framework docs link to "Collection#optional-restrictions"
+    // Several occurrences of the link have been fixed throughout.
+
     /**
      * Inserts the specified element at the front of this deque if it is
      * possible to do so immediately without violating capacity restrictions,
diff --git a/ojluni/src/main/java/java/util/EnumMap.java b/ojluni/src/main/java/java/util/EnumMap.java
index 30a8dce..cd1c5fe 100644
--- a/ojluni/src/main/java/java/util/EnumMap.java
+++ b/ojluni/src/main/java/java/util/EnumMap.java
@@ -69,7 +69,7 @@
  * {@link HashMap} counterparts.
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author Josh Bloch
diff --git a/ojluni/src/main/java/java/util/EnumSet.java b/ojluni/src/main/java/java/util/EnumSet.java
index f1b0329..95e0124 100644
--- a/ojluni/src/main/java/java/util/EnumSet.java
+++ b/ojluni/src/main/java/java/util/EnumSet.java
@@ -68,7 +68,7 @@
  * constant time if their argument is also an enum set.
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author Josh Bloch
diff --git a/ojluni/src/main/java/java/util/HashMap.java b/ojluni/src/main/java/java/util/HashMap.java
index 360f736..2c01f6f 100644
--- a/ojluni/src/main/java/java/util/HashMap.java
+++ b/ojluni/src/main/java/java/util/HashMap.java
@@ -117,7 +117,7 @@
  * should be used only to detect bugs.</i>
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <K> the type of keys maintained by this map
diff --git a/ojluni/src/main/java/java/util/HashSet.java b/ojluni/src/main/java/java/util/HashSet.java
index 5805331..f9b09ee 100644
--- a/ojluni/src/main/java/java/util/HashSet.java
+++ b/ojluni/src/main/java/java/util/HashSet.java
@@ -72,7 +72,7 @@
  * should be used only to detect bugs.</i>
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <E> the type of elements maintained by this set
diff --git a/ojluni/src/main/java/java/util/Hashtable.java b/ojluni/src/main/java/java/util/Hashtable.java
index fc163a7..4c76a74 100644
--- a/ojluni/src/main/java/java/util/Hashtable.java
+++ b/ojluni/src/main/java/java/util/Hashtable.java
@@ -105,7 +105,7 @@
  *
  * <p>As of the Java 2 platform v1.2, this class was retrofitted to
  * implement the {@link Map} interface, making it a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  *
  * Java Collections Framework</a>.  Unlike the new collection
  * implementations, {@code Hashtable} is synchronized.  If a
diff --git a/ojluni/src/main/java/java/util/IdentityHashMap.java b/ojluni/src/main/java/java/util/IdentityHashMap.java
index 1ed9d76..9dc0c26 100644
--- a/ojluni/src/main/java/java/util/IdentityHashMap.java
+++ b/ojluni/src/main/java/java/util/IdentityHashMap.java
@@ -122,7 +122,7 @@
  * {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @see     System#identityHashCode(Object)
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/Iterator.java b/ojluni/src/main/java/java/util/Iterator.java
index 02777b6..7d2daf8 100644
--- a/ojluni/src/main/java/java/util/Iterator.java
+++ b/ojluni/src/main/java/java/util/Iterator.java
@@ -40,7 +40,7 @@
  * </ul>
  *
  * <p>This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <E> the type of elements returned by this iterator
diff --git a/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java b/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
index a0ee15e..f0512c5 100644
--- a/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
+++ b/ojluni/src/main/java/java/util/JapaneseImperialCalendar.java
@@ -101,10 +101,11 @@
      */
     public static final int HEISEI = 4;
 
+    // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
     /**
      * The ERA constant designating the Reiwa era.
      */
-    private static final int REIWA = 5;
+    public static final int REIWA = 5;
 
     private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
     private static final int EPOCH_YEAR     = 1970;
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/LinkedHashMap.java b/ojluni/src/main/java/java/util/LinkedHashMap.java
index a60c7e5..9d3815f 100644
--- a/ojluni/src/main/java/java/util/LinkedHashMap.java
+++ b/ojluni/src/main/java/java/util/LinkedHashMap.java
@@ -158,7 +158,7 @@
  * {@code LinkedHashMap}.
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @implNote
diff --git a/ojluni/src/main/java/java/util/LinkedHashSet.java b/ojluni/src/main/java/java/util/LinkedHashSet.java
index c573d7c..08606cf 100644
--- a/ojluni/src/main/java/java/util/LinkedHashSet.java
+++ b/ojluni/src/main/java/java/util/LinkedHashSet.java
@@ -100,7 +100,7 @@
  * should be used only to detect bugs.</i>
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <E> the type of elements maintained by this set
diff --git a/ojluni/src/main/java/java/util/LinkedList.java b/ojluni/src/main/java/java/util/LinkedList.java
index 2683a90..60f4c41 100644
--- a/ojluni/src/main/java/java/util/LinkedList.java
+++ b/ojluni/src/main/java/java/util/LinkedList.java
@@ -70,7 +70,7 @@
  * should be used only to detect bugs.</i>
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author  Josh Bloch
diff --git a/ojluni/src/main/java/java/util/List.java b/ojluni/src/main/java/java/util/List.java
index f32d9ed..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="https://docs.oracle.com/javase/8/docs/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/ListIterator.java b/ojluni/src/main/java/java/util/ListIterator.java
index 85a2f25..6ad98fe 100644
--- a/ojluni/src/main/java/java/util/ListIterator.java
+++ b/ojluni/src/main/java/java/util/ListIterator.java
@@ -46,7 +46,7 @@
  * {@link #previous()}.
  *
  * <p>This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @author  Josh Bloch
diff --git a/ojluni/src/main/java/java/util/Locale.java b/ojluni/src/main/java/java/util/Locale.java
index 3908fa3..1ce4a202 100644
--- a/ojluni/src/main/java/java/util/Locale.java
+++ b/ojluni/src/main/java/java/util/Locale.java
@@ -41,6 +41,7 @@
 
 package java.util;
 
+import com.android.icu.util.LocaleNative;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -524,8 +525,8 @@
  *     <td><a href="http://site.icu-project.org/download/60">ICU 60.2</a></td>
  *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-32">CLDR 32.0.1</a></td>
  *     <td><a href="http://www.unicode.org/versions/Unicode10.0.0/">Unicode 10.0</a></td></tr>
- * <tr><td>Android Q</td>
- *     <td><a href="http://site.icu-project.org/download/63">ICU 63.1</a></td>
+ * <tr><td>Android 10.0 (Q)</td>
+ *     <td><a href="http://site.icu-project.org/download/63">ICU 63.2</a></td>
  *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-34">CLDR 34</a></td>
  *     <td><a href="http://www.unicode.org/versions/Unicode11.0.0/">Unicode 11.0</a></td></tr>
  * </table>
@@ -1874,9 +1875,9 @@
 
         // TODO: We need a new hack or a complete fix for http://b/8049507 --- We would
         // cover the frameworks' tracks when they were using "tl" instead of "fil".
-        String result = ICU.getDisplayLanguage(this, locale);
+        String result = LocaleNative.getDisplayLanguage(this, locale);
         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
-            result = ICU.getDisplayLanguage(this, Locale.getDefault());
+            result = LocaleNative.getDisplayLanguage(this, Locale.getDefault());
         }
         return result;
     }
@@ -1949,9 +1950,9 @@
             return "";
         }
 
-        String result = ICU.getDisplayScript(this, inLocale);
+        String result = LocaleNative.getDisplayScript(this, inLocale);
         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
-            result = ICU.getDisplayScript(this, Locale.getDefault(Category.DISPLAY));
+            result = LocaleNative.getDisplayScript(this, Locale.getDefault(Category.DISPLAY));
         }
 
         return result;
@@ -2043,9 +2044,9 @@
             return countryCode;
         }
 
-        String result = ICU.getDisplayCountry(this, locale);
+        String result = LocaleNative.getDisplayCountry(this, locale);
         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
-            result = ICU.getDisplayCountry(this, Locale.getDefault());
+            result = LocaleNative.getDisplayCountry(this, Locale.getDefault());
         }
         return result;
     }
@@ -2154,9 +2155,9 @@
             return variantCode;
         }
 
-        String result = ICU.getDisplayVariant(this, inLocale);
+        String result = LocaleNative.getDisplayVariant(this, inLocale);
         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
-            result = ICU.getDisplayVariant(this, Locale.getDefault());
+            result = LocaleNative.getDisplayVariant(this, Locale.getDefault());
         }
 
         // The "old style" locale constructors allow us to pass in variants that aren't
@@ -2349,7 +2350,7 @@
      * <li>{@code new Locale("en").getDisplayName(Locale.US)} -> {@code English}
      * <li>{@code new Locale("en", "US").getDisplayName(Locale.US)} -> {@code English (United States)}
      * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.US)} -> {@code English (United States,Computer)}
-     * <li>{@code Locale.fromLanguageTag("zh-Hant-CN").getDisplayName(Locale.US)} -> {@code Chinese (Traditional Han,China)}
+     * <li>{@code Locale.forLanguageTag("zh-Hant-CN").getDisplayName(Locale.US)} -> {@code Chinese (Traditional Han,China)}
      * <li>{@code new Locale("en").getDisplayName(Locale.FRANCE)} -> {@code anglais}
      * <li>{@code new Locale("en", "US").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis)}
      * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis,informatique)}.
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/PriorityQueue.java b/ojluni/src/main/java/java/util/PriorityQueue.java
index 90e59d1..7c929bd 100644
--- a/ojluni/src/main/java/java/util/PriorityQueue.java
+++ b/ojluni/src/main/java/java/util/PriorityQueue.java
@@ -72,7 +72,7 @@
  * ({@code peek}, {@code element}, and {@code size}).
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @since 1.5
diff --git a/ojluni/src/main/java/java/util/RandomAccess.java b/ojluni/src/main/java/java/util/RandomAccess.java
index 6b7e453..09ce29e 100644
--- a/ojluni/src/main/java/java/util/RandomAccess.java
+++ b/ojluni/src/main/java/java/util/RandomAccess.java
@@ -59,7 +59,7 @@
  * </pre>
  *
  * <p>This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @since 1.4
diff --git a/ojluni/src/main/java/java/util/Set.java b/ojluni/src/main/java/java/util/Set.java
index ee22fca..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,8 +63,35 @@
  * 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="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <E> the type of elements maintained by this set
@@ -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/SortedMap.java b/ojluni/src/main/java/java/util/SortedMap.java
index 15ddba5..7f98152 100644
--- a/ojluni/src/main/java/java/util/SortedMap.java
+++ b/ojluni/src/main/java/java/util/SortedMap.java
@@ -93,7 +93,7 @@
  *   SortedMap&lt;String, V&gt; sub = m.subMap(low+"\0", high);</pre>
  *
  * <p>This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <K> the type of keys maintained by this map
diff --git a/ojluni/src/main/java/java/util/SortedSet.java b/ojluni/src/main/java/java/util/SortedSet.java
index 1ba72dd..3ea9329 100644
--- a/ojluni/src/main/java/java/util/SortedSet.java
+++ b/ojluni/src/main/java/java/util/SortedSet.java
@@ -89,7 +89,7 @@
  *   SortedSet&lt;String&gt; sub = s.subSet(low+"\0", high);</pre>
  *
  * <p>This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <E> the type of elements maintained by this set
diff --git a/ojluni/src/main/java/java/util/TEST_MAPPING b/ojluni/src/main/java/java/util/TEST_MAPPING
new file mode 100644
index 0000000..e1434fb
--- /dev/null
+++ b/ojluni/src/main/java/java/util/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.util"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.util"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "test.java.util"
+        },
+        {
+          "include-filter": "org.openjdk.tests.java.util"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/TimeZone.java b/ojluni/src/main/java/java/util/TimeZone.java
index 61826ba..cf5e5f8 100644
--- a/ojluni/src/main/java/java/util/TimeZone.java
+++ b/ojluni/src/main/java/java/util/TimeZone.java
@@ -47,7 +47,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import libcore.io.IoUtils;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
 
 import dalvik.system.RuntimeHooks;
 
@@ -557,7 +557,7 @@
      * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
      * cannot be understood.
      */
-    // Android-changed: param s/ID/id; use ZoneInfoDB instead of ZoneInfo class.
+    // Android-changed: param s/ID/id; use ZoneInfoDb instead of ZoneInfo class.
     public static synchronized TimeZone getTimeZone(String id) {
         if (id == null) {
             throw new NullPointerException("id == null");
@@ -576,7 +576,7 @@
         // In the database?
         TimeZone zone = null;
         try {
-            zone = ZoneInfoDB.getInstance().makeTimeZone(id);
+            zone = ZoneInfoDb.getInstance().makeTimeZone(id);
         } catch (IOException ignored) {
         }
 
@@ -666,7 +666,7 @@
      * @see #getRawOffset()
      */
     public static synchronized String[] getAvailableIDs(int rawOffset) {
-        return ZoneInfoDB.getInstance().getAvailableIDs(rawOffset);
+        return ZoneInfoDb.getInstance().getAvailableIDs(rawOffset);
     }
 
     /**
@@ -674,7 +674,7 @@
      * @return an array of IDs.
      */
     public static synchronized String[] getAvailableIDs() {
-        return ZoneInfoDB.getInstance().getAvailableIDs();
+        return ZoneInfoDb.getInstance().getAvailableIDs();
     }
 
     /**
diff --git a/ojluni/src/main/java/java/util/TreeMap.java b/ojluni/src/main/java/java/util/TreeMap.java
index 7603cfc..20d98bc 100644
--- a/ojluni/src/main/java/java/util/TreeMap.java
+++ b/ojluni/src/main/java/java/util/TreeMap.java
@@ -93,7 +93,7 @@
  * associated map using {@code put}.)
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <K> the type of keys maintained by this map
diff --git a/ojluni/src/main/java/java/util/TreeSet.java b/ojluni/src/main/java/java/util/TreeSet.java
index be215ba..54eeeda 100644
--- a/ojluni/src/main/java/java/util/TreeSet.java
+++ b/ojluni/src/main/java/java/util/TreeSet.java
@@ -74,7 +74,7 @@
  * should be used only to detect bugs.</i>
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <E> the type of elements maintained by this set
diff --git a/ojluni/src/main/java/java/util/Vector.java b/ojluni/src/main/java/java/util/Vector.java
index 6c5247c..f184437 100644
--- a/ojluni/src/main/java/java/util/Vector.java
+++ b/ojluni/src/main/java/java/util/Vector.java
@@ -68,7 +68,7 @@
  *
  * <p>As of the Java 2 platform v1.2, this class was retrofitted to
  * implement the {@link List} interface, making it a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.  Unlike the new collection
  * implementations, {@code Vector} is synchronized.  If a thread-safe
  * implementation is not needed, it is recommended to use {@link
diff --git a/ojluni/src/main/java/java/util/WeakHashMap.java b/ojluni/src/main/java/java/util/WeakHashMap.java
index d977b61..7352391 100644
--- a/ojluni/src/main/java/java/util/WeakHashMap.java
+++ b/ojluni/src/main/java/java/util/WeakHashMap.java
@@ -1,5 +1,4 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
  * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -28,6 +27,7 @@
 
 import java.lang.ref.WeakReference;
 import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
@@ -120,7 +120,7 @@
  * should be used only to detect bugs.</i>
  *
  * <p>This class is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @param <K> the type of keys maintained by this map
diff --git a/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java b/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
index da1a4fd..290fee1 100644
--- a/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
+++ b/ojluni/src/main/java/java/util/concurrent/BlockingDeque.java
@@ -197,7 +197,7 @@
  * the {@code BlockingDeque} in another thread.
  *
  * <p>This interface is a member of the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html">
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
  * @since 1.6
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/java/util/concurrent/TEST_MAPPING b/ojluni/src/main/java/java/util/concurrent/TEST_MAPPING
new file mode 100644
index 0000000..5730a28
--- /dev/null
+++ b/ojluni/src/main/java/java/util/concurrent/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreJsr166TestCases",
+      "options": [
+        {
+          "include-filter": "jsr166"
+        }
+      ]
+    },
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.util.concurrent"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/function/TEST_MAPPING b/ojluni/src/main/java/java/util/function/TEST_MAPPING
new file mode 100644
index 0000000..5840cf9
--- /dev/null
+++ b/ojluni/src/main/java/java/util/function/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.util.function"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/jar/Attributes.java b/ojluni/src/main/java/java/util/jar/Attributes.java
index 6878aa8..795b809 100644
--- a/ojluni/src/main/java/java/util/jar/Attributes.java
+++ b/ojluni/src/main/java/java/util/jar/Attributes.java
@@ -1,5 +1,4 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -45,7 +44,7 @@
  * the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed 70
  * characters in length. Attribute values can contain any characters and
  * will be UTF8-encoded when written to the output stream.  See the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html">JAR File Specification</a>
+ * <a href="../../../../technotes/guides/jar/jar.html">JAR File Specification</a>
  * for more information about valid attribute names and values.
  *
  * @author  David Connelly
@@ -442,7 +441,7 @@
      * to the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed
      * 70 characters in length. Attribute values can contain any characters
      * and will be UTF8-encoded when written to the output stream.  See the
-     * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html">JAR File Specification</a>
+     * <a href="../../../../technotes/guides/jar/jar.html">JAR File Specification</a>
      * for more information about valid attribute names and values.
      */
     public static class Name {
@@ -528,7 +527,7 @@
          * <code>Name</code> object for <code>Manifest-Version</code>
          * manifest attribute. This attribute indicates the version number
          * of the manifest standard to which a JAR file's manifest conforms.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#JAR_Manifest">
+         * @see <a href="../../../../technotes/guides/jar/jar.html#JAR_Manifest">
          *      Manifest and Signature Specification</a>
          */
         public static final Name MANIFEST_VERSION = new Name("Manifest-Version");
@@ -536,7 +535,7 @@
         /**
          * <code>Name</code> object for <code>Signature-Version</code>
          * manifest attribute used when signing JAR files.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#JAR_Manifest">
+         * @see <a href="../../../../technotes/guides/jar/jar.html#JAR_Manifest">
          *      Manifest and Signature Specification</a>
          */
         public static final Name SIGNATURE_VERSION = new Name("Signature-Version");
@@ -551,7 +550,7 @@
          * <code>Name</code> object for <code>Class-Path</code>
          * manifest attribute. Bundled extensions can use this attribute
          * to find other JAR files containing needed classes.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#classpath">
+         * @see <a href="../../../../technotes/guides/jar/jar.html#classpath">
          *      JAR file specification</a>
          */
         public static final Name CLASS_PATH = new Name("Class-Path");
@@ -568,7 +567,7 @@
         /**
          * <code>Name</code> object for <code>Sealed</code> manifest attribute
          * used for sealing.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#sealing">
+         * @see <a href="../../../../technotes/guides/jar/jar.html#sealing">
          *      Package Sealing</a>
          */
         public static final Name SEALED = new Name("Sealed");
@@ -576,7 +575,7 @@
        /**
          * <code>Name</code> object for <code>Extension-List</code> manifest attribute
          * used for declaring dependencies on installed extensions.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/extensions/spec.html#dependency">
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
          *      Installed extension dependency</a>
          */
         public static final Name EXTENSION_LIST = new Name("Extension-List");
@@ -584,7 +583,7 @@
         /**
          * <code>Name</code> object for <code>Extension-Name</code> manifest attribute
          * used for declaring dependencies on installed extensions.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/extensions/spec.html#dependency">
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
          *      Installed extension dependency</a>
          */
         public static final Name EXTENSION_NAME = new Name("Extension-Name");
@@ -594,7 +593,7 @@
          * used for declaring dependencies on installed extensions.
          * @deprecated Extension mechanism will be removed in a future release.
          *             Use class path instead.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/extensions/spec.html#dependency">
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
          *      Installed extension dependency</a>
          */
         @Deprecated
@@ -603,7 +602,7 @@
         /**
          * <code>Name</code> object for <code>Implementation-Title</code>
          * manifest attribute used for package versioning.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp90779">
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
          *      Java Product Versioning Specification</a>
          */
         public static final Name IMPLEMENTATION_TITLE = new Name("Implementation-Title");
@@ -611,7 +610,7 @@
         /**
          * <code>Name</code> object for <code>Implementation-Version</code>
          * manifest attribute used for package versioning.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp90779">
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
          *      Java Product Versioning Specification</a>
          */
         public static final Name IMPLEMENTATION_VERSION = new Name("Implementation-Version");
@@ -619,7 +618,7 @@
         /**
          * <code>Name</code> object for <code>Implementation-Vendor</code>
          * manifest attribute used for package versioning.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp90779">
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
          *      Java Product Versioning Specification</a>
          */
         public static final Name IMPLEMENTATION_VENDOR = new Name("Implementation-Vendor");
@@ -629,7 +628,7 @@
          * manifest attribute used for package versioning.
          * @deprecated Extension mechanism will be removed in a future release.
          *             Use class path instead.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/extensions/versioning.html#applet">
+         * @see <a href="../../../../technotes/guides/extensions/versioning.html#applet">
          *      Optional Package Versioning</a>
          */
         @Deprecated
@@ -640,7 +639,7 @@
          * manifest attribute used for package versioning.
          * @deprecated Extension mechanism will be removed in a future release.
          *             Use class path instead.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/extensions/versioning.html#applet">
+         * @see <a href="../../../../technotes/guides/extensions/versioning.html#applet">
          *      Optional Package Versioning</a>
          */
         @Deprecated
@@ -649,7 +648,7 @@
         /**
          * <code>Name</code> object for <code>Specification-Title</code>
          * manifest attribute used for package versioning.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp90779">
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
          *      Java Product Versioning Specification</a>
          */
         public static final Name SPECIFICATION_TITLE = new Name("Specification-Title");
@@ -657,7 +656,7 @@
         /**
          * <code>Name</code> object for <code>Specification-Version</code>
          * manifest attribute used for package versioning.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp90779">
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
          *      Java Product Versioning Specification</a>
          */
         public static final Name SPECIFICATION_VERSION = new Name("Specification-Version");
@@ -665,7 +664,7 @@
         /**
          * <code>Name</code> object for <code>Specification-Vendor</code>
          * manifest attribute used for package versioning.
-         * @see <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp90779">
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
          *      Java Product Versioning Specification</a>
          */
         public static final Name SPECIFICATION_VENDOR = new Name("Specification-Vendor");
diff --git a/ojluni/src/main/java/java/util/jar/Manifest.java b/ojluni/src/main/java/java/util/jar/Manifest.java
index 4dfda78..976e44c 100644
--- a/ojluni/src/main/java/java/util/jar/Manifest.java
+++ b/ojluni/src/main/java/java/util/jar/Manifest.java
@@ -39,7 +39,7 @@
  * associated Attributes. There are main Manifest Attributes as well as
  * per-entry Attributes. For information on the Manifest format, please
  * see the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html">
+ * <a href="../../../../technotes/guides/jar/jar.html">
  * Manifest format specification</a>.
  *
  * @author  David Connelly
diff --git a/ojluni/src/main/java/java/util/jar/Pack200.java b/ojluni/src/main/java/java/util/jar/Pack200.java
index 26b2ce3..9211f0a 100644
--- a/ojluni/src/main/java/java/util/jar/Pack200.java
+++ b/ojluni/src/main/java/java/util/jar/Pack200.java
@@ -96,7 +96,7 @@
  * The deployment applications can use "Accept-Encoding=pack200-gzip". This
  * indicates to the server that the client application desires a version of
  * the file encoded with Pack200 and further compressed with gzip. Please
- * refer to  <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/deployment/deployment-guide/pack200.html">Java Deployment Guide</a> for more details and
+ * refer to  <a href="{@docRoot}/../technotes/guides/deployment/deployment-guide/pack200.html">Java Deployment Guide</a> for more details and
  * techniques.
  * <p>
  * Unless otherwise noted, passing a <tt>null</tt> argument to a constructor or
diff --git a/ojluni/src/main/java/java/util/jar/TEST_MAPPING b/ojluni/src/main/java/java/util/jar/TEST_MAPPING
new file mode 100644
index 0000000..5b26443
--- /dev/null
+++ b/ojluni/src/main/java/java/util/jar/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.util.jar"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.util.jar"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/jar/package.html b/ojluni/src/main/java/java/util/jar/package.html
index 921a821..dd9ad73 100644
--- a/ojluni/src/main/java/java/util/jar/package.html
+++ b/ojluni/src/main/java/java/util/jar/package.html
@@ -45,7 +45,7 @@
       package description.</a> <p>
       In JAR files, all file names must be encoded in the UTF-8 encoding. 
 <p>
-  <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html">
+  <li><a href="../../../../technotes/guides/jar/jar.html">
       Manifest and Signature Specification</a> - The manifest format specification.
 </ul>
 
diff --git a/ojluni/src/main/java/java/util/logging/TEST_MAPPING b/ojluni/src/main/java/java/util/logging/TEST_MAPPING
new file mode 100644
index 0000000..85f4d2b
--- /dev/null
+++ b/ojluni/src/main/java/java/util/logging/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.logging.tests.java.util.logging"
+        },
+        {
+          "include-filter": "libcore.java.util.logging"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/logging/package.html b/ojluni/src/main/java/java/util/logging/package.html
index a4c71f4..cafcdad 100644
--- a/ojluni/src/main/java/java/util/logging/package.html
+++ b/ojluni/src/main/java/java/util/logging/package.html
@@ -116,7 +116,7 @@
 <P>
 For an overview of control flow, 
 please refer to the 
-<a href="https://docs.oracle.com/javase/8/docs/technotes/guides/logging/overview.html">
+<a href="../../../../technotes/guides/logging/overview.html">
 Java Logging Overview</a>.
 </P>
 
diff --git a/ojluni/src/main/java/java/util/package.html b/ojluni/src/main/java/java/util/package.html
index 8bb5efe..a655934 100644
--- a/ojluni/src/main/java/java/util/package.html
+++ b/ojluni/src/main/java/java/util/package.html
@@ -35,8 +35,8 @@
 
 <h2>Package Specification</h2>
 <ul>
-  <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html"><b>Collections Framework Overview</b></a>
-  <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/reference.html"><b>
+  <li><a href="../../../technotes/guides/collections/overview.html"><b>Collections Framework Overview</b></a>
+  <li><a href="../../../technotes/guides/collections/reference.html"><b>
        Collections Framework Annotated Outline</b></a>
 </ul>
 
@@ -46,7 +46,7 @@
     <li><a href="http://www.java.sun.com/docs/books/tutorial/collections/">
        <b>Collections Framework Tutorial</b></a>
     <li><a
-    href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/designfaq.html"><b>Collections
+    href="../../../technotes/guides/collections/designfaq.html"><b>Collections
     Framework Design FAQ</b></a>
 </ul>
 
diff --git a/ojluni/src/main/java/java/util/prefs/FileSystemPreferences.java b/ojluni/src/main/java/java/util/prefs/FileSystemPreferences.java
index 17c50a8..b888c4d 100644
--- a/ojluni/src/main/java/java/util/prefs/FileSystemPreferences.java
+++ b/ojluni/src/main/java/java/util/prefs/FileSystemPreferences.java
@@ -34,6 +34,7 @@
 
 import sun.util.logging.PlatformLogger;
 
+// Android-changed: @hide.
 /**
  * Preferences implementation for Unix.  Preferences are stored in the file
  * system, with one directory per preferences node.  All of the preferences
@@ -50,7 +51,6 @@
  *
  * @hide
  */
-// Android-changed: @hide.
 public class FileSystemPreferences extends AbstractPreferences {
     /**
      * Returns logger for error messages. Backing store exceptions are logged at
diff --git a/ojluni/src/main/java/java/util/prefs/TEST_MAPPING b/ojluni/src/main/java/java/util/prefs/TEST_MAPPING
new file mode 100644
index 0000000..3a3445b
--- /dev/null
+++ b/ojluni/src/main/java/java/util/prefs/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.java.util.prefs"
+        },
+        {
+          "include-filter": "libcore.java.util.prefs"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/regex/Matcher.java b/ojluni/src/main/java/java/util/regex/Matcher.java
index 38f8046..d50ea32 100644
--- a/ojluni/src/main/java/java/util/regex/Matcher.java
+++ b/ojluni/src/main/java/java/util/regex/Matcher.java
@@ -26,8 +26,7 @@
 
 package java.util.regex;
 
-import dalvik.annotation.optimization.ReachabilitySensitive;
-import libcore.util.NativeAllocationRegistry;
+import com.android.icu.util.regex.MatcherNative;
 
 /**
  * An engine that performs match operations on a {@linkplain java.lang.CharSequence
@@ -109,10 +108,6 @@
     /**
      * The Pattern object that created this Matcher.
      */
-    // Patterns also contain cleanup code and a ReachabilitySensitive field.
-    // This ensures that "this" and pattern remain reachable while we're using pattern.address
-    // directly.
-    @ReachabilitySensitive
     private Pattern parentPattern;
 
     /**
@@ -137,21 +132,7 @@
      */
     private boolean matchFound;
 
-    /**
-     * The address of the native peer.
-     * Uses of this must be manually synchronized to avoid native crashes.
-     */
-    @ReachabilitySensitive
-    private long address;
-
-    /**
-     * If non-null, a Runnable that can be used to explicitly deallocate address.
-     */
-    private Runnable nativeFinalizer;
-
-    private static final NativeAllocationRegistry registry =
-            NativeAllocationRegistry.createMalloced(Matcher.class.getClassLoader(),
-            getNativeFinalizer());
+    private MatcherNative nativeMatcher;
 
     /**
      * The index of the last position appended in a substitution.
@@ -227,17 +208,12 @@
     public Matcher usePattern(Pattern newPattern) {
         if (newPattern == null)
             throw new IllegalArgumentException("Pattern cannot be null");
-        parentPattern = newPattern;
 
         synchronized (this) {
-            if (nativeFinalizer != null) {
-                nativeFinalizer.run();
-                address = 0; // In case openImpl throws.
-                nativeFinalizer = null;
-            }
-            address = openImpl(parentPattern.address);
-            nativeFinalizer = registry.registerNativeAllocation(this, address);
+            // may throw
+            nativeMatcher = MatcherNative.create(newPattern.nativePattern);
         }
+        parentPattern = newPattern;
 
         if (text != null) {
             resetForInput();
@@ -533,7 +509,7 @@
      */
     public int groupCount() {
         synchronized (this) {
-            return groupCountImpl(address);
+            return nativeMatcher.groupCount();
         }
     }
 
@@ -548,7 +524,7 @@
      */
     public boolean matches() {
         synchronized (this) {
-            matchFound = matchesImpl(address, groups);
+            matchFound = nativeMatcher.matches(groups);
         }
         return matchFound;
     }
@@ -570,7 +546,7 @@
      */
     public boolean find() {
         synchronized (this) {
-            matchFound = findNextImpl(address, groups);
+            matchFound = nativeMatcher.findNext(groups);
         }
         return matchFound;
     }
@@ -600,7 +576,7 @@
             throw new IndexOutOfBoundsException("Illegal start index");
         reset();
         synchronized (this) {
-            matchFound = findImpl(address, start, groups);
+            matchFound = nativeMatcher.find(start, groups);
         }
         return matchFound;
     }
@@ -621,7 +597,7 @@
      */
     public boolean lookingAt() {
         synchronized (this) {
-            matchFound = lookingAtImpl(address, groups);
+            matchFound = nativeMatcher.lookingAt(groups);
         }
         return matchFound;
     }
@@ -764,16 +740,20 @@
                 escape = true;
             } else if (c == '$' && !escape) {
                 dollar = true;
-            } else if (c >= '0' && c <= '9' && dollar) {
-                buffer.append(group(c - '0'));
+            } else if (c >= '0' && c <= '9' && dollar && !escapeNamedGroup) {
+                String groupValue = group(c - '0');
+                if (groupValue != null) {
+                    buffer.append(groupValue);
+                }
                 dollar = false;
             } else if (c == '{' && dollar) {
                 escapeNamedGroup = true;
                 escapeNamedGroupStart = i;
             } else if (c == '}' && dollar && escapeNamedGroup) {
-                String namedGroupName =
-                    s.substring(escapeNamedGroupStart + 1, i);
-                buffer.append(group(namedGroupName));
+                String groupValue = group(s.substring(escapeNamedGroupStart + 1, i));
+                if (groupValue != null) {
+                    buffer.append(groupValue);
+                }
                 dollar = false;
                 escapeNamedGroup = false;
             } else if (c != '}' && dollar && escapeNamedGroup) {
@@ -1019,7 +999,7 @@
     public Matcher useTransparentBounds(boolean b) {
         synchronized (this) {
             transparentBounds = b;
-            useTransparentBoundsImpl(address, b);
+            nativeMatcher.useTransparentBounds(b);
         }
         return this;
     }
@@ -1068,7 +1048,7 @@
     public Matcher useAnchoringBounds(boolean b) {
         synchronized (this) {
             anchoringBounds = b;
-            useAnchoringBoundsImpl(address, b);
+            nativeMatcher.useAnchoringBounds(b);
         }
         return this;
     }
@@ -1108,7 +1088,7 @@
      */
     public boolean hitEnd() {
         synchronized (this) {
-            return hitEndImpl(address);
+            return nativeMatcher.hitEnd();
         }
     }
 
@@ -1128,7 +1108,7 @@
      */
     public boolean requireEnd() {
         synchronized (this) {
-            return requireEndImpl(address);
+            return nativeMatcher.requireEnd();
         }
     }
 
@@ -1191,9 +1171,9 @@
 
     private void resetForInput() {
         synchronized (this) {
-            setInputImpl(address, text, from, to);
-            useAnchoringBoundsImpl(address, anchoringBounds);
-            useTransparentBoundsImpl(address, transparentBounds);
+            nativeMatcher.setInput(text, from, to);
+            nativeMatcher.useAnchoringBounds(anchoringBounds);
+            nativeMatcher.useTransparentBounds(transparentBounds);
         }
     }
 
@@ -1212,7 +1192,7 @@
 
     private int getMatchedGroupIndex(String name) {
         ensureMatch();
-        int result = getMatchedGroupIndex0(parentPattern.address, name);
+        int result = nativeMatcher.getMatchedGroupIndex(name);
         if (result < 0) {
             throw new IllegalArgumentException("No capturing group in the pattern " +
                                                "with the name " + name);
@@ -1220,20 +1200,6 @@
         return result;
     }
 
-    private static native int getMatchedGroupIndex0(long patternAddr, String name);
-    private static native boolean findImpl(long addr, int startIndex, int[] offsets);
-    private static native boolean findNextImpl(long addr, int[] offsets);
-    private static native long getNativeFinalizer();
-    private static native int groupCountImpl(long addr);
-    private static native boolean hitEndImpl(long addr);
-    private static native boolean lookingAtImpl(long addr, int[] offsets);
-    private static native boolean matchesImpl(long addr, int[] offsets);
-    private static native long openImpl(long patternAddr);
-    private static native boolean requireEndImpl(long addr);
-    private static native void setInputImpl(long addr, String s, int start, int end);
-    private static native void useAnchoringBoundsImpl(long addr, boolean value);
-    private static native void useTransparentBoundsImpl(long addr, boolean value);
-
     /**
      * A trivial match result implementation that's based on an array of integers
      * representing match offsets. The array is of the form
diff --git a/ojluni/src/main/java/java/util/regex/Pattern.java b/ojluni/src/main/java/java/util/regex/Pattern.java
index 55a48de..a4ead58 100644
--- a/ojluni/src/main/java/java/util/regex/Pattern.java
+++ b/ojluni/src/main/java/java/util/regex/Pattern.java
@@ -26,11 +26,9 @@
 
 package java.util.regex;
 
-import dalvik.annotation.optimization.ReachabilitySensitive;
+import com.android.icu.util.regex.PatternNative;
 import dalvik.system.VMRuntime;
 
-import libcore.util.NativeAllocationRegistry;
-
 import java.util.Iterator;
 import java.util.ArrayList;
 import java.util.NoSuchElementException;
@@ -945,12 +943,7 @@
     // BEGIN Android-changed: reimplement matching logic natively via ICU.
     // We only need some tie-ins to native memory, instead of a large number
     // of fields on the .java side.
-    @ReachabilitySensitive
-    transient long address;
-
-    private static final NativeAllocationRegistry registry =
-            NativeAllocationRegistry.createMalloced(Pattern.class.getClassLoader(),
-            getNativeFinalizer());
+    /* package */ transient PatternNative nativePattern;
     // END Android-changed: reimplement matching logic natively via ICU.
 
     /**
@@ -1430,12 +1423,8 @@
         // These are the flags natively supported by ICU.
         // They even have the same value in native code.
         int icuFlags = flags & (CASE_INSENSITIVE | COMMENTS | MULTILINE | DOTALL | UNIX_LINES);
-        address = compileImpl(icuPattern, icuFlags);
-        registry.registerNativeAllocation(this, address);
+        nativePattern = PatternNative.create(icuPattern, icuFlags);
     }
-
-    private static native long compileImpl(String regex, int flags);
-    private static native long getNativeFinalizer();
     // END Android-changed: reimplement matching logic natively via ICU.
 
     /**
diff --git a/ojluni/src/main/java/java/util/regex/TEST_MAPPING b/ojluni/src/main/java/java/util/regex/TEST_MAPPING
new file mode 100644
index 0000000..1bd44e2
--- /dev/null
+++ b/ojluni/src/main/java/java/util/regex/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.regex.tests.java.util.regex"
+        },
+        {
+          "include-filter": "libcore.java.util.regex"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.util.regex"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/stream/TEST_MAPPING b/ojluni/src/main/java/java/util/stream/TEST_MAPPING
new file mode 100644
index 0000000..9673e09
--- /dev/null
+++ b/ojluni/src/main/java/java/util/stream/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreOjTestCases",
+      "options": [
+        {
+          "include-filter": "java.util.stream"
+        },
+        {
+          "include-filter": "org.openjdk.tests.java.util.stream"
+        },
+        {
+          "include-filter": "org.openjdk.testlib.java.util.stream"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/zip/TEST_MAPPING b/ojluni/src/main/java/java/util/zip/TEST_MAPPING
new file mode 100644
index 0000000..52ac932
--- /dev/null
+++ b/ojluni/src/main/java/java/util/zip/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.java.util.zip"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.java.util.zip"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/java/util/zip/ZipInputStream.java b/ojluni/src/main/java/java/util/zip/ZipInputStream.java
index 0413f47..aaebb49 100644
--- a/ojluni/src/main/java/java/util/zip/ZipInputStream.java
+++ b/ojluni/src/main/java/java/util/zip/ZipInputStream.java
@@ -323,11 +323,16 @@
         e.method = get16(tmpbuf, LOCHOW);
         e.xdostime = get32(tmpbuf, LOCTIM);
         if ((flag & 8) == 8) {
-            /* "Data Descriptor" present */
-            if (e.method != DEFLATED) {
-                throw new ZipException(
-                        "only DEFLATED entries can have EXT descriptor");
-            }
+            // Android-Changed: Remove the requirement that only DEFLATED entries
+            // can have data descriptors. This is not required by the ZIP spec and
+            // is inconsistent with the behaviour of ZipFile and versions of Android
+            // prior to Android N.
+            //
+            // /* "Data Descriptor" present */
+            // if (e.method != DEFLATED) {
+            //     throw new ZipException(
+            //             "only DEFLATED entries can have EXT descriptor");
+            // }
         } else {
             e.crc = get32(tmpbuf, LOCCRC);
             e.csize = get32(tmpbuf, LOCSIZ);
diff --git a/ojluni/src/main/java/javax/crypto/Cipher.java b/ojluni/src/main/java/javax/crypto/Cipher.java
index a872317..7968f2f 100644
--- a/ojluni/src/main/java/javax/crypto/Cipher.java
+++ b/ojluni/src/main/java/javax/crypto/Cipher.java
@@ -242,7 +242,7 @@
  * </table>
  *
  * These transformations are described in the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
+ * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
  * Cipher section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -597,7 +597,7 @@
      * @param transformation the name of the transformation, e.g.,
      * <i>DES/CBC/PKCS5Padding</i>.
      * See the Cipher section in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard transformation names.
      *
@@ -634,7 +634,7 @@
      * @param transformation the name of the transformation,
      * e.g., <i>DES/CBC/PKCS5Padding</i>.
      * See the Cipher section in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard transformation names.
      *
@@ -686,7 +686,7 @@
      * @param transformation the name of the transformation,
      * e.g., <i>DES/CBC/PKCS5Padding</i>.
      * See the Cipher section in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard transformation names.
      *
@@ -2477,7 +2477,7 @@
      * For more information on default key size in JCE jurisdiction
      * policy files, please see Appendix E in the
      * <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppC">
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppC">
      * Java Cryptography Architecture Reference Guide</a>.
      *
      * @param transformation the cipher transformation.
diff --git a/ojluni/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java b/ojluni/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
index b8bf169..5eeb481 100644
--- a/ojluni/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
+++ b/ojluni/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java
@@ -115,7 +115,7 @@
      *
      * @param algName encryption algorithm name. See Appendix A in the
      * <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      * Java Cryptography Architecture Reference Guide</a>
      * for information about standard Cipher algorithm names.
      * @param encryptedData encrypted data. The contents of
@@ -198,7 +198,7 @@
      * in the constructor when such mapping is available.
      * See Appendix A in the
      * <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      * Java Cryptography Architecture Reference Guide</a>
      * for information about standard Cipher algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/crypto/ExemptionMechanism.java b/ojluni/src/main/java/javax/crypto/ExemptionMechanism.java
index f991a66..b90ab43 100644
--- a/ojluni/src/main/java/javax/crypto/ExemptionMechanism.java
+++ b/ojluni/src/main/java/javax/crypto/ExemptionMechanism.java
@@ -116,7 +116,7 @@
      * mechanism.
      * See the ExemptionMechanism section in the
      * <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Exemption">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard exemption mechanism names.
      *
@@ -155,7 +155,7 @@
      * @param algorithm the standard name of the requested exemption mechanism.
      * See the ExemptionMechanism section in the
      * <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Exemption">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard exemption mechanism names.
      *
@@ -199,7 +199,7 @@
      * @param algorithm the standard name of the requested exemption mechanism.
      * See the ExemptionMechanism section in the
      * <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Exemption">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard exemption mechanism names.
      *
diff --git a/ojluni/src/main/java/javax/crypto/KeyAgreement.java b/ojluni/src/main/java/javax/crypto/KeyAgreement.java
index f6decbc..fd79680 100644
--- a/ojluni/src/main/java/javax/crypto/KeyAgreement.java
+++ b/ojluni/src/main/java/javax/crypto/KeyAgreement.java
@@ -75,7 +75,7 @@
  * </table>
  *
  * This algorithm is described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyAgreement">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
  * KeyAgreement section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -177,7 +177,7 @@
      * @param algorithm the standard name of the requested key agreement
      * algorithm.
      * See the KeyAgreement section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyAgreement">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -226,7 +226,7 @@
      * @param algorithm the standard name of the requested key agreement
      * algorithm.
      * See the KeyAgreement section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyAgreement">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -272,7 +272,7 @@
      * @param algorithm the standard name of the requested key agreement
      * algorithm.
      * See the KeyAgreement section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyAgreement">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/crypto/KeyGenerator.java b/ojluni/src/main/java/javax/crypto/KeyGenerator.java
index 0b30338..5951eef 100644
--- a/ojluni/src/main/java/javax/crypto/KeyGenerator.java
+++ b/ojluni/src/main/java/javax/crypto/KeyGenerator.java
@@ -156,7 +156,7 @@
  * </table>
  *
  * These algorithms are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyGenerator">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
  * KeyGenerator section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -272,7 +272,7 @@
      *
      * @param algorithm the standard name of the requested key algorithm.
      * See the KeyGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -305,7 +305,7 @@
      *
      * @param algorithm the standard name of the requested key algorithm.
      * See the KeyGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -349,7 +349,7 @@
      *
      * @param algorithm the standard name of the requested key algorithm.
      * See the KeyGenerator section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyGenerator">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/crypto/Mac.java b/ojluni/src/main/java/javax/crypto/Mac.java
index 749b627..f70a697 100644
--- a/ojluni/src/main/java/javax/crypto/Mac.java
+++ b/ojluni/src/main/java/javax/crypto/Mac.java
@@ -142,7 +142,7 @@
  * </table>
  *
  * These algorithms are described in the
- * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Mac">
+ * <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
  * Mac section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -243,7 +243,7 @@
      *
      * @param algorithm the standard name of the requested MAC algorithm.
      * See the Mac section in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Mac">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -287,7 +287,7 @@
      *
      * @param algorithm the standard name of the requested MAC algorithm.
      * See the Mac section in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Mac">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -327,7 +327,7 @@
      *
      * @param algorithm the standard name of the requested MAC algorithm.
      * See the Mac section in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Mac">
+     *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/crypto/SecretKeyFactory.java b/ojluni/src/main/java/javax/crypto/SecretKeyFactory.java
index 659df8d..bd8b271 100644
--- a/ojluni/src/main/java/javax/crypto/SecretKeyFactory.java
+++ b/ojluni/src/main/java/javax/crypto/SecretKeyFactory.java
@@ -251,7 +251,7 @@
  * </table>
  *
  * These algorithms are described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecretKeyFactory">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
  * SecretKeyFactory section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -324,7 +324,7 @@
      * @param algorithm the standard name of the requested secret-key
      * algorithm.
      * See the SecretKeyFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecretKeyFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -359,7 +359,7 @@
      * @param algorithm the standard name of the requested secret-key
      * algorithm.
      * See the SecretKeyFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecretKeyFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
@@ -405,7 +405,7 @@
      * @param algorithm the standard name of the requested secret-key
      * algorithm.
      * See the SecretKeyFactory section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SecretKeyFactory">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">
      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/crypto/TEST_MAPPING b/ojluni/src/main/java/javax/crypto/TEST_MAPPING
new file mode 100644
index 0000000..6860a5c
--- /dev/null
+++ b/ojluni/src/main/java/javax/crypto/TEST_MAPPING
@@ -0,0 +1,24 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.crypto.tests.javax.crypto"
+        },
+        {
+          "include-filter": "org.apache.harmony.crypto.tests.javax.crypto.func"
+        },
+        {
+          "include-filter": "libcore.javax.crypto"
+        },
+        {
+          "include-filter": "com.android.org.conscrypt.javax.crypto"
+        },
+        {
+          "include-filter": "org.apache.harmony.crypto.tests.javax.crypto.serialization"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/crypto/interfaces/TEST_MAPPING b/ojluni/src/main/java/javax/crypto/interfaces/TEST_MAPPING
new file mode 100644
index 0000000..427bf79
--- /dev/null
+++ b/ojluni/src/main/java/javax/crypto/interfaces/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.crypto.tests.javax.crypto.interfaces"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/crypto/interfaces/package.html b/ojluni/src/main/java/javax/crypto/interfaces/package.html
index 75ef6fe..8b18ce2 100644
--- a/ojluni/src/main/java/javax/crypto/interfaces/package.html
+++ b/ojluni/src/main/java/javax/crypto/interfaces/package.html
@@ -46,7 +46,7 @@
 cryptographic provider developer guide:
 <ul>
   <li><a href=
-    "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
+    "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
     <b>How to Implement a Provider for the
     Java<FONT SIZE=-2><SUP>TM</SUP></FONT> Cryptography Architecture
     </b></a></li>
@@ -65,7 +65,7 @@
 <ul>
   <li>
     <a href=
-      "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+      "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
       <b>Java<FONT SIZE=-2><SUP>TM</SUP></FONT>
       Cryptography Architecture API Specification and Reference
       </b></a></li>
diff --git a/ojluni/src/main/java/javax/crypto/package.html b/ojluni/src/main/java/javax/crypto/package.html
index bd4c05a..1518573 100644
--- a/ojluni/src/main/java/javax/crypto/package.html
+++ b/ojluni/src/main/java/javax/crypto/package.html
@@ -47,7 +47,7 @@
 <h2>Package Specification</h2>
 
 <ul>
-  <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html"><b>
+  <li><a href="{@docRoot}/../technotes/guides/security/StandardNames.html"><b>
     <b>Java<FONT SIZE=-2><SUP>TM</SUP></FONT>
     Cryptography Architecture Standard Algorithm Name
     Documentation</b></a></li>
@@ -59,13 +59,13 @@
 <ul>
   <li>
     <a href=
-      "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+      "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
       <b>Java<FONT SIZE=-2><SUP>TM</SUP></FONT>
        Cryptography Architecture (JCA) Reference Guide
       </b></a></li>
   <li>
     <a href=
-      "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
+      "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
       <b>How to Implement a Provider in the
       Java<FONT SIZE=-2><SUP>TM</SUP></FONT> Cryptography Architecture
       </b></a></li>
diff --git a/ojluni/src/main/java/javax/crypto/spec/SecretKeySpec.java b/ojluni/src/main/java/javax/crypto/spec/SecretKeySpec.java
index ff1258c..767c0d2 100644
--- a/ojluni/src/main/java/javax/crypto/spec/SecretKeySpec.java
+++ b/ojluni/src/main/java/javax/crypto/spec/SecretKeySpec.java
@@ -82,7 +82,7 @@
      * @param algorithm the name of the secret-key algorithm to be associated
      * with the given key material.
      * See Appendix A in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      * Java Cryptography Architecture Reference Guide</a>
      * for information about standard algorithm names.
      * @exception IllegalArgumentException if <code>algorithm</code>
@@ -127,7 +127,7 @@
      * @param algorithm the name of the secret-key algorithm to be associated
      * with the given key material.
      * See Appendix A in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      * Java Cryptography Architecture Reference Guide</a>
      * for information about standard algorithm names.
      * @exception IllegalArgumentException if <code>algorithm</code>
diff --git a/ojluni/src/main/java/javax/crypto/spec/TEST_MAPPING b/ojluni/src/main/java/javax/crypto/spec/TEST_MAPPING
new file mode 100644
index 0000000..d1e9d5a
--- /dev/null
+++ b/ojluni/src/main/java/javax/crypto/spec/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.crypto.tests.javax.crypto.spec"
+        },
+        {
+          "include-filter": "libcore.javax.crypto.spec"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/crypto/spec/package.html b/ojluni/src/main/java/javax/crypto/spec/package.html
index 3e30aa1..b8fd807 100644
--- a/ojluni/src/main/java/javax/crypto/spec/package.html
+++ b/ojluni/src/main/java/javax/crypto/spec/package.html
@@ -61,13 +61,13 @@
 <ul>
   <li>
     <a href=
-      "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html">
+      "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
       <b>Java<FONT SIZE=-2><SUP>TM</SUP></FONT>
       Cryptography Architecture API Specification and Reference
       </b></a></li>
   <li>
     <a href=
-      "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/HowToImplAProvider.html">
+      "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
       <b>How to Implement a Provider for the
       Java<FONT SIZE=-2><SUP>TM</SUP></FONT> Cryptography Architecture
       </b></a></li>
diff --git a/ojluni/src/main/java/javax/net/TEST_MAPPING b/ojluni/src/main/java/javax/net/TEST_MAPPING
new file mode 100644
index 0000000..aeabde8
--- /dev/null
+++ b/ojluni/src/main/java/javax/net/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.javax.net"
+        },
+        {
+          "include-filter": "libcore.javax.net"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/net/ssl/ExtendedSSLSession.java b/ojluni/src/main/java/javax/net/ssl/ExtendedSSLSession.java
index 2d832f3..70f98ce 100644
--- a/ojluni/src/main/java/javax/net/ssl/ExtendedSSLSession.java
+++ b/ojluni/src/main/java/javax/net/ssl/ExtendedSSLSession.java
@@ -45,7 +45,7 @@
      * The signature algorithm name must be a standard Java Security
      * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
      * See Appendix A in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      * Java Cryptography Architecture API Specification &amp; Reference </a>
      * for information about standard algorithm names.
      * <p>
@@ -73,7 +73,7 @@
      * The signature algorithm name must be a standard Java Security
      * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
      * See Appendix A in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      * Java Cryptography Architecture API Specification &amp; Reference </a>
      * for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java b/ojluni/src/main/java/javax/net/ssl/HttpsURLConnection.java
index 143fa5e..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,9 +187,10 @@
      * 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;
-        public static final Class<? extends HostnameVerifier> originalDefaultHostnameVerifierClass;
         static {
             try {
                 /**
@@ -198,9 +200,8 @@
                   * 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);
-                originalDefaultHostnameVerifierClass = defaultHostnameVerifier.getClass();
             } catch (Exception e) {
                 throw new AssertionError("Failed to obtain okhttp HostnameVerifier", e);
             }
@@ -210,7 +211,7 @@
     /**
      * The <code>hostnameVerifier</code> for this object.
      */
-    protected HostnameVerifier hostnameVerifier;
+    protected HostnameVerifier hostnameVerifier = NoPreloadHolder.defaultHostnameVerifier;
     // END Android-changed: Use holder class idiom for a lazily-created OkHttp hostname verifier.
 
     // Android-changed: Modified the documentation to explain side effects / discourage method use.
@@ -321,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.
      *
@@ -329,15 +354,6 @@
      * @see #setDefaultHostnameVerifier(HostnameVerifier)
      */
     public HostnameVerifier getHostnameVerifier() {
-        // Android-added: Use the default verifier if none is set.
-        // Note that this also has the side effect of *setting* (if unset)
-        // hostnameVerifier to be the default one. It's not clear why this
-        // was done (commit abd00f0eaa46f71f98e75a631c268c812d1ec7c1) but
-        // we're keeping this behavior for lack of a strong reason to do
-        // otherwise.
-        if (hostnameVerifier == null) {
-            hostnameVerifier = NoPreloadHolder.defaultHostnameVerifier;
-        }
         return hostnameVerifier;
     }
 
diff --git a/ojluni/src/main/java/javax/net/ssl/KeyManagerFactory.java b/ojluni/src/main/java/javax/net/ssl/KeyManagerFactory.java
index 04af51a..7ae790c 100644
--- a/ojluni/src/main/java/javax/net/ssl/KeyManagerFactory.java
+++ b/ojluni/src/main/java/javax/net/ssl/KeyManagerFactory.java
@@ -134,7 +134,7 @@
      *
      * @param algorithm the standard name of the requested algorithm.
      *          See the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html">
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
      *          Java Secure Socket Extension Reference Guide </a>
      *          for information about standard algorithm names.
      *
@@ -170,7 +170,7 @@
 
      * @param algorithm the standard name of the requested algorithm.
      *          See the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html">
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
      *          Java Secure Socket Extension Reference Guide </a>
      *          for information about standard algorithm names.
      *
@@ -211,7 +211,7 @@
      *
      * @param algorithm the standard name of the requested algorithm.
      *          See the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html">
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
      *          Java Secure Socket Extension Reference Guide </a>
      *          for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLContext.java b/ojluni/src/main/java/javax/net/ssl/SSLContext.java
index b580a72..eb7322c 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLContext.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLContext.java
@@ -82,7 +82,7 @@
  * </table>
  *
  * This protocol is described in the <a href=
- * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SSLContext">
  * SSLContext section</a> of the
  * Java Cryptography Architecture Standard Algorithm Name Documentation.
  *
@@ -180,7 +180,7 @@
      *
      * @param protocol the standard name of the requested protocol.
      *          See the SSLContext section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SSLContext">
      *          Java Cryptography Architecture Standard Algorithm Name
      *          Documentation</a>
      *          for information about standard protocol names.
@@ -216,7 +216,7 @@
      *
      * @param protocol the standard name of the requested protocol.
      *          See the SSLContext section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SSLContext">
      *          Java Cryptography Architecture Standard Algorithm Name
      *          Documentation</a>
      *          for information about standard protocol names.
@@ -256,7 +256,7 @@
      *
      * @param protocol the standard name of the requested protocol.
      *          See the SSLContext section in the <a href=
-     * "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext">
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SSLContext">
      *          Java Cryptography Architecture Standard Algorithm Name
      *          Documentation</a>
      *          for information about standard protocol names.
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLParameters.java b/ojluni/src/main/java/javax/net/ssl/SSLParameters.java
index 41dcf0f..1b9b3fb 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLParameters.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLParameters.java
@@ -257,7 +257,7 @@
      *
      * @param algorithm The standard string name of the endpoint
      *     identification algorithm (or null).  See Appendix A in the <a href=
-     *   "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
      *     Java Cryptography Architecture API Specification &amp; Reference </a>
      *     for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/net/ssl/TEST_MAPPING b/ojluni/src/main/java/javax/net/ssl/TEST_MAPPING
new file mode 100644
index 0000000..d3ae570
--- /dev/null
+++ b/ojluni/src/main/java/javax/net/ssl/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.javax.net.ssl"
+        },
+        {
+          "include-filter": "com.android.org.conscrypt.javax.net.ssl"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.javax.net.ssl"
+        },
+        {
+          "include-filter": "org.apache.harmony.luni.tests.internal.net.www.protocol.https"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/net/ssl/TrustManagerFactory.java b/ojluni/src/main/java/javax/net/ssl/TrustManagerFactory.java
index 7322169..d76f5fb 100644
--- a/ojluni/src/main/java/javax/net/ssl/TrustManagerFactory.java
+++ b/ojluni/src/main/java/javax/net/ssl/TrustManagerFactory.java
@@ -136,7 +136,7 @@
      *
      * @param algorithm the standard name of the requested trust management
      *          algorithm.  See the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html">
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
      *          Java Secure Socket Extension Reference Guide </a>
      *          for information about standard algorithm names.
      *
@@ -172,7 +172,7 @@
      *
      * @param algorithm the standard name of the requested trust management
      *          algorithm.  See the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html">
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
      *          Java Secure Socket Extension Reference Guide </a>
      *          for information about standard algorithm names.
      *
@@ -213,7 +213,7 @@
      *
      * @param algorithm the standard name of the requested trust management
      *          algorithm.  See the <a href=
-     *  "https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html">
+     *  "{@docRoot}/../technotes/guides/security/jsse/JSSERefGuide.html">
      *          Java Secure Socket Extension Reference Guide </a>
      *          for information about standard algorithm names.
      *
diff --git a/ojluni/src/main/java/javax/net/ssl/package.html b/ojluni/src/main/java/javax/net/ssl/package.html
index 0f87f45..5213137 100644
--- a/ojluni/src/main/java/javax/net/ssl/package.html
+++ b/ojluni/src/main/java/javax/net/ssl/package.html
@@ -37,7 +37,7 @@
 <h2>Package Specification</h2>
 
 <ul>
-  <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">
+  <li><a href="{@docRoot}/../technotes/guides/security/StandardNames.html">
     <b>Java<FONT SIZE=-2><SUP>TM</SUP></FONT>
     Cryptography Architecture Standard Algorithm Name
     Documentation</b></a></li>
diff --git a/ojluni/src/main/java/javax/security/auth/TEST_MAPPING b/ojluni/src/main/java/javax/security/auth/TEST_MAPPING
new file mode 100644
index 0000000..45bd9c7
--- /dev/null
+++ b/ojluni/src/main/java/javax/security/auth/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.javax.security.auth"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/security/auth/callback/TEST_MAPPING b/ojluni/src/main/java/javax/security/auth/callback/TEST_MAPPING
new file mode 100644
index 0000000..e742b17
--- /dev/null
+++ b/ojluni/src/main/java/javax/security/auth/callback/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.javax.security.auth.callback"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/security/auth/login/TEST_MAPPING b/ojluni/src/main/java/javax/security/auth/login/TEST_MAPPING
new file mode 100644
index 0000000..a22e2b3
--- /dev/null
+++ b/ojluni/src/main/java/javax/security/auth/login/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.javax.security.auth.login"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/security/auth/login/package-info.java b/ojluni/src/main/java/javax/security/auth/login/package-info.java
index 6bb5a06..5b43480 100644
--- a/ojluni/src/main/java/javax/security/auth/login/package-info.java
+++ b/ojluni/src/main/java/javax/security/auth/login/package-info.java
@@ -28,7 +28,7 @@
  * <h2>Package Specification</h2>
  *
  * <ul>
- *   <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">
+ *   <li><a href="{@docRoot}/../technotes/guides/security/StandardNames.html">
  *     <b>Java&trade;
  *     Cryptography Architecture Standard Algorithm Name
  *     Documentation</b></a></li>
diff --git a/ojluni/src/main/java/javax/security/auth/x500/TEST_MAPPING b/ojluni/src/main/java/javax/security/auth/x500/TEST_MAPPING
new file mode 100644
index 0000000..3ba13da
--- /dev/null
+++ b/ojluni/src/main/java/javax/security/auth/x500/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.javax.security.auth.x500"
+        },
+        {
+          "include-filter": "org.apache.harmony.tests.javax.security.auth.x500"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/security/cert/TEST_MAPPING b/ojluni/src/main/java/javax/security/cert/TEST_MAPPING
new file mode 100644
index 0000000..4603638
--- /dev/null
+++ b/ojluni/src/main/java/javax/security/cert/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.javax.security.cert"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/javax/sql/TEST_MAPPING b/ojluni/src/main/java/javax/sql/TEST_MAPPING
new file mode 100644
index 0000000..bbbb56c
--- /dev/null
+++ b/ojluni/src/main/java/javax/sql/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.javax.sql"
+        },
+        {
+          "include-filter": "org.apache.harmony.sql.tests.javax.sql"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
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/ojluni/src/main/java/sun/invoke/util/TEST_MAPPING b/ojluni/src/main/java/sun/invoke/util/TEST_MAPPING
new file mode 100644
index 0000000..48ae161
--- /dev/null
+++ b/ojluni/src/main/java/sun/invoke/util/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.sun.invoke.util"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/sun/misc/TEST_MAPPING b/ojluni/src/main/java/sun/misc/TEST_MAPPING
new file mode 100644
index 0000000..f0d2cec
--- /dev/null
+++ b/ojluni/src/main/java/sun/misc/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "org.apache.harmony.tests.org.apache.harmony.kernel.dalvik"
+        },
+        {
+          "include-filter": "libcore.sun.misc"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/sun/net/util/TEST_MAPPING b/ojluni/src/main/java/sun/net/util/TEST_MAPPING
new file mode 100644
index 0000000..068b5da
--- /dev/null
+++ b/ojluni/src/main/java/sun/net/util/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.sun.net.util"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
index 49ad55c..c680c9c 100644
--- a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
@@ -237,6 +237,18 @@
                     if (index == -1)
                         throw new IOException("Network interface cannot be identified");
                     Net.setInterface6(fd, index);
+                    // BEGIN Android-added: Apply IP_MULTICAST_IF to dual-stack sockets.
+                    // On dual-stack sockets, IP_MULTICAST_IF sets inet_sk(sk)->mc_index and
+                    // inet_sk(sk)->mc_addr, which are specific to IPv4, and IPV6_MULTICAST_IF sets
+                    // inet6_sk(sk)->mcast_oif, which are specific to IPv6. For IPv4 multicast
+                    // traffic to work over an interface that is not the default, we need to
+                    // configure both. http://b/144222142
+                    Inet4Address target = Net.anyInet4Address(interf);
+                    if (target != null) {
+                        int targetAddress = Net.inet4AsInt(target);
+                        Net.setInterface4(fd, targetAddress);
+                    }
+                    // END Android-added: Apply IP_MULTICAST_IF to dual-stack sockets.
                 } else {
                     // need IPv4 address to identify interface
                     Inet4Address target = Net.anyInet4Address(interf);
diff --git a/ojluni/src/main/java/sun/nio/fs/MimeTypesFileTypeDetector.java b/ojluni/src/main/java/sun/nio/fs/MimeTypesFileTypeDetector.java
index 1c8f708..585b673 100644
--- a/ojluni/src/main/java/sun/nio/fs/MimeTypesFileTypeDetector.java
+++ b/ojluni/src/main/java/sun/nio/fs/MimeTypesFileTypeDetector.java
@@ -37,7 +37,7 @@
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import libcore.net.MimeUtils;
+import libcore.content.type.MimeMap;
 
 /**
  * File type detector that uses a file extension to look up its MIME type
@@ -46,7 +46,7 @@
 
 class MimeTypesFileTypeDetector extends AbstractFileTypeDetector {
 
-    // BEGIN Android-removed: Delegate to libcore.net.MimeUtils.
+    // BEGIN Android-removed: Delegate to libcore.content.type.MimeMap.
     /*
     // path to mime.types file
     private final Path mimeTypesFile;
@@ -61,7 +61,7 @@
         mimeTypesFile = filePath;
     }
     */
-    // END Android-removed: Delegate to libcore.net.MimeUtils.
+    // END Android-removed: Delegate to libcore.content.type.MimeMap.
 
 
     @Override
@@ -74,7 +74,7 @@
         if (ext.isEmpty())
             return null;  // no extension
 
-        // Android-removed: Delegate to libcore.net.MimeUtils.
+        // Android-removed: Delegate to libcore.content.type.MimeMap.
         // loadMimeTypes();
         // if (mimeTypeMap == null || mimeTypeMap.isEmpty())
         //    return null;
@@ -82,10 +82,10 @@
         // Case-sensitive search
         String mimeType;
         do {
-            // BEGIN Android-changed: Delegate to libcore.net.MimeUtils.
+            // BEGIN Android-changed: Delegate to libcore.content.type.MimeMap.
             // mimeType = mimeTypeMap.get(ext);
-            mimeType = MimeUtils.guessMimeTypeFromExtension(ext);
-            // END Android-changed: Delegate to libcore.net.MimeUtils.
+            mimeType = MimeMap.getDefault().guessMimeTypeFromExtension(ext);
+            // END Android-changed: Delegate to libcore.content.type.MimeMap.
             if (mimeType == null)
                 ext = getExtension(ext);
         } while (mimeType == null && !ext.isEmpty());
@@ -105,7 +105,7 @@
         return ext;
     }
 
-    // BEGIN Android-removed: Delegate to libcore.net.MimeUtils.
+    // BEGIN Android-removed: Delegate to libcore.content.type.MimeMap.
     /*
     /**
      * Parse the mime types file, and store the type-extension mappings into
@@ -218,5 +218,5 @@
         }
     }
     */
-    // END Android-removed: Delegate to libcore.net.MimeUtils.
+    // END Android-removed: Delegate to libcore.content.type.MimeMap.
 }
diff --git a/ojluni/src/main/java/sun/nio/fs/UnixChannelFactory.java b/ojluni/src/main/java/sun/nio/fs/UnixChannelFactory.java
index c6f074e..9491fd9 100644
--- a/ojluni/src/main/java/sun/nio/fs/UnixChannelFactory.java
+++ b/ojluni/src/main/java/sun/nio/fs/UnixChannelFactory.java
@@ -47,6 +47,13 @@
     private static final JavaIOFileDescriptorAccess fdAccess =
         SharedSecrets.getJavaIOFileDescriptorAccess();
 
+    static {
+        // b/151107960. This class is on the preloaded-classes-blacklist.
+        // It would be instantiated during AOT now without this magic
+        // function call and consequently fail 'atest PreloadCheck'.
+        dalvik.system.VMRuntime.doNotInitializeInAot();
+    }
+
     protected UnixChannelFactory() {
     }
 
diff --git a/ojluni/src/main/java/sun/reflect/CallerSensitive.java b/ojluni/src/main/java/sun/reflect/CallerSensitive.java
index 0c78da0..41d6fd4 100644
--- a/ojluni/src/main/java/sun/reflect/CallerSensitive.java
+++ b/ojluni/src/main/java/sun/reflect/CallerSensitive.java
@@ -28,6 +28,7 @@
 import java.lang.annotation.*;
 import static java.lang.annotation.ElementType.*;
 
+// Android-added: @hide; CallerSensitive is used in source but not part of the public API
 /**
  * A method annotated @CallerSensitive is sensitive to its calling class,
  * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass},
@@ -37,7 +38,6 @@
  *
  * @hide
  */
-// Android-added @hide
 @Retention(RetentionPolicy.RUNTIME)
 @Target({METHOD})
 public @interface CallerSensitive {
diff --git a/ojluni/src/main/java/sun/security/jca/TEST_MAPPING b/ojluni/src/main/java/sun/security/jca/TEST_MAPPING
new file mode 100644
index 0000000..02e5a74
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/jca/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.sun.security.jca"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/sun/security/pkcs/TEST_MAPPING b/ojluni/src/main/java/sun/security/pkcs/TEST_MAPPING
new file mode 100644
index 0000000..3f37df7
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/pkcs/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.sun.security.pkcs"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/sun/security/x509/TEST_MAPPING b/ojluni/src/main/java/sun/security/x509/TEST_MAPPING
new file mode 100644
index 0000000..92012a6
--- /dev/null
+++ b/ojluni/src/main/java/sun/security/x509/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.sun.security.x509"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/java/sun/util/logging/TEST_MAPPING b/ojluni/src/main/java/sun/util/logging/TEST_MAPPING
new file mode 100644
index 0000000..e3bb92a
--- /dev/null
+++ b/ojluni/src/main/java/sun/util/logging/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.sun.util.logging"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ojluni/src/main/native/Android.bp b/ojluni/src/main/native/Android.bp
index 38a2a23..45a5c98 100644
--- a/ojluni/src/main/native/Android.bp
+++ b/ojluni/src/main/native/Android.bp
@@ -1,5 +1,22 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 filegroup {
     name: "libopenjdk_native_srcs",
+    visibility: [
+        "//libcore",
+    ],
     srcs: [
         "ZipFile.c",
         "Inflater.c",
@@ -20,7 +37,6 @@
         "SocketChannelImpl.c",
         "FileChannelImpl.c",
         "FileDispatcherImpl.c",
-        "FileOutputStream_md.c",
         "FileInputStream.c",
         "FileSystemPreferences.c",
         "EPoll.c",
diff --git a/ojluni/src/main/native/FileInputStream.c b/ojluni/src/main/native/FileInputStream.c
index 58664a1..650cb6c 100644
--- a/ojluni/src/main/native/FileInputStream.c
+++ b/ojluni/src/main/native/FileInputStream.c
@@ -62,10 +62,15 @@
     fis_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;");
 }
 
+// BEGIN Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+// http://b/112107427
+/*
 JNIEXPORT void JNICALL
 FileInputStream_open0(JNIEnv *env, jobject this, jstring path) {
     fileOpen(env, this, path, fis_fd, O_RDONLY);
 }
+*/
+// END Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
 
 JNIEXPORT jlong JNICALL
 FileInputStream_skip0(JNIEnv *env, jobject this, jlong toSkip) {
@@ -141,7 +146,6 @@
 }
 
 static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(FileInputStream, open0, "(Ljava/lang/String;)V"),
   NATIVE_METHOD(FileInputStream, skip0, "(J)J"),
   NATIVE_METHOD(FileInputStream, available0, "()I"),
 };
diff --git a/ojluni/src/main/native/FileOutputStream_md.c b/ojluni/src/main/native/FileOutputStream_md.c
deleted file mode 100644
index 73218d4..0000000
--- a/ojluni/src/main/native/FileOutputStream_md.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-
-#include "io_util.h"
-#include "io_util_md.h"
-
-#include <fcntl.h>
-#include <nativehelper/JNIHelp.h>
-
-#define NATIVE_METHOD(className, functionName, signature) \
-{ #functionName, signature, (void*)(className ## _ ## functionName) }
-
-/*******************************************************************/
-/*  BEGIN JNI ********* BEGIN JNI *********** BEGIN JNI ************/
-/*******************************************************************/
-
-jfieldID fos_fd; /* id for jobject 'fd' in java.io.FileOutputStream */
-
-/**************************************************************
- * Output stream
- */
-static void FileOutputStream_initIDs(JNIEnv *env) {
-    jclass clazz = (*env)->FindClass(env, "java/io/FileOutputStream");
-    fos_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;");
-}
-
-
-JNIEXPORT void JNICALL
-FileOutputStream_open0(JNIEnv *env, jobject this,
-                                   jstring path, jboolean append) {
-    fileOpen(env, this, path, fos_fd,
-             O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC));
-}
-
-static JNINativeMethod gMethods[] = {
-  NATIVE_METHOD(FileOutputStream, open0, "(Ljava/lang/String;Z)V"),
-};
-
-void register_java_io_FileOutputStream(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "java/io/FileOutputStream", gMethods, NELEM(gMethods));
-    FileOutputStream_initIDs(env);
-}
diff --git a/ojluni/src/main/native/OnLoad.cpp b/ojluni/src/main/native/OnLoad.cpp
index ab13939..f0b8566 100644
--- a/ojluni/src/main/native/OnLoad.cpp
+++ b/ojluni/src/main/native/OnLoad.cpp
@@ -35,7 +35,6 @@
 extern "C" void register_sun_nio_ch_SocketChannelImpl(JNIEnv* env);
 extern "C" void register_sun_nio_ch_FileChannelImpl(JNIEnv* env);
 extern "C" void register_sun_nio_ch_FileDispatcherImpl(JNIEnv* env);
-extern "C" void register_java_io_FileOutputStream(JNIEnv* env);
 extern "C" void register_java_io_FileInputStream(JNIEnv* env);
 extern "C" void register_java_util_prefs_FileSystemPreferences(JNIEnv* env);
 extern "C" void register_sun_nio_ch_NativeThread(JNIEnv* env);
@@ -104,7 +103,6 @@
   register_sun_nio_ch_SocketChannelImpl(env);
   register_sun_nio_ch_FileChannelImpl(env);
   register_sun_nio_ch_FileDispatcherImpl(env);
-  register_java_io_FileOutputStream(env);
   register_java_io_FileInputStream(env);
   register_java_util_prefs_FileSystemPreferences(env);
   register_sun_nio_ch_NativeThread(env);
diff --git a/ojluni/src/main/native/Register.cpp b/ojluni/src/main/native/Register.cpp
deleted file mode 100644
index c550c76..0000000
--- a/ojluni/src/main/native/Register.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#define LOG_TAG "libcore" // We'll be next to "dalvikvm" in the log; make the distinction clear.
-
-#include <stdlib.h>
-
-#include <log/log.h>
-
-#include <nativehelper/ScopedLocalFrame.h>
-
-#include "JniConstants.h"
-
-extern "C" {
-
-extern void register_java_io_Console(JNIEnv* env);
-extern void register_java_io_FileDescriptor(JNIEnv*);
-extern void register_java_io_FileInputStream(JNIEnv*);
-extern void register_java_io_FileOutputStream(JNIEnv*);
-extern void register_java_io_ObjectInputStream(JNIEnv*);
-extern void register_java_io_ObjectOutputStream(JNIEnv*);
-extern void register_java_io_ObjectStreamClass(JNIEnv*);
-extern void register_java_io_UnixFileSystem(JNIEnv*);
-extern void register_java_lang_Double(JNIEnv*);
-extern void register_java_lang_Float(JNIEnv*);
-extern void register_java_lang_ProcessEnvironment(JNIEnv*);
-extern void register_java_lang_Runtime(JNIEnv*);
-extern void register_java_lang_StrictMath(JNIEnv*);
-extern void register_java_lang_Math(JNIEnv*);
-extern void register_java_lang_System(JNIEnv*);
-extern void register_java_lang_Thread(JNIEnv*);
-extern void register_java_lang_UNIXProcess(JNIEnv*);
-extern void register_java_net_DatagramPacket(JNIEnv*);
-extern void register_java_net_Inet4Address(JNIEnv*);
-extern void register_java_net_Inet6Address(JNIEnv*);
-extern void register_java_net_InetAddress(JNIEnv*);
-extern void register_java_net_PlainDatagramSocketImpl(JNIEnv*);
-extern void register_java_net_SocketInputStream(JNIEnv*);
-extern void register_java_net_SocketOutputStream(JNIEnv*);
-extern void register_java_nio_MappedByteBuffer(JNIEnv* env);
-extern void register_java_util_zip_Adler32(JNIEnv* env);
-extern void register_java_util_zip_CRC32(JNIEnv*);
-extern void register_java_util_zip_Deflater(JNIEnv*);
-extern void register_java_util_zip_Inflater(JNIEnv*);
-extern void register_java_util_zip_ZipFile(JNIEnv*);
-extern void register_java_util_prefs_FileSystemPreferences(JNIEnv*);
-extern void register_sun_nio_ch_DatagramChannelImpl(JNIEnv*);
-extern void register_sun_nio_ch_DatagramDispatcher(JNIEnv*);
-extern void register_sun_nio_ch_FileChannelImpl(JNIEnv*);
-extern void register_sun_nio_ch_FileDispatcherImpl(JNIEnv*);
-extern void register_sun_nio_ch_FileKey(JNIEnv*);
-extern void register_sun_nio_ch_IOUtil(JNIEnv*);
-extern void register_sun_nio_ch_NativeThread(JNIEnv*);
-extern void register_sun_nio_ch_Net(JNIEnv*);
-extern void register_sun_nio_ch_ServerSocketChannelImpl(JNIEnv*);
-extern void register_sun_nio_ch_SocketChannelImpl(JNIEnv* env);
-
-extern jint net_JNI_OnLoad(JavaVM*, void*);
-
-}
-
-extern void register_java_lang_Character(JNIEnv*);
-
-// DalvikVM calls this on startup, so we can statically register all our native methods.
-jint JNI_OnLoad(JavaVM* vm, void*) { JNIEnv* env;
-    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        ALOGE("JavaVM::GetEnv() failed");
-        abort();
-    }
-
-    ScopedLocalFrame localFrame(env);
-    register_java_util_zip_ZipFile(env);
-    register_java_util_zip_Inflater(env);
-    register_java_util_zip_Deflater(env);
-    register_java_util_zip_CRC32(env);
-    register_java_util_zip_Adler32(env);
-    register_sun_nio_ch_IOUtil(env);
-    register_sun_nio_ch_FileChannelImpl(env);
-    register_sun_nio_ch_FileDispatcherImpl(env);
-    register_java_io_Console(env);
-    register_java_io_FileOutputStream(env);
-    register_java_io_FileInputStream(env);
-    register_java_io_FileDescriptor(env);
-    register_java_io_ObjectInputStream(env);
-    register_java_io_ObjectOutputStream(env);
-    register_java_io_UnixFileSystem(env);
-    register_sun_nio_ch_NativeThread(env);
-    register_sun_nio_ch_FileKey(env);
-    register_java_io_ObjectStreamClass(env);
-    register_java_lang_Character(env);
-    register_java_lang_Float(env);
-    register_java_lang_Double(env);
-    register_java_lang_StrictMath(env);
-    register_java_lang_Math(env);
-    register_java_lang_ProcessEnvironment(env);
-    register_java_lang_Runtime(env);
-    register_java_lang_System(env);
-    register_java_lang_UNIXProcess(env);
-    // register_java_net_InetAddress depends on java_lang_Float & Math being
-    // fully registered (getMethodId on InetAddress class triggers its
-    // <clinit> which depends on java.lang.Float)
-    register_java_net_InetAddress(env);
-    register_java_net_Inet4Address(env);
-    register_java_net_Inet6Address(env);
-    register_java_net_SocketInputStream(env);
-    register_java_net_SocketOutputStream(env);
-    register_java_util_prefs_FileSystemPreferences(env);
-    register_sun_nio_ch_ServerSocketChannelImpl(env);
-    register_sun_nio_ch_SocketChannelImpl(env);
-    register_sun_nio_ch_Net(env);
-    register_sun_nio_ch_DatagramChannelImpl(env);
-    register_sun_nio_ch_DatagramDispatcher(env);
-    register_java_nio_MappedByteBuffer(env);
-    net_JNI_OnLoad(vm, NULL);
-
-    JniConstants::Initialize(env);
-    return JNI_VERSION_1_6;
-}
-
-void JNI_OnUnload(JavaVM* vm, void*) {
-    JniConstants::Invalidate();
-}
diff --git a/ojluni/src/main/native/System.c b/ojluni/src/main/native/System.c
index 6cfee92..39332ce 100644
--- a/ojluni/src/main/native/System.c
+++ b/ojluni/src/main/native/System.c
@@ -38,13 +38,12 @@
 #include "openssl/opensslv.h"
 #include "zlib.h"
 #include <nativehelper/JNIHelp.h>
+#include <nativehelper/jni_macros.h>
+
 #if defined(__ANDROID__)
 void android_get_LD_LIBRARY_PATH(char*, size_t);
 #endif
 
-#define NATIVE_METHOD(className, functionName, signature) \
-{ #functionName, signature, (void*)(className ## _ ## functionName) }
-
 #define PUTPROP(props, key, val) \
     if (1) { \
         jstring jkey = (*env)->NewStringUTF(env, key); \
@@ -252,13 +251,13 @@
     }
 }
 
-static jlong System_nanoTime(JNIEnv* env, jclass unused) {
+static jlong System_nanoTime() {
   struct timespec now;
   clock_gettime(CLOCK_MONOTONIC, &now);
   return now.tv_sec * 1000000000LL + now.tv_nsec;
 }
 
-static jlong System_currentTimeMillis(JNIEnv* env, jclass unused) {
+static jlong System_currentTimeMillis() {
   return JVM_CurrentTimeMillis(NULL, NULL);
 }
 
@@ -269,8 +268,8 @@
   NATIVE_METHOD(System, setIn0, "(Ljava/io/InputStream;)V"),
   NATIVE_METHOD(System, specialProperties, "()[Ljava/lang/String;"),
   NATIVE_METHOD(System, log, "(CLjava/lang/String;Ljava/lang/Throwable;)V"),
-  NATIVE_METHOD(System, currentTimeMillis, "()J"),
-  NATIVE_METHOD(System, nanoTime, "()J"),
+  CRITICAL_NATIVE_METHOD(System, currentTimeMillis, "()J"),
+  CRITICAL_NATIVE_METHOD(System, nanoTime, "()J"),
 };
 
 void register_java_lang_System(JNIEnv* env) {
diff --git a/ojluni/src/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java b/ojluni/src/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java
index 091b385..c45cd96 100644
--- a/ojluni/src/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java
+++ b/ojluni/src/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java
@@ -176,7 +176,9 @@
     @DataProvider(name="createByEra")
     Object[][] data_createByEra() {
         return new Object[][] {
-                {JapaneseEra.of(3), 2020 - YDIFF_REIWA, 2, 29, 60, LocalDate.of(2020, 2, 29)}, // NEWERA
+                // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+                //{JapaneseEra.of(3), 2020 - YDIFF_REIWA, 2, 29, 60, LocalDate.of(2020, 2, 29)},
+                {JapaneseEra.REIWA, 2020 - YDIFF_REIWA, 2, 29, 60, LocalDate.of(2020, 2, 29)},
                 {JapaneseEra.HEISEI, 1996 - YDIFF_HEISEI, 2, 29, 60, LocalDate.of(1996, 2, 29)},
                 {JapaneseEra.HEISEI, 2000 - YDIFF_HEISEI, 2, 29, 60, LocalDate.of(2000, 2, 29)},
                 {JapaneseEra.MEIJI, 1874 - YDIFF_MEIJI, 2, 28, 59, LocalDate.of(1874, 2, 28)},
@@ -369,8 +371,11 @@
     @DataProvider(name="prolepticYear")
     Object[][] data_prolepticYear() {
         return new Object[][] {
-                {3, JapaneseEra.of(3), 1, 1 + YDIFF_REIWA, false},
-                {3, JapaneseEra.of(3), 102, 102 + YDIFF_REIWA, true},
+                // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+                // {3, JapaneseEra.of(3), 1, 1 + YDIFF_REIWA, false},
+                // {3, JapaneseEra.of(3), 102, 102 + YDIFF_REIWA, true},
+                {3, JapaneseEra.REIWA, 1, 1 + YDIFF_REIWA, false},
+                {3, JapaneseEra.REIWA, 102, 102 + YDIFF_REIWA, true},
 
                 {2, JapaneseEra.HEISEI, 1, 1 + YDIFF_HEISEI, false},
                 {2, JapaneseEra.HEISEI, 4, 4 + YDIFF_HEISEI, true},
@@ -555,7 +560,9 @@
             { JapaneseEra.TAISHO, 0, "Taisho"},
             { JapaneseEra.SHOWA, 1, "Showa"},
             { JapaneseEra.HEISEI, 2, "Heisei"},
-            { JapaneseEra.of(3), 3, "Reiwa"},
+            // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+            // { JapaneseEra.of(3), 3, "Reiwa"},
+            { JapaneseEra.REIWA, 3, "Reiwa"},
         };
     }
 
diff --git a/ojluni/src/test/java/time/tck/java/time/chrono/TCKJapaneseEra.java b/ojluni/src/test/java/time/tck/java/time/chrono/TCKJapaneseEra.java
index e37a6a5..afe2586 100644
--- a/ojluni/src/test/java/time/tck/java/time/chrono/TCKJapaneseEra.java
+++ b/ojluni/src/test/java/time/tck/java/time/chrono/TCKJapaneseEra.java
@@ -77,7 +77,9 @@
     @DataProvider(name = "JapaneseEras")
     Object[][] data_of_eras() {
         return new Object[][] {
-                    {JapaneseEra.of(3), "Reiwa", 3},
+                    // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+                    // {JapaneseEra.of(3), "Reiwa", 3},
+                    {JapaneseEra.REIWA, "Reiwa", 3},
                     {JapaneseEra.HEISEI, "Heisei", 2},
                     {JapaneseEra.SHOWA, "Showa", 1},
                     {JapaneseEra.TAISHO, "Taisho", 0},
diff --git a/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronology.java b/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronology.java
index 03443d9..7c6e25d 100644
--- a/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronology.java
+++ b/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronology.java
@@ -60,7 +60,9 @@
             { JapaneseEra.SHOWA,     64,  1,  7, 1989 },
             { JapaneseEra.HEISEI,     1,  1,  8, 1989 },
             { JapaneseEra.HEISEI,    31,  4, 30, 2019 },
-            { JapaneseEra.of(3),      1,  5,  1, 2019 },
+            // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+            // { JapaneseEra.of(3),      1,  5,  1, 2019 },
+            { JapaneseEra.REIWA,      1,  5,  1, 2019 },
         };
     }
 
@@ -78,7 +80,9 @@
             { JapaneseEra.HEISEI,  1,    1,  1,  8 },
             { JapaneseEra.HEISEI,  2,    8,  1,  8 },
             { JapaneseEra.HEISEI, 31,  120,  4, 30 },
-            { JapaneseEra.of(3),   1,    1,  5,  1 },
+            // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+            // { JapaneseEra.of(3),   1,    1,  5,  1 },
+            { JapaneseEra.REIWA,   1,    1,  5,  1 },
         };
     }
 
@@ -111,8 +115,11 @@
             { JapaneseEra.HEISEI,     1,  1,  7 },
             { JapaneseEra.HEISEI,     1,  2, 29 },
             { JapaneseEra.HEISEI,    31,  5,  1 },
-            { JapaneseEra.of(3),      1,  4, 30 },
-            { JapaneseEra.of(3), Year.MAX_VALUE,  12, 31 },
+            // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+            // { JapaneseEra.of(3),      1,  4, 30 },
+            // { JapaneseEra.of(3), Year.MAX_VALUE,  12, 31 },
+            { JapaneseEra.REIWA,      1,  4, 30 },
+            { JapaneseEra.REIWA, Year.MAX_VALUE,  12, 31 },
         };
     }
 
@@ -132,9 +139,13 @@
             { JapaneseEra.HEISEI,    -1 },
             { JapaneseEra.HEISEI,     0 },
             { JapaneseEra.HEISEI,    32 },
-            { JapaneseEra.of(3),     -1 },
-            { JapaneseEra.of(3),      0 },
-            { JapaneseEra.of(3), Year.MAX_VALUE },
+            // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+            // { JapaneseEra.of(3),     -1 },
+            // { JapaneseEra.of(3),      0 },
+            // { JapaneseEra.of(3), Year.MAX_VALUE },
+            { JapaneseEra.REIWA,     -1 },
+            { JapaneseEra.REIWA,      0 },
+            { JapaneseEra.REIWA, Year.MAX_VALUE },
         };
     }
 
@@ -152,8 +163,11 @@
             { JapaneseEra.HEISEI,  1, 360 },
             { JapaneseEra.HEISEI,  2, 366 },
             { JapaneseEra.HEISEI, 31, 121 },
-            { JapaneseEra.of(3),   1, 246 },
-            { JapaneseEra.of(3),   2, 367 },
+            // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+            // { JapaneseEra.of(3),   1, 246 },
+            // { JapaneseEra.of(3),   2, 367 },
+            { JapaneseEra.REIWA,   1, 246 },
+            { JapaneseEra.REIWA,   2, 367 },
         };
     }
 
@@ -165,7 +179,9 @@
             { "Taisho", JapaneseEra.TAISHO,     null },
             { "Showa",  JapaneseEra.SHOWA,      null },
             { "Heisei", JapaneseEra.HEISEI,     null },
-            { "Reiwa", JapaneseEra.of(3),       null },
+            // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+            // { "Reiwa", JapaneseEra.of(3),       null },
+            { "Reiwa", JapaneseEra.REIWA,       null },
             { "NewEra", null,                   IllegalArgumentException.class},
         };
     }
diff --git a/ojluni/src/test/java/time/test/java/time/format/TestDateTimeTextProvider.java b/ojluni/src/test/java/time/test/java/time/format/TestDateTimeTextProvider.java
index 7628eeb..76296df 100644
--- a/ojluni/src/test/java/time/test/java/time/format/TestDateTimeTextProvider.java
+++ b/ojluni/src/test/java/time/test/java/time/format/TestDateTimeTextProvider.java
@@ -94,14 +94,14 @@
             {DAY_OF_WEEK, 6, TextStyle.SHORT, enUS, "Sat"},
             {DAY_OF_WEEK, 7, TextStyle.SHORT, enUS, "Sun"},
 
-            // Android-changed: upstream tests expect title case names for pt_BR, but CLDR has lower
-            {DAY_OF_WEEK, 1, TextStyle.SHORT, ptBR, "seg"},
-            {DAY_OF_WEEK, 2, TextStyle.SHORT, ptBR, "ter"},
-            {DAY_OF_WEEK, 3, TextStyle.SHORT, ptBR, "qua"},
-            {DAY_OF_WEEK, 4, TextStyle.SHORT, ptBR, "qui"},
-            {DAY_OF_WEEK, 5, TextStyle.SHORT, ptBR, "sex"},
-            {DAY_OF_WEEK, 6, TextStyle.SHORT, ptBR, "s\u00E1b"},
-            {DAY_OF_WEEK, 7, TextStyle.SHORT, ptBR, "dom"},
+            // Android-changed: upstream tests expect title case names for pt_BR, but CLDR has lower with dot
+            {DAY_OF_WEEK, 1, TextStyle.SHORT, ptBR, "seg."},
+            {DAY_OF_WEEK, 2, TextStyle.SHORT, ptBR, "ter."},
+            {DAY_OF_WEEK, 3, TextStyle.SHORT, ptBR, "qua."},
+            {DAY_OF_WEEK, 4, TextStyle.SHORT, ptBR, "qui."},
+            {DAY_OF_WEEK, 5, TextStyle.SHORT, ptBR, "sex."},
+            {DAY_OF_WEEK, 6, TextStyle.SHORT, ptBR, "s\u00E1b."},
+            {DAY_OF_WEEK, 7, TextStyle.SHORT, ptBR, "dom."},
 
             {DAY_OF_WEEK, 1, TextStyle.FULL, enUS, "Monday"},
             {DAY_OF_WEEK, 2, TextStyle.FULL, enUS, "Tuesday"},
@@ -133,18 +133,19 @@
             {MONTH_OF_YEAR, 11, TextStyle.SHORT, enUS, "Nov"},
             {MONTH_OF_YEAR, 12, TextStyle.SHORT, enUS, "Dec"},
 
-            {MONTH_OF_YEAR, 1, TextStyle.SHORT, ptBR, "jan"},
-            {MONTH_OF_YEAR, 2, TextStyle.SHORT, ptBR, "fev"},
-            {MONTH_OF_YEAR, 3, TextStyle.SHORT, ptBR, "mar"},
-            {MONTH_OF_YEAR, 4, TextStyle.SHORT, ptBR, "abr"},
-            {MONTH_OF_YEAR, 5, TextStyle.SHORT, ptBR, "mai"},
-            {MONTH_OF_YEAR, 6, TextStyle.SHORT, ptBR, "jun"},
-            {MONTH_OF_YEAR, 7, TextStyle.SHORT, ptBR, "jul"},
-            {MONTH_OF_YEAR, 8, TextStyle.SHORT, ptBR, "ago"},
-            {MONTH_OF_YEAR, 9, TextStyle.SHORT, ptBR, "set"},
-            {MONTH_OF_YEAR, 10, TextStyle.SHORT, ptBR, "out"},
-            {MONTH_OF_YEAR, 11, TextStyle.SHORT, ptBR, "nov"},
-            {MONTH_OF_YEAR, 12, TextStyle.SHORT, ptBR, "dez"},
+            // Android-changed: upstream tests expect title case names for pt_BR, but CLDR has lower with dot
+            {MONTH_OF_YEAR, 1, TextStyle.SHORT, ptBR, "jan."},
+            {MONTH_OF_YEAR, 2, TextStyle.SHORT, ptBR, "fev."},
+            {MONTH_OF_YEAR, 3, TextStyle.SHORT, ptBR, "mar."},
+            {MONTH_OF_YEAR, 4, TextStyle.SHORT, ptBR, "abr."},
+            {MONTH_OF_YEAR, 5, TextStyle.SHORT, ptBR, "mai."},
+            {MONTH_OF_YEAR, 6, TextStyle.SHORT, ptBR, "jun."},
+            {MONTH_OF_YEAR, 7, TextStyle.SHORT, ptBR, "jul."},
+            {MONTH_OF_YEAR, 8, TextStyle.SHORT, ptBR, "ago."},
+            {MONTH_OF_YEAR, 9, TextStyle.SHORT, ptBR, "set."},
+            {MONTH_OF_YEAR, 10, TextStyle.SHORT, ptBR, "out."},
+            {MONTH_OF_YEAR, 11, TextStyle.SHORT, ptBR, "nov."},
+            {MONTH_OF_YEAR, 12, TextStyle.SHORT, ptBR, "dez."},
 
             {MONTH_OF_YEAR, 1, TextStyle.FULL, enUS, "January"},
             {MONTH_OF_YEAR, 2, TextStyle.FULL, enUS, "February"},
diff --git a/openjdk_java_files.bp b/openjdk_java_files.bp
index c1f29ea..7ba860c 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",
@@ -1345,6 +1346,7 @@
         "ojluni/src/main/java/javax/sql/StatementEventListener.java",
         "ojluni/src/main/java/sun/reflect/CallerSensitive.java",
     ],
+    path: "ojluni/src/main/java",
 }
 
 // Stubs needed to satisfy javac's dependencies when compiling lambda code. These are
@@ -1358,11 +1360,15 @@
 // any of these classes.
 filegroup {
     name: "openjdk_lambda_stub_files",
+    visibility: [
+        "//libcore:__subpackages__",
+    ],
     srcs: [
         "ojluni/src/lambda/java/java/lang/invoke/LambdaMetafactory.java",
         "ojluni/src/lambda/java/java/lang/invoke/SerializedLambda.java",
     ],
 }
+
 filegroup {
     name: "openjdk_lambda_duplicate_stub_files",
     srcs: [
@@ -1374,6 +1380,21 @@
     ],
 }
 
+// Stubs needed to satisfy javac when compiling source code that contains
+// @Generated annotations, which are produced by some code generation tools.
+// TODO: Remove this source file, this target, and all its dependencies, if
+// the code generation tools (notably dagger) can be fixed.
+// See http://b/123891440.
+filegroup {
+    name: "openjdk_generated_annotation_stub_files",
+    visibility: [
+        "//libcore:__subpackages__",
+    ],
+    srcs: [
+        "ojluni/src/generated-annotation/java/javax/annotation/processing/Generated.java",
+    ],
+}
+
 // Classes which are exposed in the intra-core or core-platform APIs but not in
 // the public APIs. Unless they are annotated, these classes and all their
 // members will be exposed in all such APIs. To avoid patching the main ojluni
@@ -1414,6 +1435,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",
@@ -1421,6 +1444,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",
@@ -1431,7 +1456,6 @@
         "ojluni/src/main/java/sun/misc/CEStreamExhausted.java",
         "ojluni/src/main/java/sun/misc/CharacterDecoder.java",
         "ojluni/src/main/java/sun/misc/CharacterEncoder.java",
-        "ojluni/src/main/java/sun/misc/Cleaner.java",
         "ojluni/src/main/java/sun/misc/CompoundEnumeration.java",
         "ojluni/src/main/java/sun/misc/DoubleConsts.java",
         "ojluni/src/main/java/sun/misc/FileURLMapper.java",
@@ -1511,7 +1535,6 @@
         "ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java",
         "ojluni/src/main/java/sun/nio/ch/DefaultAsynchronousChannelProvider.java",
         "ojluni/src/main/java/sun/nio/ch/DefaultSelectorProvider.java",
-        "ojluni/src/main/java/sun/nio/ch/DirectBuffer.java",
         "ojluni/src/main/java/sun/nio/ch/EPoll.java",
         "ojluni/src/main/java/sun/nio/ch/EPollPort.java",
         "ojluni/src/main/java/sun/nio/ch/ExtendedSocketOption.java",
@@ -1621,13 +1644,10 @@
         "ojluni/src/main/java/sun/security/jca/JCAUtil.java",
         "ojluni/src/main/java/sun/security/jca/ProviderConfig.java",
         "ojluni/src/main/java/sun/security/jca/ProviderList.java",
-        "ojluni/src/main/java/sun/security/jca/Providers.java",
         "ojluni/src/main/java/sun/security/jca/ServiceId.java",
-        "ojluni/src/main/java/sun/security/pkcs/PKCS7.java",
         "ojluni/src/main/java/sun/security/pkcs/PKCS8Key.java",
         "ojluni/src/main/java/sun/security/pkcs/PKCS9Attribute.java",
         "ojluni/src/main/java/sun/security/pkcs/PKCS9Attributes.java",
-        "ojluni/src/main/java/sun/security/pkcs/SignerInfo.java",
         "ojluni/src/main/java/sun/security/pkcs/SigningCertificateInfo.java",
         "ojluni/src/main/java/sun/security/provider/CertPathProvider.java",
         "ojluni/src/main/java/sun/security/provider/certpath/AdaptableX509CertSelector.java",
@@ -1793,11 +1813,15 @@
 // All classes, whether exposed in any API or not.
 filegroup {
     name: "openjdk_java_files",
+    visibility: [
+        "//frameworks/base",
+    ],
     srcs: [
         ":openjdk_javadoc_files",
         ":openjdk_mmodule_extra_files",
         ":openjdk_internal_files",
         ":openjdk_lambda_stub_files",
+        ":openjdk_generated_annotation_stub_files",
     ],
 }
 
@@ -1814,8 +1838,9 @@
     name: "openjdk-sdk-stubs-no-javadoc",
     srcs: [":openjdk_javadoc_files"],
     installable: false,
-    no_framework_libs: true,
-    args: "--exclude-documentation-from-stubs"
+    sdk_version: "none",
+    system_modules: "none",
+    args: "--exclude-documentation-from-stubs",
 }
 
 // Generates stub files for the classes exposed in the intra-core or
@@ -1829,8 +1854,9 @@
         ":openjdk_mmodule_extra_files",
     ],
     installable: false,
-    no_framework_libs: true,
-    args: "--exclude-documentation-from-stubs "
-        + "--hide-annotation libcore.api.Hide ",
+    sdk_version: "none",
+    system_modules: "none",
+    args: "--exclude-documentation-from-stubs " +
+        "--hide-annotation libcore.api.Hide ",
     merge_inclusion_annotations_dirs: ["ojluni-annotated-mmodule-stubs"],
 }
diff --git a/support/src/test/java/libcore/java/security/CpuFeatures.java b/support/src/test/java/libcore/java/security/CpuFeatures.java
index 8ab610f..df65ed2 100644
--- a/support/src/test/java/libcore/java/security/CpuFeatures.java
+++ b/support/src/test/java/libcore/java/security/CpuFeatures.java
@@ -16,47 +16,87 @@
 
 package libcore.java.security;
 
+import android.system.Os;
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import dalvik.system.VMRuntime;
 
-class CpuFeatures {
+public class CpuFeatures {
+    /** Machine architecture, determined from the "machine" value returned by uname() */
+    private enum Arch {
+        // 64bit ARM can return armv8 or aarch64.
+        // 32bit ARM should return armv7 or armv7a
+        ARM("^aarch.*|^arm.*"),
+        // 64bit Android and Linux generally return x86_64.
+        // 32bit Android and Linux generally return i686
+        // Other host architectures can potentially return x86 or i386.
+        X86("^x86.*|i386|i686");
+
+        private final String machineRegex;
+
+        Arch(String machineRegex) {
+            this.machineRegex = machineRegex;
+        }
+
+        /**
+         * Returns the architecture of this machine by matching against output from uname()
+         * against the regex for each known family.
+         */
+        public static Arch currentArch() {
+            String machine = Os.uname().machine;
+            for (Arch type : values()) {
+                if (machine.matches(type.machineRegex)) {
+                    return type;
+                }
+            }
+            throw new IllegalStateException("Unknown machine value: " + machine);
+        }
+    }
+
+    private enum InstructionSet {
+        ARM_32(Arch.ARM, "arm"),
+        ARM_64(Arch.ARM, "arm64"),
+        X86_32(Arch.X86, "x86"),
+        X86_64(Arch.X86, "x86_64");
+
+        private final Arch arch;
+        private final String name;
+
+        InstructionSet(Arch arch, String name) {
+            this.arch = arch;
+            this.name = name;
+        }
+
+        public Arch architecture() {
+            return arch;
+        }
+
+        /**
+         * Returns the current InstructionSet set by matching against the name fields above.
+         */
+        public static InstructionSet currentInstructionSet() {
+            // Always returns one of the values from VMRuntime.ABI_TO_INSTRUCTION_SET_MAP.
+            String instructionSet = VMRuntime.getCurrentInstructionSet();
+            for (InstructionSet set : values()) {
+                if (instructionSet.equals(set.name)) {
+                    return set;
+                }
+            }
+            throw new IllegalStateException("Unknown instruction set: " + instructionSet);
+        }
+    }
+
     private CpuFeatures() {
     }
 
-    static boolean isAESHardwareAccelerated() {
-        // Expectations based on CPU type: If these aren't met then Conscrypt
-        // integration tests will fail and the cause should be investigated.
-        String instructionSet = VMRuntime.getCurrentInstructionSet();
-        if (instructionSet.startsWith("arm")) {
-            // All ARM CPUs with the "aes" feature should have hardware AES.
-            List<String> features = getListFromCpuinfo("Features");
-            if (features != null && features.contains("aes")) {
-                return true;
-            }
-        } else if (instructionSet.startsWith("x86")) {
-            // x86 CPUs with the "aes" flag and running in 64bit mode should have hardware AES.
-            if ("x86_64".equals(instructionSet)) {
-                List<String> flags = getListFromCpuinfo("flags");
-                if (flags != null && flags.contains("aes")) {
-                    return true;
-                }
-            } else {
-                // Hardware AES not supported in 32bit mode.
-                return false;
-            }
-        }
-
-        // Otherwise trust Conscrypt NativeCrypto's own checks, for example if we're in an
-        // emulated ABI, it might bridge to a library that has accelerated AES instructions.
+    /**
+     * Returns true if this device has hardware AES support as determined by BoringSSL.
+     */
+    public static boolean isAesHardwareAccelerated() {
         try {
             Class<?> nativeCrypto = Class.forName("com.android.org.conscrypt.NativeCrypto");
             Method EVP_has_aes_hardware = nativeCrypto.getDeclaredMethod("EVP_has_aes_hardware");
@@ -71,33 +111,51 @@
         return false;
     }
 
-    private static String getFieldFromCpuinfo(String field) {
-        try {
-            BufferedReader br = new BufferedReader(new FileReader("/proc/cpuinfo"));
-            Pattern p = Pattern.compile(field + "\\s*:\\s*(.*)");
+    /**
+     * Returns true if this device should have hardware AES support based on CPU information.
+     *
+     * A return value of false means that acceleration isn't expected, but it may still be available
+     * e.g. via bridging to a native library in an emulated environment.
+     */
+    public static boolean isKnownToSupportHardwareAes() {
+        Arch architecture = Arch.currentArch();
+        InstructionSet instructionSet = InstructionSet.currentInstructionSet();
 
-            try {
-                String line;
-                while ((line = br.readLine()) != null) {
-                    Matcher m = p.matcher(line);
-                    if (m.matches()) {
-                        return m.group(1);
-                    }
+        if (!instructionSet.architecture().equals(architecture)) {
+            // Different architectures imply an emulated environment, so unable to determine if
+            // hardware acceleration is expected.  Assume not.
+            return false;
+        }
+
+        if (architecture.equals(Arch.ARM)) {
+            // All ARM CPUs (32 and 64 bit) with the "aes" feature should have hardware AES.
+            return cpuFieldContainsAes("Features");
+        } else if (instructionSet.equals(InstructionSet.X86_64)) {
+            // x86 CPUs with the "aes" flag and running in 64bit mode should have hardware AES.
+            // Hardware AES is not *expected* in 32bit mode, but may be available.
+            return cpuFieldContainsAes("flags");
+        }
+        return false;
+    }
+
+
+    /**
+     * Returns true if any line in the output from /proc/cpuinfo matches the provided
+     * field name and contains the word "aes" in its list of values.
+     *
+     * Example line from /proc/cpuinfo: Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32
+     */
+    private static boolean cpuFieldContainsAes(String fieldName) {
+        try (BufferedReader br = new BufferedReader(new FileReader("/proc/cpuinfo"))) {
+            String regex = "^" + fieldName + "\\s*:.*\\baes\\b.*";
+            String line;
+            while ((line = br.readLine()) != null) {
+                if (line.matches(regex)) {
+                    return true;
                 }
-            } finally {
-                br.close();
             }
         } catch (IOException ignored) {
         }
-
-        return null;
-    }
-
-    private static List<String> getListFromCpuinfo(String fieldName) {
-        String features = getFieldFromCpuinfo(fieldName);
-        if (features == null)
-            return null;
-
-        return Arrays.asList(features.split("\\s"));
+        return false;
     }
 }
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index eb9cf45..7521cf9 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -510,6 +510,7 @@
             provide("Cipher", "AES/ECB/PKCS5PADDING");
             provide("Cipher", "AES/ECB/PKCS7PADDING");
             provide("Cipher", "AES/GCM/NOPADDING");
+            provide("Cipher", "AES/GCM-SIV/NOPADDING");
             provide("Cipher", "AES/OFB/NOPADDING");
             provide("Cipher", "AES/OFB/PKCS5PADDING");
             provide("Cipher", "AES/OFB/PKCS7PADDING");
@@ -520,6 +521,7 @@
             provide("Cipher", "AES_128/ECB/PKCS5PADDING");
             provide("Cipher", "AES_128/ECB/PKCS7PADDING");
             provide("Cipher", "AES_128/GCM/NOPADDING");
+            provide("Cipher", "AES_128/GCM-SIV/NOPADDING");
             provide("Cipher", "AES_256/CBC/NOPADDING");
             provide("Cipher", "AES_256/CBC/PKCS5PADDING");
             provide("Cipher", "AES_256/CBC/PKCS7PADDING");
@@ -527,6 +529,7 @@
             provide("Cipher", "AES_256/ECB/PKCS5PADDING");
             provide("Cipher", "AES_256/ECB/PKCS7PADDING");
             provide("Cipher", "AES_256/GCM/NOPADDING");
+            provide("Cipher", "AES_256/GCM-SIV/NOPADDING");
             provide("Cipher", "DESEDE/CBC/NOPADDING");
             provide("Cipher", "DESEDE/CBC/PKCS5PADDING");
             provide("Cipher", "DESEDE/CBC/PKCS7PADDING");
@@ -754,7 +757,7 @@
                             "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
                             "SSL_RSA_WITH_RC4_128_MD5",
                             "TLS_EMPTY_RENEGOTIATION_INFO_SCSV")
-            : CpuFeatures.isAESHardwareAccelerated() ? CIPHER_SUITES_ANDROID_AES_HARDWARE
+            : CpuFeatures.isAesHardwareAccelerated() ? CIPHER_SUITES_ANDROID_AES_HARDWARE
                     : CIPHER_SUITES_ANDROID_SOFTWARE;
 
     private static final Map<String, Class<? extends KeySpec>> PRIVATE_KEY_SPEC_CLASSES;
diff --git a/support/src/test/java/libcore/testing/io/TestIoUtils.java b/support/src/test/java/libcore/testing/io/TestIoUtils.java
index 8e241df..34a2cf7 100644
--- a/support/src/test/java/libcore/testing/io/TestIoUtils.java
+++ b/support/src/test/java/libcore/testing/io/TestIoUtils.java
@@ -17,6 +17,10 @@
 package libcore.testing.io;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.Random;
 
 public class TestIoUtils {
@@ -25,6 +29,13 @@
     private TestIoUtils() {}
 
     /**
+     * Returns the contents of 'path' as a string. The contents are assumed to be UTF-8.
+     */
+    public static String readFileAsString(String absolutePath) throws IOException {
+        return new String(Files.readAllBytes(Paths.get(absolutePath)), StandardCharsets.UTF_8);
+    }
+
+    /**
      * Creates a unique new temporary directory under "java.io.tmpdir".
      */
     public static File createTemporaryDirectory(String prefix) {
diff --git a/support/src/test/java/org/apache/harmony/xnet/tests/support/MySSLContextSpi.java b/support/src/test/java/org/apache/harmony/xnet/tests/support/MySSLContextSpi.java
index 54e2a03..94ca6a9 100644
--- a/support/src/test/java/org/apache/harmony/xnet/tests/support/MySSLContextSpi.java
+++ b/support/src/test/java/org/apache/harmony/xnet/tests/support/MySSLContextSpi.java
@@ -77,14 +77,14 @@
         return null;
     }
 
-    protected SSLParameters engineGetDefaultSSLParameters() {
+    public SSLParameters engineGetDefaultSSLParameters() {
         engineGetSocketFactory();
-        return null;
+        return super.engineGetDefaultSSLParameters();
     }
 
-    protected SSLParameters engineGetSupportedSSLParameters() {
+    public SSLParameters engineGetSupportedSSLParameters() {
         engineGetSocketFactory();
-        return null;
+        return super.engineGetSupportedSSLParameters();
     }
 
     /*
diff --git a/support/src/test/java/tests/support/Support_Configuration.java b/support/src/test/java/tests/support/Support_Configuration.java
index 0856d44..d5fc705 100644
--- a/support/src/test/java/tests/support/Support_Configuration.java
+++ b/support/src/test/java/tests/support/Support_Configuration.java
@@ -46,6 +46,8 @@
 
     public static final String HomeAddressSoftware = "Jetty(6.0.x)";
 
+    public static String ProxyServerTestHost = "jcltest.apache.org";
+
     public static final String SocksServerTestHost = "jcltest.apache.org";
 
     public static final int SocksServerTestPort = 1080;
diff --git a/test-rules/src/main/java/libcore/junit/util/EnableDeprecatedBouncyCastleAlgorithmsRule.java b/test-rules/src/main/java/libcore/junit/util/EnableDeprecatedBouncyCastleAlgorithmsRule.java
new file mode 100644
index 0000000..bfd45ef
--- /dev/null
+++ b/test-rules/src/main/java/libcore/junit/util/EnableDeprecatedBouncyCastleAlgorithmsRule.java
@@ -0,0 +1,71 @@
+/*
+ * 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 libcore.junit.util;
+
+import dalvik.system.VMRuntime;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.function.Supplier;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import sun.security.jca.Providers;
+
+/**
+ * Allows tests to temporarily enable deprecated BouncyCastle algorithms to verify that their
+ * behavior has not changed.
+ *
+ * <p>To use add the following to the test class.
+ *
+ * <pre>
+ * &#64;Rule
+ * public TestRule enableDeprecatedBCAlgorithmsRule =
+ *     EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance();
+ * </pre>
+ *
+ * <p>It will give all test methods access to the deprecated algorithms.
+ */
+public class EnableDeprecatedBouncyCastleAlgorithmsRule implements TestRule {
+
+    private static final TestRule INSTANCE = new EnableDeprecatedBouncyCastleAlgorithmsRule();
+
+    public static TestRule getInstance() {
+        return INSTANCE;
+    }
+
+    private EnableDeprecatedBouncyCastleAlgorithmsRule() {
+    }
+
+    @Override
+    public Statement apply(final Statement statement, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                int currentMaximum =
+                        Providers.getMaximumAllowableApiLevelForBcDeprecation();
+                try {
+                    int newMaximum = VMRuntime.getRuntime().getTargetSdkVersion();
+                    Providers.setMaximumAllowableApiLevelForBcDeprecation(newMaximum);
+                    statement.evaluate();
+                } finally {
+                    Providers.setMaximumAllowableApiLevelForBcDeprecation(currentMaximum);
+                }
+            }
+        };
+    }
+}
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/test-rules/src/platform_compat/java/libcore/junit/util/CoreCompatChangeRule.java b/test-rules/src/platform_compat/java/libcore/junit/util/CoreCompatChangeRule.java
new file mode 100644
index 0000000..b526707
--- /dev/null
+++ b/test-rules/src/platform_compat/java/libcore/junit/util/CoreCompatChangeRule.java
@@ -0,0 +1,123 @@
+/*
+ * 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 libcore.junit.util.compat;
+
+import android.compat.Compatibility;
+import android.compat.Compatibility.Callbacks;
+import android.compat.Compatibility.ChangeConfig;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.HashSet;
+import java.util.Set;
+import com.google.common.primitives.Longs;
+
+/**
+ * Allows tests to specify the which change to disable.
+ *
+ * <p>To use add the following to the test class. It will only change the behavior of a test method
+ * if it is annotated with {@link EnableCompatChanges} and/or {@link DisableCompatChanges}.
+ *
+ * <pre>
+ * &#64;Rule
+ * public TestRule compatChangeRule = new CoreCompatChangeRule();
+ * </pre>
+ *
+ * <p>Each test method that needs to disable a specific change needs to be annotated
+ * with {@link EnableCompatChanges} and/or {@link DisableCompatChanges} specifying the change id.
+ * e.g.:
+ *
+ * <pre>
+ *   &#64;Test
+ *   &#64;DisableCompatChanges({42})
+ *   public void testAsIfChange42Disabled() {
+ *     // check behavior
+ *   }
+ *
+ *   &#64;Test
+ *   &#64;EnableCompatChanges({42})
+ *   public void testAsIfChange42Enabled() {
+ *     // check behavior
+ *
+ * </pre>
+ */
+public class CoreCompatChangeRule implements TestRule {
+
+    @Override
+    public Statement apply(final Statement statement, Description description) {
+        Set<Long> enabled = new HashSet<>();
+        Set<Long> disabled = new HashSet<>();
+        EnableCompatChanges enableCompatChanges = description.getAnnotation(
+                EnableCompatChanges.class);
+        DisableCompatChanges disableCompatChanges = description.getAnnotation(
+                DisableCompatChanges.class);
+        if (enableCompatChanges != null) {
+            enabled.addAll(Longs.asList(enableCompatChanges.value()));
+        }
+        if (disableCompatChanges != null) {
+            disabled.addAll(Longs.asList(disableCompatChanges.value()));
+        }
+        ChangeConfig config = new ChangeConfig(enabled, disabled);
+        if (config.isEmpty()) {
+            return statement;
+        } else {
+            return createStatementForConfig(statement, config);
+        }
+    }
+
+    protected Statement createStatementForConfig(final Statement statement, ChangeConfig config) {
+            return new CompatChangeStatement(statement, config);
+    }
+
+    private static class CompatChangeStatement extends Statement {
+        private final Statement testStatement;
+        private final ChangeConfig config;
+
+        private CompatChangeStatement(Statement testStatement, ChangeConfig config) {
+            this.testStatement = testStatement;
+            this.config = config;
+        }
+
+        @Override
+        public void evaluate() throws Throwable {
+            Compatibility.setOverrides(config);
+            try {
+                testStatement.evaluate();
+            } finally {
+                Compatibility.clearOverrides();
+            }
+        }
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface EnableCompatChanges {
+        long[] value();
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface DisableCompatChanges {
+        long[] value();
+    }
+}
diff --git a/test-rules/src/test/java/android/compat/testing/DummyApi.java b/test-rules/src/test/java/android/compat/testing/DummyApi.java
new file mode 100644
index 0000000..dfe40cc
--- /dev/null
+++ b/test-rules/src/test/java/android/compat/testing/DummyApi.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.compat.testing;
+
+import android.compat.Compatibility;
+
+/**
+ * This is a dummy API to test gating
+ *
+ * @hide
+ */
+public class DummyApi {
+
+    public static final long CHANGE_ID = 666013;
+    public static final long CHANGE_ID_1 = 666014;
+    public static final long CHANGE_ID_2 = 666015;
+
+    /**
+     * Dummy method
+     * @return "A" if change is enabled, "B" otherwise.
+     */
+    public static String dummyFunc() {
+        if (Compatibility.isChangeEnabled(CHANGE_ID)) {
+            return "A";
+        }
+        return "B";
+    }
+
+    /**
+     * Dummy combined method
+     * @return "0" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is disabled,
+               "1" if {@link CHANGE_ID_1} is disabled and {@link CHANGE_ID_2} is enabled,
+               "2" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is disabled,
+               "3" if {@link CHANGE_ID_1} is enabled and {@link CHANGE_ID_2} is enabled.
+     */
+    public static String dummyCombinedFunc() {
+        if (!Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && !Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "0";
+        } else if (!Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "1";
+        } else if (Compatibility.isChangeEnabled(CHANGE_ID_1)
+                && !Compatibility.isChangeEnabled(CHANGE_ID_2)) {
+            return "2";
+        }
+        return "3";
+    }
+
+}
\ No newline at end of file
diff --git a/test-rules/src/test/java/libcore/junit/util/EnableDeprecatedBouncyCastleAlgorithmsRuleTest.java b/test-rules/src/test/java/libcore/junit/util/EnableDeprecatedBouncyCastleAlgorithmsRuleTest.java
new file mode 100644
index 0000000..a08ed84
--- /dev/null
+++ b/test-rules/src/test/java/libcore/junit/util/EnableDeprecatedBouncyCastleAlgorithmsRuleTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 libcore.junit.util;
+
+import dalvik.system.VMRuntime;
+import libcore.junit.util.SwitchTargetSdkVersionRule.TargetSdkVersion;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import sun.security.jca.Providers;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for {@link EnableDeprecatedBouncyCastleAlgorithmsRule}.
+ */
+@RunWith(JUnit4.class)
+public class EnableDeprecatedBouncyCastleAlgorithmsRuleTest {
+
+    /**
+     * Chain the rules together so that changes to the target sdk version will be visible in the
+     * bouncy castle rules.
+     */
+    @Rule
+    public TestRule chain = RuleChain
+            .outerRule(SwitchTargetSdkVersionRule.getInstance())
+            .around(EnableDeprecatedBouncyCastleAlgorithmsRule.getInstance());
+
+    @Test
+    @TargetSdkVersion(23)
+    public void testRunningAsIfTargetedAtSDKVersion23() {
+        assertEquals(23, Providers.getMaximumAllowableApiLevelForBcDeprecation());
+    }
+
+    @Test
+    public void testRunningAsIfTargetedAtCurrentSDKVersion() {
+        assertEquals(VMRuntime.getRuntime().getTargetSdkVersion(),
+                Providers.getMaximumAllowableApiLevelForBcDeprecation());
+    }
+}
diff --git a/test-rules/src/test/java/libcore/junit/util/compat/CoreCompatChangeRuleTest.java b/test-rules/src/test/java/libcore/junit/util/compat/CoreCompatChangeRuleTest.java
new file mode 100644
index 0000000..87b9446
--- /dev/null
+++ b/test-rules/src/test/java/libcore/junit/util/compat/CoreCompatChangeRuleTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 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.junit.util.compat;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.compat.testing.DummyApi;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for compatibility change gating.
+ */
+@RunWith(JUnit4.class)
+public class CoreCompatChangeRuleTest {
+
+    @Rule
+    public TestRule compatChangeRule = new CoreCompatChangeRule();
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID})
+    public void testDummyGatingPositive() {
+        assertThat(DummyApi.dummyFunc()).isEqualTo("A");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID})
+    public void testDummyGatingNegative() {
+        assertThat(DummyApi.dummyFunc()).isEqualTo("B");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined0() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("0");
+    }
+
+    @Test
+    @DisableCompatChanges({DummyApi.CHANGE_ID_1})
+    @EnableCompatChanges({DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined1() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("1");
+    }
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID_1})
+    @DisableCompatChanges({DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined2() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("2");
+    }
+
+    @Test
+    @EnableCompatChanges({DummyApi.CHANGE_ID_1, DummyApi.CHANGE_ID_2})
+    public void testDummyGatingCombined3() {
+        assertThat(DummyApi.dummyCombinedFunc()).isEqualTo("3");
+    }
+}
\ No newline at end of file
diff --git a/tools/upstream/src/main/java/libcore/CompareUpstreams.java b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
index ca17f67..d9588a7 100644
--- a/tools/upstream/src/main/java/libcore/CompareUpstreams.java
+++ b/tools/upstream/src/main/java/libcore/CompareUpstreams.java
@@ -47,7 +47,7 @@
  * - The ANDROID_BUILD_TOP environment variable must be set to point to the
  * AOSP root directory (parent of libcore).
  *
- * To check out upstreams OpenJDK 7u40, 8u60, 8u121-b13, and 9+181, run:
+ * To check out upstreams OpenJDK 7u40, 8u60, 8u121-b13, 8u222-b01 and 9+181, run:
  *
  *  mkdir ~/openjdk
  *  cd ~/openjdk
@@ -58,6 +58,8 @@
  *  (cd !$ ; hg update -r jdk8u121-b13 && sh get_source.sh && sh common/bin/hgforest.sh update -r jdk8u121-b13)
  *  hg clone http://hg.openjdk.java.net/jdk8u/jdk8u60/ 8u60
  *  (cd !$ ; sh get_source.sh)
+ *  hg clone http://hg.openjdk.java.net/jdk8u/jdk8u 8u222-b01
+ *  (cd !$ ; hg update -r jdk8u222-b01 && sh get_source.sh && sh common/bin/hgforest.sh update -r jdk8u222-b01)
  *  hg clone http://hg.openjdk.java.net/jdk9/jdk9/ 9+181
  *  (cd !$ ; hg update -r jdk-9+181 && sh get_source.sh && sh common/bin/hgforest.sh update -r jdk-9+181)
  *
@@ -69,6 +71,17 @@
  */
 public class CompareUpstreams {
 
+    /**
+     * Whether to compare against snapshots based on (a) the output of {@link CopyUpstreamFiles},
+     * as opposed to (b) directly against checked-out upstream source {@link Repository}s.
+     *
+     * Because the snapshots are currently kept on x20 which is slow to access, (b) run much
+     * faster (a few seconds vs. 30 minutes), but it requires the checked-out and compiled
+     * upstream repositories to exist which is not the case for everyone / not easily achievable
+     * (OpenJDK 8 requires an old C++ compiler to build).
+     */
+    public static final boolean COMPARE_AGAINST_UPSTREAM_SNAPSHOT = true;
+
     private final StandardRepositories standardRepositories;
 
     public CompareUpstreams(StandardRepositories standardRepositories) {
@@ -153,9 +166,13 @@
         }
         headers.add("diff");
         printTsv(out, headers);
+
+        Path snapshotRoot = COMPARE_AGAINST_UPSTREAM_SNAPSHOT
+                ? Util.pathFromEnvOrThrow("OJLUNI_UPSTREAMS")
+                : 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);
@@ -167,7 +184,15 @@
             List<String> comparisons = new ArrayList<>(upstreams.size());
             for (Repository upstream : upstreams) {
                 final String comparison;
-                Path upstreamFile = upstream.absolutePath(relPath);
+                final Path upstreamFile;
+                if (COMPARE_AGAINST_UPSTREAM_SNAPSHOT) {
+                    Path maybePath = snapshotRoot
+                            .resolve(upstream.name())
+                            .resolve(relPath);
+                    upstreamFile = maybePath.toFile().exists() ? maybePath : null;
+                } else {
+                    upstreamFile = upstream.absolutePath(relPath);
+                }
                 if (upstreamFile == null) {
                     comparison = "missing";
                 } else {
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/Repository.java b/tools/upstream/src/main/java/libcore/Repository.java
index 89f64f0..4c7bbd7 100644
--- a/tools/upstream/src/main/java/libcore/Repository.java
+++ b/tools/upstream/src/main/java/libcore/Repository.java
@@ -27,6 +27,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -232,18 +234,19 @@
          */
         public List<Path> loadRelPathsFromBlueprint() throws IOException {
             List<Path> result = new ArrayList<>();
-            result.addAll(loadRelPathsFromBlueprint(
+            result.addAll(loadOrderedRelPathsSetFromBlueprint(
                 "openjdk_java_files.bp", "\"ojluni/src/main/java/(.+\\.java)\""));
-            result.addAll(loadRelPathsFromBlueprint(
+            result.addAll(loadOrderedRelPathsSetFromBlueprint(
                 "ojluni/src/main/native/Android.bp", "\\s+\"(.+\\.(?:c|cpp))\","));
             return result;
         }
 
-        private List<Path> loadRelPathsFromBlueprint(
+        private Set<Path> loadOrderedRelPathsSetFromBlueprint(
             String blueprintPathString, String patternString) throws IOException {
             Path blueprintPath = rootPath.resolve(blueprintPathString);
             Pattern pattern = Pattern.compile(patternString);
-            List<Path> result = new ArrayList<>();
+            // Use TreeSet to sort and de-duplicate the result.
+            Set<Path> result = new TreeSet<>();
             for (String line : Util.readLines(blueprintPath)) {
                 Matcher matcher = pattern.matcher(line);
                 while (matcher.find()) {
@@ -251,7 +254,6 @@
                     result.add(relPath);
                 }
             }
-            Collections.sort(result);
             return result;
         }
 
diff --git a/tools/upstream/src/main/java/libcore/StandardRepositories.java b/tools/upstream/src/main/java/libcore/StandardRepositories.java
index 3bdbebf..7047c60 100644
--- a/tools/upstream/src/main/java/libcore/StandardRepositories.java
+++ b/tools/upstream/src/main/java/libcore/StandardRepositories.java
@@ -35,8 +35,10 @@
     private final List<Repository> allUpstreams;
     // upstreams older than what is currently the default
     private final List<Repository> historicUpstreams;
+    private final Repository openJdk8u222;
     private final Repository openJdk8u121;
     private final Repository openJdk9b113;
+    private final Repository openJdk9p181;
     private final Repository openJdk7u40;
     private final OjluniRepository ojluni;
 
@@ -46,6 +48,8 @@
         allUpstreams.add(openJdk9(upstreamRoot, "9+181"));
         this.openJdk9b113 = addAndReturn(allUpstreams, openJdk9(upstreamRoot, "9b113+"));
         this.openJdk8u121 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "8u121-b13"));
+        this.openJdk8u222 = addAndReturn(allUpstreams, openJdkLegacy(upstreamRoot, "8u222-b01"));
+        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));
@@ -76,19 +80,11 @@
     }
 
     public static StandardRepositories fromEnv() {
-        Path androidBuildTop = Paths.get(getEnvOrThrow("ANDROID_BUILD_TOP"));
-        Path upstreamRoot = Paths.get(getEnvOrThrow("OPENJDK_HOME"));
+        Path androidBuildTop = Util.pathFromEnvOrThrow("ANDROID_BUILD_TOP");
+        Path upstreamRoot = Util.pathFromEnvOrThrow("OPENJDK_HOME");
         return new StandardRepositories(androidBuildTop, upstreamRoot);
     }
 
-    private static String getEnvOrThrow(String name) {
-        String result = System.getenv(name);
-        if (result == null) {
-            throw new IllegalStateException("Environment variable undefined: " + name);
-        }
-        return result;
-    }
-
     private static final Set<String> juFilesFromJsr166 = Collections.unmodifiableSet(
             new HashSet<>(Arrays.asList(
                     "AbstractQueue",
@@ -117,9 +113,41 @@
         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"
+                    )));
+
+    private static final Set<String> REL_PATHS_AT_OPENJDK8_222 = Collections.unmodifiableSet(
+            new HashSet<>(Arrays.asList(
+                    "java/time/chrono/JapaneseEra.java",
+                    "java/util/JapaneseImperialCalendar.java",
+                    "sun/util/calendar/Era.java",
+                    // Tests:
+                    "java/time/tck/java/time/chrono/TCKJapaneseChronology.java",
+                    "java/time/tck/java/time/chrono/TCKJapaneseEra.java",
+                    "java/time/test/java/time/chrono/TestJapaneseChronology.java",
+                    "java/time/test/java/time/chrono/TestUmmAlQuraChronology.java",
+                    "java/time/test/java/time/format/TestNonIsoFormatter.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 (REL_PATHS_AT_OPENJDK8_222.contains(relPath.toString())) {
+            return openJdk8u222;
+        } else if (isJsr166) {
             return openJdk9b113;
         } else if (relPath.startsWith("java/sql/") || relPath.startsWith("javax/sql/")) {
             return openJdk7u40;
diff --git a/tools/upstream/src/main/java/libcore/Util.java b/tools/upstream/src/main/java/libcore/Util.java
index c50e990..0f69c5f 100644
--- a/tools/upstream/src/main/java/libcore/Util.java
+++ b/tools/upstream/src/main/java/libcore/Util.java
@@ -26,6 +26,7 @@
 import java.io.Reader;
 import java.io.Writer;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -36,6 +37,23 @@
     private Util() {
     }
 
+    public static Path pathFromEnvOrThrow(String name) {
+        String envValue = getEnvOrThrow(name);
+        Path result = Paths.get(envValue);
+        if (!result.toFile().exists()) {
+            throw new IllegalArgumentException("Path not found: " + result);
+        }
+        return result;
+    }
+
+    private static String getEnvOrThrow(String name) {
+        String result = System.getenv(name);
+        if (result == null) {
+            throw new IllegalStateException("Environment variable undefined: " + name);
+        }
+        return result;
+    }
+
     public static Lines readLines(Reader reader) throws IOException {
         List<String> result = new ArrayList<>();
         BufferedReader br = (reader instanceof BufferedReader)
diff --git a/xml/src/main/java/com/android/org/kxml2/io/TEST_MAPPING b/xml/src/main/java/com/android/org/kxml2/io/TEST_MAPPING
new file mode 100644
index 0000000..d8c9759
--- /dev/null
+++ b/xml/src/main/java/com/android/org/kxml2/io/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.xml"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/xml/src/main/java/org/xmlpull/v1/TEST_MAPPING b/xml/src/main/java/org/xmlpull/v1/TEST_MAPPING
new file mode 100644
index 0000000..d8c9759
--- /dev/null
+++ b/xml/src/main/java/org/xmlpull/v1/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLibcoreTestCases",
+      "options": [
+        {
+          "include-filter": "libcore.xml"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java b/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java
index bb3d130..b3cb855 100644
--- a/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java
+++ b/xml/src/main/java/org/xmlpull/v1/XmlPullParser.java
@@ -661,7 +661,7 @@
     int getLineNumber();
 
     /**
-     * Returns the current column number, starting from 0.
+     * Returns the current column number, starting from 1.
      * When the parser does not know the current column number
      * or can not determine it,  -1 is returned (e.g. for WBXML).
      *