Merge "Revert "libcore: Remove native calls in FileDescriptor <clinit>"" into rvc-dev am: c5bf4e3807 am: 67266859ad am: 8c34163cfa

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

Change-Id: Iec4c0b87f295e8c1979e449d55d530d5e1d4a57e
diff --git a/JavaLibrary.bp b/JavaLibrary.bp
index adb5b0f..0d98122 100644
--- a/JavaLibrary.bp
+++ b/JavaLibrary.bp
@@ -109,46 +109,6 @@
     ],
 }
 
-// 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.
-//
-// Deprecated: Will be replaced by core-current-stubs-source.
-filegroup {
-    name: "core_public_api_files",
-    visibility: [
-        "//frameworks/base",
-    ],
-    srcs: [
-        ":android_icu4j_public_api_files",
-    ],
-}
-
-// Contains the stubs source for the part of the Android SDK public API which
-// is provided by the core libraries.
-//
-// Currently is only a placeholder that creates an empty srcjar due to issues
-// caused by http://b/142113901.
-//
-// TODO(http://b/142113521) - Add stubs source for the core library modules.
-genrule {
-    name: "core-current-stubs-source",
-    visibility: [
-        "//frameworks/base",
-    ],
-    tools: [
-        "merge_zips",
-    ],
-    srcs: [
-        ":art-module-public-api-stubs-source",
-        ":conscrypt-module-public-api-stubs-source",
-    ],
-    out: ["core-current-stubs-source.srcjar"],
-    cmd: "$(location merge_zips) $(out)" +
-        " $(location :art-module-public-api-stubs-source)" +
-        " $(location :conscrypt-module-public-api-stubs-source)",
-}
-
 // 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
@@ -223,7 +183,10 @@
 
     installable: false,
 
-    plugins: ["compat-changeid-annotation-processor"],
+    plugins: [
+        "compat-changeid-annotation-processor",
+        "unsupportedappusage-annotation-processor",
+    ],
 }
 
 platform_compat_config {
@@ -379,6 +342,7 @@
     sdk_version: "none",
     system_modules: "core-all-system-modules",
     patch_module: "java.base",
+    plugins: ["unsupportedappusage-annotation-processor"],
 }
 
 //
@@ -456,6 +420,7 @@
     srcs: [
         ":openjdk_lambda_stub_files",
     ],
+    include_srcs: true,
 }
 
 // Creates a jar that exists to satisfy javac when compiling source code that
@@ -486,6 +451,7 @@
     visibility: [
         "//art/build/sdk",
         "//external/conscrypt",
+        "//external/conscrypt/apex/tests",
         "//frameworks/base/location/tests/locationtests",
         "//frameworks/base/core/tests/coretests",
         "//frameworks/base/wifi/tests",
@@ -602,8 +568,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: [
@@ -635,6 +605,7 @@
         "core-test-rules",
         "core-tests-support",
         "junit-params",
+        "libcore-crypto-tests",
         "mockftpserver",
         "mockito-target",
         "mockwebserver",
@@ -655,6 +626,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",
@@ -834,9 +839,13 @@
 
 // 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.
+// 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",
@@ -938,11 +947,12 @@
     },
 }
 
-// Used when compiling higher-level code against core.current.stubs.
-java_system_modules {
-    name: "core-current-stubs-system-modules",
-    visibility: ["//visibility:public"],
-    libs: [
+// 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.
@@ -953,6 +963,24 @@
         // 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
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index 4a9e8631..ee20d80 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -128,15 +128,20 @@
                 : 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() {
+    @libcore.api.CorePlatformApi
+    public void reportClassLoaderChain() {
+        if (reporter == null) {
+            return;
+        }
+
         String[] classPathAndClassLoaderContexts = computeClassLoaderContextsNative();
         if (classPathAndClassLoaderContexts.length == 0) {
             return;
@@ -367,7 +372,7 @@
         /**
          * 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 } 
+         * {@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]"}.
          *
diff --git a/dalvik/src/main/java/dalvik/system/CloseGuard.java b/dalvik/src/main/java/dalvik/system/CloseGuard.java
index 4607f2d..99ddf3e 100644
--- a/dalvik/src/main/java/dalvik/system/CloseGuard.java
+++ b/dalvik/src/main/java/dalvik/system/CloseGuard.java
@@ -134,6 +134,9 @@
      */
     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.
@@ -224,6 +227,21 @@
     @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;
         }
     }
 
@@ -275,19 +299,18 @@
     @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/ZygoteHooks.java b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
index 0339b4d..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();
     }
 
     /**
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/virtualdeviceknownfailures.txt b/expectations/virtualdeviceknownfailures.txt
index c1fa62a..b689133 100644
--- a/expectations/virtualdeviceknownfailures.txt
+++ b/expectations/virtualdeviceknownfailures.txt
@@ -24,15 +24,7 @@
 },
 {
   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_InetAddress_IPv6",
-          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4_nullInterface",
-          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6_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_sendLjava_net_DatagramPacketB_IPv6",
-          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv4",
-          "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv6",
+  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"
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/java/util/TimeZoneTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TimeZoneTest.java
index 0d16786..b98f230 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TimeZoneTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/TimeZoneTest.java
@@ -232,11 +232,10 @@
 
         // Any one of these might legitimately change its raw offset, though that's
         // fairly unlikely, and the chances of more than one changing are very slim.
-        assertTrue(ids.toString(), ids.contains("America/Dawson"));
         assertTrue(ids.toString(), ids.contains("America/Tijuana"));
+        assertTrue(ids.toString(), ids.contains("America/Ensenada")); // Alias for America/Tijuana
         assertTrue(ids.toString(), ids.contains("America/Vancouver"));
-        assertTrue(ids.toString(), ids.contains("Canada/Pacific"));
-        assertTrue(ids.toString(), ids.contains("Canada/Yukon"));
+        assertTrue(ids.toString(), ids.contains("Canada/Pacific")); // Alias for America/Vancouver
         assertTrue(ids.toString(), ids.contains("Pacific/Pitcairn"));
     }
 
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/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 970dcc2..321f4e3 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -28,6 +28,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 
+import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
 /**
@@ -673,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.
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index 568614f..6e05cea 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -310,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");
@@ -370,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) {
@@ -403,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;
             }
@@ -431,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 f9e3ea3..e35a69d 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -39,6 +39,9 @@
  * 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/luni/src/main/java/android/compat/Compatibility.java b/luni/src/main/java/android/compat/Compatibility.java
index e5d7cbb..9b4b1af 100644
--- a/luni/src/main/java/android/compat/Compatibility.java
+++ b/luni/src/main/java/android/compat/Compatibility.java
@@ -121,13 +121,13 @@
         }
         @CorePlatformApi
         protected void reportChange(long changeId) {
-            System.logW(String.format(
-                    "No Compatibility callbacks set! Reporting change %d", changeId));
+            // Do not use String.format here (b/160912695)
+            System.logW("No Compatibility callbacks set! Reporting change " + changeId);
         }
         @CorePlatformApi
         protected boolean isChangeEnabled(long changeId) {
-            System.logW(String.format(
-                    "No Compatibility callbacks set! Querying change %d", changeId));
+            // Do not use String.format here (b/160912695)
+            System.logW("No Compatibility callbacks set! Querying change " + changeId);
             return true;
         }
     }
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index ea6fe6f..12b978de 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -16,12 +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.system.VMRuntime;
+
 import java.text.DateFormat;
 import java.util.HashMap;
 import java.util.Locale;
@@ -38,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 {
@@ -171,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
@@ -180,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/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/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/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/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/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/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/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/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index 74d536f..15a0a48 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -531,6 +531,7 @@
     method public void addDexPath(String);
     method public void addNativePath(java.util.Collection<java.lang.String>);
     method public String getLdLibraryPath();
+    method public void reportClassLoaderChain();
     method public static void setReporter(dalvik.system.BaseDexClassLoader.Reporter);
   }
 
@@ -563,6 +564,7 @@
     method public static dalvik.system.CloseGuard get();
     method public static dalvik.system.CloseGuard.Reporter getReporter();
     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();
@@ -570,6 +572,7 @@
 
   public static interface CloseGuard.Reporter {
     method public void report(String, Throwable);
+    method public default void report(String);
   }
 
   public interface DalvikLogHandler {
diff --git a/ojluni/src/main/java/java/io/FileDescriptor.java b/ojluni/src/main/java/java/io/FileDescriptor.java
index ed3ebfe..98db443 100644
--- a/ojluni/src/main/java/java/io/FileDescriptor.java
+++ b/ojluni/src/main/java/java/io/FileDescriptor.java
@@ -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.
@@ -214,15 +231,6 @@
         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/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index 63651a0..352d9ec 100644
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -26,6 +26,7 @@
 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;
@@ -294,6 +295,7 @@
      *          the current time and midnight, January 1, 1970 UTC.
      * @see     java.util.Date
      */
+    @CriticalNative
     public static native long currentTimeMillis();
 
     /**
@@ -340,6 +342,7 @@
      *         high-resolution time source, in nanoseconds
      * @since 1.5
      */
+    @CriticalNative
     public static native long nanoTime();
 
     /**
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/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/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/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/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/native/Android.bp b/ojluni/src/main/native/Android.bp
index 7aa8dda..45a5c98 100644
--- a/ojluni/src/main/native/Android.bp
+++ b/ojluni/src/main/native/Android.bp
@@ -37,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/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/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();
     }
 
     /*